From 5bc35d781db4a3125f4f009b5abf5b28fe30707a Mon Sep 17 00:00:00 2001
From: BatLeDev
Date: Thu, 5 Feb 2026 17:49:06 +0100
Subject: [PATCH 1/9] refactor: organize api in folders
---
api/config/development.mjs | 2 +-
api/config/test.mjs | 2 +-
api/src/{admin.ts => admin/router.ts} | 8 ++-
api/src/admin/status.ts | 55 +++++++++++++++++++
api/src/app.ts | 14 ++---
.../{routers/limits.ts => limits/router.ts} | 0
api/src/{ => misc}/routers/identities.ts | 0
api/src/{ => misc}/utils/api-docs.ts | 2 +-
api/src/{ => misc}/utils/find.ts | 0
api/src/{ => misc}/utils/permissions.ts | 0
.../router.ts} | 0
.../{routers/plugins.ts => plugins/router.ts} | 2 +-
.../processings.ts => processings/router.ts} | 8 +--
api/src/{routers/runs.ts => runs/router.ts} | 4 +-
api/src/{utils/runs.ts => runs/service.ts} | 0
api/src/server.ts | 2 +-
dev/resources/nginx.conf | 4 +-
docker-compose.yml | 5 +-
scripts/re-schedule-all.ts | 2 +-
ui/.gitignore | 1 +
ui/dts/auto-imports.d.ts | 1 -
ui/dts/typed-router.d.ts | 1 +
ui/src/components/private-access.vue | 3 -
.../processing/processing-actions.vue | 3 -
.../components/processing/processing-card.vue | 4 +-
.../components/processing/processing-runs.vue | 3 -
ui/src/pages/dev.vue | 3 -
worker/config/development.mjs | 2 +-
28 files changed, 89 insertions(+), 42 deletions(-)
rename api/src/{admin.ts => admin/router.ts} (79%)
create mode 100644 api/src/admin/status.ts
rename api/src/{routers/limits.ts => limits/router.ts} (100%)
rename api/src/{ => misc}/routers/identities.ts (100%)
rename api/src/{ => misc}/utils/api-docs.ts (99%)
rename api/src/{ => misc}/utils/find.ts (100%)
rename api/src/{ => misc}/utils/permissions.ts (100%)
rename api/src/{routers/plugins-registry.ts => plugins-registry/router.ts} (100%)
rename api/src/{routers/plugins.ts => plugins/router.ts} (99%)
rename api/src/{routers/processings.ts => processings/router.ts} (98%)
rename api/src/{routers/runs.ts => runs/router.ts} (96%)
rename api/src/{utils/runs.ts => runs/service.ts} (100%)
diff --git a/api/config/development.mjs b/api/config/development.mjs
index 9e37ef41..ee27bada 100644
--- a/api/config/development.mjs
+++ b/api/config/development.mjs
@@ -7,7 +7,7 @@ export default {
},
port: 8082,
privateDirectoryUrl: 'http://localhost:8080',
- privateEventsUrl: 'http://localhost:8084',
+ privateEventsUrl: 'http://localhost:8083',
secretKeys: {
identities: 'secret-identities',
events: 'secret-events'
diff --git a/api/config/test.mjs b/api/config/test.mjs
index aafec418..0c4481ef 100644
--- a/api/config/test.mjs
+++ b/api/config/test.mjs
@@ -7,7 +7,7 @@ export default {
},
port: 8082,
privateDirectoryUrl: 'http://localhost:8080',
- privateEventsUrl: 'http://localhost:8084',
+ privateEventsUrl: 'http://localhost:8083',
secretKeys: {
identities: 'secret-identities',
events: 'secret-events'
diff --git a/api/src/admin.ts b/api/src/admin/router.ts
similarity index 79%
rename from api/src/admin.ts
rename to api/src/admin/router.ts
index bc6ed9b6..a0e7bd80 100644
--- a/api/src/admin.ts
+++ b/api/src/admin/router.ts
@@ -2,7 +2,8 @@ import { resolve } from 'node:path'
import { readFile } from 'node:fs/promises'
import { Router } from 'express'
import { reqOrigin, session } from '@data-fair/lib-express'
-import getApiDoc from './utils/api-docs.ts'
+import { getStatus } from './status.ts'
+import getApiDoc from '../misc/utils/api-docs.ts'
const router = Router()
export default router
@@ -21,6 +22,11 @@ router.get('/info', (req, res) => {
res.send(info)
})
+router.get('/status', async (req, res) => {
+ const status = await getStatus(req)
+ res.send(status)
+})
+
// Get the full API documentation of the service
router.get('/api-docs.json', async (req, res) => {
res.json(getApiDoc(reqOrigin(req)))
diff --git a/api/src/admin/status.ts b/api/src/admin/status.ts
new file mode 100644
index 00000000..2e03ddb1
--- /dev/null
+++ b/api/src/admin/status.ts
@@ -0,0 +1,55 @@
+import type { Request } from 'express'
+import mongo from '#mongo'
+import config from '#config'
+import fs from 'node:fs/promises'
+
+const mongoStatus = async () => { await mongo.db.command({ ping: 1 }) }
+const volumeStatus = async () => {
+ await fs.writeFile(`${config.dataDir}/check-access.txt`, 'ok')
+}
+
+export const getStatus = async (req: Request) =>
+ runHealthChecks(req, [
+ { fn: mongoStatus, name: 'mongodb' },
+ { fn: volumeStatus, name: 'data volume' }
+ ])
+
+// Helper functions
+const getSingleStatus = async (req: Request, fn: (req: Request) => Promise, name: string) => {
+ const start = performance.now()
+ try {
+ await fn(req)
+ return {
+ status: 'ok',
+ name,
+ timeInMs: Math.round(performance.now() - start)
+ }
+ } catch (err) {
+ return {
+ status: 'error',
+ message: err instanceof Error ? err.message : String(err),
+ name,
+ timeInMs: Math.round(performance.now() - start)
+ }
+ }
+}
+const runHealthChecks = async (
+ req: Request,
+ checks: Array<{ fn: (req: Request) => Promise; name: string }>
+) => {
+ let results
+ try {
+ results = await Promise.all(checks.map(({ fn, name }) => getSingleStatus(req, fn, name)))
+ } catch (err: any) {
+ return {
+ status: 'error',
+ details: err.toString()
+ }
+ }
+ const errors = results.filter(r => r.status === 'error')
+ return {
+ status: errors.length ? 'error' : 'ok',
+ message: errors.length ? ('Problem with : ' + errors.map(s => s.name).join(', ')) : 'Service is ok',
+ details: results
+ }
+}
diff --git a/api/src/app.ts b/api/src/app.ts
index 44241549..c5846148 100644
--- a/api/src/app.ts
+++ b/api/src/app.ts
@@ -1,13 +1,13 @@
import { resolve } from 'node:path'
import express from 'express'
import { session, errorHandler, createSiteMiddleware, createSpaMiddleware, defaultNonceCSPDirectives } from '@data-fair/lib-express/index.js'
-import identitiesRouter from './routers/identities.ts'
-import limitsRouter from './routers/limits.ts'
-import pluginsRegistryRouter from './routers/plugins-registry.ts'
-import pluginsRouter from './routers/plugins.ts'
-import processingsRouter from './routers/processings.ts'
-import runsRouter from './routers/runs.ts'
-import adminRouter from './admin.ts'
+import identitiesRouter from './misc/routers/identities.ts'
+import limitsRouter from './limits/router.ts'
+import pluginsRegistryRouter from './plugins-registry/router.ts'
+import pluginsRouter from './plugins/router.ts'
+import processingsRouter from './processings/router.ts'
+import runsRouter from './runs/router.ts'
+import adminRouter from './admin/router.ts'
import config, { uiConfig } from '#config'
export const app = express()
diff --git a/api/src/routers/limits.ts b/api/src/limits/router.ts
similarity index 100%
rename from api/src/routers/limits.ts
rename to api/src/limits/router.ts
diff --git a/api/src/routers/identities.ts b/api/src/misc/routers/identities.ts
similarity index 100%
rename from api/src/routers/identities.ts
rename to api/src/misc/routers/identities.ts
diff --git a/api/src/utils/api-docs.ts b/api/src/misc/utils/api-docs.ts
similarity index 99%
rename from api/src/utils/api-docs.ts
rename to api/src/misc/utils/api-docs.ts
index 932f0670..612a1af9 100644
--- a/api/src/utils/api-docs.ts
+++ b/api/src/misc/utils/api-docs.ts
@@ -4,7 +4,7 @@ import { type Plugin, resolvedSchema as PluginSchema } from '#types/plugin/index
import { readFileSync } from 'node:fs'
import path from 'path'
-const packageJson = JSON.parse(readFileSync(path.resolve(import.meta.dirname, '../../package.json'), 'utf-8'))
+const packageJson = JSON.parse(readFileSync(path.resolve(import.meta.dirname, '../../../package.json'), 'utf-8'))
// CTRL + K CTRL + 4 to fold operations levels
diff --git a/api/src/utils/find.ts b/api/src/misc/utils/find.ts
similarity index 100%
rename from api/src/utils/find.ts
rename to api/src/misc/utils/find.ts
diff --git a/api/src/utils/permissions.ts b/api/src/misc/utils/permissions.ts
similarity index 100%
rename from api/src/utils/permissions.ts
rename to api/src/misc/utils/permissions.ts
diff --git a/api/src/routers/plugins-registry.ts b/api/src/plugins-registry/router.ts
similarity index 100%
rename from api/src/routers/plugins-registry.ts
rename to api/src/plugins-registry/router.ts
diff --git a/api/src/routers/plugins.ts b/api/src/plugins/router.ts
similarity index 99%
rename from api/src/routers/plugins.ts
rename to api/src/plugins/router.ts
index ec976f54..6750e06f 100644
--- a/api/src/routers/plugins.ts
+++ b/api/src/plugins/router.ts
@@ -15,7 +15,7 @@ import multer from 'multer'
import { session, httpError } from '@data-fair/lib-express'
import mongo from '#mongo'
import config from '#config'
-import permissions from '../utils/permissions.ts'
+import permissions from '../misc/utils/permissions.ts'
// @ts-ignore
const ajv = ajvFormats(new Ajv({ strict: false }))
diff --git a/api/src/routers/processings.ts b/api/src/processings/router.ts
similarity index 98%
rename from api/src/routers/processings.ts
rename to api/src/processings/router.ts
index a504e58f..1a4daf6a 100644
--- a/api/src/routers/processings.ts
+++ b/api/src/processings/router.ts
@@ -15,15 +15,15 @@ import eventsQueue from '@data-fair/lib-node/events-queue.js'
import { reqOrigin, session } from '@data-fair/lib-express/index.js'
import { httpError } from '@data-fair/lib-utils/http-errors.js'
import { createNext } from '@data-fair/processings-shared/runs.ts'
-import { applyProcessing, deleteProcessing } from '../utils/runs.ts'
+import { applyProcessing, deleteProcessing } from '../runs/service.ts'
import { cipher, decipher } from '@data-fair/processings-shared/cipher.ts'
import mongo from '#mongo'
import config from '#config'
import locks from '#locks'
import { resolvedSchema as processingSchema } from '#types/processing/index.ts'
-import getApiDoc from '../utils/api-docs.ts'
-import findUtils from '../utils/find.ts'
-import permissions from '../utils/permissions.ts'
+import getApiDoc from '../misc/utils/api-docs.ts'
+import findUtils from '../misc/utils/find.ts'
+import permissions from '../misc/utils/permissions.ts'
const router = Router()
export default router
diff --git a/api/src/routers/runs.ts b/api/src/runs/router.ts
similarity index 96%
rename from api/src/routers/runs.ts
rename to api/src/runs/router.ts
index 4dcbbb4f..3120e38b 100644
--- a/api/src/routers/runs.ts
+++ b/api/src/runs/router.ts
@@ -5,8 +5,8 @@ import * as wsEmitter from '@data-fair/lib-node/ws-emitter.js'
import { session } from '@data-fair/lib-express/index.js'
import { Router } from 'express'
import mongo from '#mongo'
-import findUtils from '../utils/find.ts'
-import permissions from '../utils/permissions.ts'
+import findUtils from '../misc/utils/find.ts'
+import permissions from '../misc/utils/permissions.ts'
const router = Router()
export default router
diff --git a/api/src/utils/runs.ts b/api/src/runs/service.ts
similarity index 100%
rename from api/src/utils/runs.ts
rename to api/src/runs/service.ts
diff --git a/api/src/server.ts b/api/src/server.ts
index 9726d97f..f2ab198f 100644
--- a/api/src/server.ts
+++ b/api/src/server.ts
@@ -13,7 +13,7 @@ import config from '#config'
import mongo from '#mongo'
import locks from '#locks'
import http from 'http'
-import permissions from './utils/permissions.ts'
+import permissions from './misc/utils/permissions.ts'
const exec = promisify(execCallback)
const server = http.createServer(app)
diff --git a/dev/resources/nginx.conf b/dev/resources/nginx.conf
index 47881c69..e53f3211 100644
--- a/dev/resources/nginx.conf
+++ b/dev/resources/nginx.conf
@@ -98,11 +98,11 @@ http {
}
location /openapi-viewer {
- proxy_pass http://localhost:8083;
+ proxy_pass http://localhost:8084;
}
location /events/ {
- proxy_pass http://localhost:8084;
+ proxy_pass http://localhost:8083;
}
}
}
diff --git a/docker-compose.yml b/docker-compose.yml
index f0a26534..318d22f6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -68,9 +68,8 @@ services:
profiles:
- dev
image: ghcr.io/data-fair/openapi-viewer:master
- ports:
- - 8083:8080
environment:
+ - PORT=8084
- USE_SIMPLE_DIRECTORY=true
- ALLOWED_URLS={"processings":"http://localhost:5600/processings/api/v1/api-docs.json","processingsId":"http://localhost:5600/processings/api/v1/processings/{id}/api-docs.json","processingsAdmin":"http://localhost:5600/processings/api/v1/admin/api-docs.json"}
@@ -80,7 +79,7 @@ services:
image: ghcr.io/data-fair/events:main
network_mode: host
environment:
- - PORT=8084
+ - PORT=8083
- PRIVATE_DIRECTORY_URL=http://localhost:5600/simple-directory
- SECRET_IDENTITIES=secret-identities
- SECRET_EVENTS=secret-events
diff --git a/scripts/re-schedule-all.ts b/scripts/re-schedule-all.ts
index e038eb02..a8c2af12 100644
--- a/scripts/re-schedule-all.ts
+++ b/scripts/re-schedule-all.ts
@@ -1,4 +1,4 @@
-import runs from '../api/src/utils/runs.ts'
+import runs from '../api/src/runs/service.ts'
async function main () {
const { db } = await require('../api/utils/db').connect()
diff --git a/ui/.gitignore b/ui/.gitignore
index b6cdf575..55e510f1 100644
--- a/ui/.gitignore
+++ b/ui/.gitignore
@@ -12,6 +12,7 @@ dist
dist-ssr
*.local
*.tsbuildinfo
+dts
# Editor directories and files
.vscode/*
diff --git a/ui/dts/auto-imports.d.ts b/ui/dts/auto-imports.d.ts
index fc4303ad..4035690e 100644
--- a/ui/dts/auto-imports.d.ts
+++ b/ui/dts/auto-imports.d.ts
@@ -60,7 +60,6 @@ declare global {
const mdiPencil: typeof import('@mdi/js')['mdiPencil']
const mdiPlay: typeof import('@mdi/js')['mdiPlay']
const mdiPlayCircle: typeof import('@mdi/js')['mdiPlayCircle']
- const mdiPlug: typeof import('@mdi/js')['mdiPlug']
const mdiPlusCircle: typeof import('@mdi/js')['mdiPlusCircle']
const mdiPlusCircleOutline: typeof import('@mdi/js')['mdiPlusCircleOutline']
const mdiPowerPlug: typeof import('@mdi/js')['mdiPowerPlug']
diff --git a/ui/dts/typed-router.d.ts b/ui/dts/typed-router.d.ts
index 0201f23b..e671f935 100644
--- a/ui/dts/typed-router.d.ts
+++ b/ui/dts/typed-router.d.ts
@@ -20,6 +20,7 @@ declare module 'vue-router/auto-routes' {
export interface RouteNamedMap {
'/admin/': RouteRecordInfo<'/admin/', '/admin', Record, Record>,
'/admin/plugins': RouteRecordInfo<'/admin/plugins', '/admin/plugins', Record, Record>,
+ '/dev': RouteRecordInfo<'/dev', '/dev', Record, Record>,
'/processings/': RouteRecordInfo<'/processings/', '/processings', Record, Record>,
'/processings/[id]/': RouteRecordInfo<'/processings/[id]/', '/processings/:id', { id: ParamValue }, { id: ParamValue }>,
'/processings/[id]/runs/[runId]': RouteRecordInfo<'/processings/[id]/runs/[runId]', '/processings/:id/runs/:runId', { id: ParamValue, runId: ParamValue }, { id: ParamValue, runId: ParamValue }>,
diff --git a/ui/src/components/private-access.vue b/ui/src/components/private-access.vue
index aaf18b9b..f737225a 100644
--- a/ui/src/components/private-access.vue
+++ b/ui/src/components/private-access.vue
@@ -103,6 +103,3 @@ function onChange () {
loading.value = false
}
-
-
diff --git a/ui/src/components/processing/processing-actions.vue b/ui/src/components/processing/processing-actions.vue
index 3ce6aead..42ae521a 100644
--- a/ui/src/components/processing/processing-actions.vue
+++ b/ui/src/components/processing/processing-actions.vue
@@ -454,6 +454,3 @@ watch(showTriggerMenu, async (newValue) => {
}
})
-
-
diff --git a/ui/src/components/processing/processing-card.vue b/ui/src/components/processing/processing-card.vue
index 900e722f..616d610b 100644
--- a/ui/src/components/processing/processing-card.vue
+++ b/ui/src/components/processing/processing-card.vue
@@ -56,9 +56,7 @@
-
- {{ pluginFetch.data.value?.metadata.name }}
-
+ {{ pluginFetch.data.value?.metadata.name }}
diff --git a/ui/src/components/processing/processing-runs.vue b/ui/src/components/processing/processing-runs.vue
index f0df5076..122f79f6 100644
--- a/ui/src/components/processing/processing-runs.vue
+++ b/ui/src/components/processing/processing-runs.vue
@@ -85,6 +85,3 @@ onUnmounted(() => {
defineExpose({ refresh: () => runs.refresh() })
-
-
diff --git a/ui/src/pages/dev.vue b/ui/src/pages/dev.vue
index 57e88f48..a35aa138 100644
--- a/ui/src/pages/dev.vue
+++ b/ui/src/pages/dev.vue
@@ -43,6 +43,3 @@
-
-
diff --git a/worker/config/development.mjs b/worker/config/development.mjs
index c6dbb051..edffb4e8 100644
--- a/worker/config/development.mjs
+++ b/worker/config/development.mjs
@@ -12,7 +12,7 @@ export default {
port: 9091
},
privateDataFairUrl: 'http://localhost:8081',
- privateEventsUrl: 'http://localhost:8084',
+ privateEventsUrl: 'http://localhost:8083',
runsRetention: 5,
upgradeRoot: '../'
}
From 56838a2c02af373f0708bfb08bf0dca7591fb7c1 Mon Sep 17 00:00:00 2001
From: BatLeDev
Date: Fri, 6 Feb 2026 10:24:17 +0100
Subject: [PATCH 2/9] chore: wip
---
package-lock.json | 16 +-
ui/package.json | 4 +
ui/src/pages/admin/plugins.vue | 334 ++++++++++++++++++++++-----------
3 files changed, 243 insertions(+), 111 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 4f5b45a2..a1d8efd5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2262,9 +2262,9 @@
"license": "MIT"
},
"node_modules/@types/semver": {
- "version": "7.7.0",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
- "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==",
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
"dev": true,
"license": "MIT"
},
@@ -9332,9 +9332,9 @@
"license": "MIT"
},
"node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -11296,6 +11296,7 @@
"iframe-resizer": "^4.4.5",
"reconnecting-websocket": "^4.4.0",
"sass-embedded": "^1.80.5",
+ "semver": "^7.7.4",
"timezones.json": "^1.7.1",
"unplugin-auto-import": "^0.18.3",
"unplugin-fonts": "^1.1.1",
@@ -11307,6 +11308,9 @@
"vue-i18n": "^11.1.2",
"vue-router": "^4.4.5",
"vue-tsc": "^2.1.10"
+ },
+ "devDependencies": {
+ "@types/semver": "^7.7.1"
}
},
"worker": {
diff --git a/ui/package.json b/ui/package.json
index 009729e9..55dc89b7 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -32,6 +32,7 @@
"iframe-resizer": "^4.4.5",
"reconnecting-websocket": "^4.4.0",
"sass-embedded": "^1.80.5",
+ "semver": "^7.7.4",
"timezones.json": "^1.7.1",
"unplugin-auto-import": "^0.18.3",
"unplugin-fonts": "^1.1.1",
@@ -43,5 +44,8 @@
"vue-i18n": "^11.1.2",
"vue-router": "^4.4.5",
"vue-tsc": "^2.1.10"
+ },
+ "devDependencies": {
+ "@types/semver": "^7.7.1"
}
}
diff --git a/ui/src/pages/admin/plugins.vue b/ui/src/pages/admin/plugins.vue
index c1577371..ef6bcbb7 100644
--- a/ui/src/pages/admin/plugins.vue
+++ b/ui/src/pages/admin/plugins.vue
@@ -9,7 +9,7 @@
density="compact"
hide-details
placeholder="rechercher"
- style="max-width:400px;"
+ max-width="400"
variant="outlined"
/>
@@ -41,78 +41,129 @@
-
-
- {{ result.distTag === 'latest' ? result.name : result.name + ' (' + result.distTag + ')' }}
-
-
- Utilisé {{ result.usages }} fois -
- {{ result.version }}
-
-
-
+
+ Utilisé {{ result.usages }} fois - {{ result.version }}
+
+
+
+
+
+
+
+ Mise à jour majeure
+
+
+
+ Mettre à jour vers une nouvelle version majeure risque d'entraîner une rupture de compatibilité. Vous pouvez choisir de confirmer la montée en version, ou préférer l'installation de la nouvelle version séparée.
+
+
+
+
+ Annuler
+
+
+ Mettre à jour
+
+
+ Installer séparément
+
+
+
+
-
-
- Désinstallation du plugin
-
-
-
- Voulez-vous vraiment désinstaller le plugin "{{ result.name }}" ?
-
-
-
-
- Non
-
+
+
- Oui
-
-
-
-
+ @click="showDeleteMenu = result.id"
+ />
+
+
+
+ Désinstallation du plugin
+
+
+
+ Voulez-vous vraiment désinstaller le plugin "{{ result.name }}" ?
+
+
+
+
+ Non
+
+
+ Oui
+
+
+
+
+
@@ -168,7 +219,7 @@
plugins disponibles
@@ -193,7 +244,7 @@
Installer depuis npm
Annuler
@@ -274,30 +325,25 @@
-
-
- {{ result.distTag === 'latest' ? result.name : result.name + ' (' + result.distTag + ')' }}
-
-
- {{ result.version }}
-
+
+ {{ result.version }}
+
+
setBreadcrumbs([{ text: 'Plugins' }]))
type AvailablePlugin = {
+ id?: string // Calculated from name version and distTag
name: string
- description: string
+ description?: string
distTag: string
version: string
}
@@ -356,6 +403,7 @@ const installedPluginsFetch = useFetch<{
count: number
}>(`${$apiPath}/plugins`)
+// Assign usage count to each installed plugin and make old config schema compatible with vjsf 3
const installedPlugins = computed(() => {
const results = installedPluginsFetch.data.value?.results || []
const usages = installedPluginsFetch.data.value?.facets.usages || {}
@@ -370,9 +418,11 @@ const availablePluginsFetch = useFetch<{
results: AvailablePlugin[],
count: number
}>(`${$apiPath}/plugins-registry`, { query: query.value })
+
const availablePlugins = computed(() => {
const results = availablePluginsFetch.data.value?.results || []
results.sort((a, b) => a.name.localeCompare(b.name) || a.version.localeCompare(b.version))
+ results.forEach(r => { r.id = generatePluginId(r.name, r.version, r.distTag) })
return results
})
@@ -384,7 +434,7 @@ const filteredInstalledPlugins = computed(() => {
const filteredAvailablePlugins = computed(() => {
const filteredPlugins = availablePlugins.value.filter(result =>
- !installedPlugins.value.find(r => r.name === result.name && r.distTag === result.distTag)
+ !installedPlugins.value.find(r => r.id === result.id)
)
if (!search.value) return filteredPlugins
@@ -394,18 +444,20 @@ const filteredAvailablePlugins = computed(() => {
)
})
-const deleteMenuShowed = ref(null) as Ref
+const showDeleteMenu = ref(null) as Ref
+const showMajorUpdateMenu = ref(null) as Ref
+const showManualInstallMenu = ref(false)
const pluginLocked = ref(null) as Ref
-const showForceInstall = ref(false)
-const forceInstallPlugin = ref({ name: '', version: '', distTag: 'latest', description: '' })
+const manualInstallPlugin = ref({ name: '', version: '', distTag: 'latest' })
const selectedFile = ref()
const hasNpmFields = computed(() =>
- !!(forceInstallPlugin.value.name?.trim() || forceInstallPlugin.value.version?.trim())
+ !!(manualInstallPlugin.value.name?.trim() || manualInstallPlugin.value.version?.trim())
)
+// Tue if form is valid
const canForceInstall = computed(() => {
- if (hasNpmFields.value) return forceInstallPlugin.value.name && forceInstallPlugin.value.version && forceInstallPlugin.value.distTag
+ if (hasNpmFields.value) return manualInstallPlugin.value.name && manualInstallPlugin.value.version && manualInstallPlugin.value.distTag
else if (selectedFile.value) return true
return false
})
@@ -416,16 +468,20 @@ const install = useAsyncAction(
let body: FormData | AvailablePlugin
- // Installation depuis un fichier
+ // From a file
if (selectedFile.value) {
body = new FormData()
body.append('file', selectedFile.value)
- // Installation depuis npm
+ // From npm registry
} else {
- const pluginPost = plugin || forceInstallPlugin.value
- pluginLocked.value = `${pluginPost.name}-${pluginPost.distTag}`
- body = pluginPost
+ const pluginPost = plugin || manualInstallPlugin.value
+ pluginLocked.value = `${pluginPost.id || generatePluginId(pluginPost.name, pluginPost.version, pluginPost.distTag)}`
+ body = {
+ name: pluginPost.name,
+ version: pluginPost.version,
+ distTag: pluginPost.distTag
+ }
}
await $fetch('/plugins', {
@@ -434,9 +490,9 @@ const install = useAsyncAction(
})
installedPluginsFetch.refresh()
pluginLocked.value = null
- showForceInstall.value = false
+ showManualInstallMenu.value = false
selectedFile.value = undefined
- forceInstallPlugin.value = { name: '', version: '', distTag: 'latest', description: '' }
+ manualInstallPlugin.value = { name: '', version: '', distTag: 'latest' }
},
{
error: 'Erreur lors de l\'installation du plugin',
@@ -452,7 +508,7 @@ const uninstall = useAsyncAction(
})
installedPluginsFetch.refresh()
pluginLocked.value = null
- deleteMenuShowed.value = null
+ showDeleteMenu.value = null
},
{
error: 'Erreur lors de la désinstallation du plugin',
@@ -461,16 +517,78 @@ const uninstall = useAsyncAction(
)
/**
- * Check if an update is available for a plugin (same distTag, same name, different version)
+ * Check if an update is available for a plugin (same distTag, same name, higher major version)
* @param plugin - The plugin to check
- * @returns - A tuple with a boolean indicating if an update is available and the new version
+ * @returns - A tuple with a boolean indicating if an update is available, the new version and a major-update flag
*/
-function updateAvailable (plugin: InstalledPlugin): [boolean, string] {
- if (availablePlugins.value.length === 0) return [false, '']
+function updateAvailable (plugin: InstalledPlugin): [boolean, string, boolean] {
+ if (availablePlugins.value.length === 0) return [false, '', false]
const availablePlugin = availablePlugins.value.find(r => (r.name === plugin.name && r.distTag === plugin.distTag))
- if (availablePlugin &&
- availablePlugin.version !== plugin.version) return [true, availablePlugin.version]
- return [false, '']
+ if (!availablePlugin) return [false, '', false]
+
+ const relatedInstalled = installedPlugins.value.filter(r => r.name === plugin.name && r.distTag === plugin.distTag)
+ if (relatedInstalled.length === 0) return [false, '', false]
+
+ let latestInstalled = relatedInstalled[0]
+ for (const candidate of relatedInstalled.slice(1)) {
+ const candidateParts = candidate.version.split('.')
+ const latestParts = latestInstalled.version.split('.')
+ let candidateIsNewer = false
+
+ for (let i = 0; i < 3; i += 1) {
+ const candidatePart = Number.parseInt(candidateParts[i] || '0', 10)
+ const latestPart = Number.parseInt(latestParts[i] || '0', 10)
+
+ if (candidatePart > latestPart) {
+ candidateIsNewer = true
+ break
+ }
+ if (candidatePart < latestPart) {
+ candidateIsNewer = false
+ break
+ }
+ }
+
+ if (candidateIsNewer) latestInstalled = candidate
+ }
+
+ if (latestInstalled.id !== plugin.id) return [false, '', false]
+
+ const availableParts = availablePlugin.version.split('.')
+ const installedParts = latestInstalled.version.split('.')
+ let availableIsNewer = false
+ let versionsEqual = true
+
+ for (let i = 0; i < 3; i += 1) {
+ const availablePart = Number.parseInt(availableParts[i] || '0', 10)
+ const installedPart = Number.parseInt(installedParts[i] || '0', 10)
+
+ if (availablePart > installedPart) {
+ availableIsNewer = true
+ versionsEqual = false
+ break
+ }
+ if (availablePart < installedPart) {
+ availableIsNewer = false
+ versionsEqual = false
+ break
+ }
+ }
+
+ if (versionsEqual) return [false, '', false]
+ if (availableIsNewer) {
+ const installedMajor = Number.parseInt(installedParts[0] || '0', 10)
+ const availableMajor = Number.parseInt(availableParts[0] || '0', 10)
+ const isMajorUpdate = availableMajor > installedMajor
+ return [true, availablePlugin.version, isMajorUpdate]
+ }
+ return [false, '', false]
+}
+
+async function installParallel (plugin: InstalledPlugin) {
+ const availablePlugin = availablePlugins.value.find(r => r.name === plugin.name && r.distTag === plugin.distTag)
+ if (!availablePlugin) return
+ await install.execute(availablePlugin)
}
async function update (plugin: InstalledPlugin) {
@@ -501,6 +619,12 @@ const vjsfOptions = computed(() => ({
xI18n: true
}))
+const generatePluginId = (name: string, version: string, distTag: string) => {
+ let id = name.replace('/', '-') + '-' + version.split('.')[0]
+ if (distTag && distTag !== 'latest') id += '-' + distTag
+ return id
+}
+
+
+fr:
+ adminRequired: Vous n'avez pas la permission d'accéder à cette page, il faut avoir activé le mode super-administration.
+ authRequired: Authentification nécessaire
+ availablePluginsLabel: plugins disponibles
+ cancel: Annuler
+ install: Installer
+ installError: Erreur lors de l'installation du plugin
+ installSeparately: Installer séparément
+ installSuccess: Plugin installé !
+ installedPluginsLabel: plugins installés
+ majorUpdateBody: Mettre à jour vers une nouvelle version majeure risque d'entraîner une rupture de compatibilité. Vous pouvez choisir de confirmer la montée en version, ou préférer l'installation de la nouvelle version séparée.
+ majorUpdateTitleWithVersions: "Mise à jour majeure - {from} vers {to}"
+ manualInstall: Installer manuellement
+ manualInstallDistTag: Tag de distribution
+ manualInstallFileLabel: Sélectionner un fichier .tgz
+ manualInstallFromFile: Installer depuis un fichier
+ manualInstallFromNpm: Installer depuis npm
+ manualInstallName: Nom du plugin
+ manualInstallTitle: Installation manuelle d'un plugin
+ manualInstallVersion: Version du plugin
+ no: Non
+ pluginsBreadcrumb: Plugins
+ searchPlaceholder: rechercher
+ showAllLabel: Afficher les versions de test des plugins
+ uninstall: Désinstaller
+ uninstallConfirm: Voulez-vous vraiment désinstaller le plugin "{name}" ?
+ uninstallError: Erreur lors de la désinstallation du plugin
+ uninstallSuccess: Plugin désinstallé !
+ uninstallTitle: Désinstallation du plugin
+ update: Mettre à jour
+ updateWithVersion: Mettre à jour ({version})
+ usageCount: Utilisé {count} fois
+ yes: Oui
+
From 3c6eb2f098a0f6e9a109428b4cd20f52ee68c2f9 Mon Sep 17 00:00:00 2001
From: BatLeDev
Date: Fri, 6 Feb 2026 12:25:15 +0100
Subject: [PATCH 4/9] refactor: copy catalogs template
---
docker-compose.yml | 33 +-
package-lock.json | 137 +---
package.json | 2 +-
ui/dts/auto-imports.d.ts | 271 --------
ui/dts/components.d.ts | 24 -
ui/dts/typed-router.d.ts | 29 -
ui/eslint.config.mjs | 16 +-
ui/package.json | 10 +-
.../layout/layout-actions-button.vue | 21 -
.../layout/layout-actions-right.vue | 13 -
ui/src/components/layout/layout-actions.vue | 8 -
.../processing/processing-actions.vue | 599 +++++++++---------
ui/src/components/processings-actions.vue | 253 ++++----
ui/src/pages/admin/plugins.vue | 2 +-
ui/src/pages/dev.vue | 6 +-
ui/src/pages/processings/[id]/index.vue | 5 +-
ui/src/pages/processings/index.vue | 79 ++-
ui/src/pages/processings/new.vue | 28 +-
18 files changed, 538 insertions(+), 998 deletions(-)
delete mode 100644 ui/dts/auto-imports.d.ts
delete mode 100644 ui/dts/components.d.ts
delete mode 100644 ui/dts/typed-router.d.ts
delete mode 100644 ui/src/components/layout/layout-actions-button.vue
delete mode 100644 ui/src/components/layout/layout-actions-right.vue
delete mode 100644 ui/src/components/layout/layout-actions.vue
diff --git a/docker-compose.yml b/docker-compose.yml
index 318d22f6..bdbb688b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -52,26 +52,23 @@ services:
condition: service_healthy
environment:
- PORT=8081
- - DEBUG=files
- MONGO_URL=mongodb://localhost:27017/data-fair
- - OPENAPI_VIEWER_URL=http://localhost:5600/openapi-viewer/
- DIRECTORY_URL=http://localhost:5600/simple-directory
- - NOTIFY_URL=http://localhost:5600/events
+ - PRIVATE_EVENTS_URL=http://localhost:8083
+ - PRIVATE_DIRECTORY_URL=http://localhost:8080
- PUBLIC_URL=http://localhost:5600/data-fair
- WS_PUBLIC_URL=ws://localhost:5600/data-fair
- - EXTRA_NAV_ITEMS=[{"id":"events","can":"admin","iframe":"http://localhost:5600/events/embed/events","basePath":"/events","icon":"mdi-clipboard-text-clock","title":"Traçabilité"}, {"id":"processings","can":"contrib","iframe":"http://localhost:5600/processings/processings","basePath":"/processings","icon":"mdi-cog-transfer-outline","title":"Traitements périodiques"}]
- - EXTRA_ADMIN_NAV_ITEMS=[{"id":"processings","iframe":"http://localhost:5600/processings/admin","basePath":"/processings","icon":"mdi-cog-transfer-outline","title":"Plugins - Traitements"},{"id":"processingsAdminDoc","href":"http://localhost:5600/openapi-viewer?urlType=processingsAdmin","icon":"mdi-cog-transfer-outline","title":"API Traitements périodiques"}]
- OBSERVER_ACTIVE=false
+
+ - PRIVATE_PROCESSINGS_URL=http://localhost:8082
+ - SECRET_EVENTS=secret-events
+ - EXTRA_ADMIN_NAV_ITEMS=[{"id":"processingsAdminDoc","href":"http://localhost:5600/openapi-viewer?urlType=processingsAdmin","icon":"mdi-cog-transfer-outline","title":"API Traitements périodiques"}]
+ - OPENAPI_VIEWER_URL=http://localhost:5600/openapi-viewer/
- OPENAPI_VIEWER_V2=true
- openapi-viewer:
- profiles:
- - dev
- image: ghcr.io/data-fair/openapi-viewer:master
- environment:
- - PORT=8084
- - USE_SIMPLE_DIRECTORY=true
- - ALLOWED_URLS={"processings":"http://localhost:5600/processings/api/v1/api-docs.json","processingsId":"http://localhost:5600/processings/api/v1/processings/{id}/api-docs.json","processingsAdmin":"http://localhost:5600/processings/api/v1/admin/api-docs.json"}
+ #####
+ # optional services
+ #####
events:
profiles:
@@ -80,12 +77,22 @@ services:
network_mode: host
environment:
- PORT=8083
+ - MONGO_URL=mongodb://localhost:27017/data-fair-events
- PRIVATE_DIRECTORY_URL=http://localhost:5600/simple-directory
- SECRET_IDENTITIES=secret-identities
- SECRET_EVENTS=secret-events
- SECRET_SENDMAILS=secret-sendmails
- OBSERVER_ACTIVE=false
+ openapi-viewer:
+ profiles:
+ - dev
+ image: ghcr.io/data-fair/openapi-viewer:master
+ environment:
+ - PORT=8084
+ - USE_SIMPLE_DIRECTORY=true
+ - ALLOWED_URLS={"processings":"http://localhost:5600/processings/api/v1/api-docs.json","processingsId":"http://localhost:5600/processings/api/v1/processings/{id}/api-docs.json","processingsAdmin":"http://localhost:5600/processings/api/v1/admin/api-docs.json"}
+
#####
# db and search engine
#####
diff --git a/package-lock.json b/package-lock.json
index 42a04fb5..8b23d640 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,7 @@
"@types/semver": "^7.7.1",
"eslint": "^9.29.0",
"eslint-plugin-vue": "^10.2.0",
- "eslint-plugin-vuetify": "github:albanm/eslint-plugin-vuetify",
+ "eslint-plugin-vuetify": "^2.5.3",
"husky": "^9.1.6",
"neostandard": "^0.12.1",
"tough-cookie": "^5.0.0",
@@ -581,9 +581,9 @@
}
},
"node_modules/@data-fair/lib-vuetify": {
- "version": "1.12.4",
- "resolved": "https://registry.npmjs.org/@data-fair/lib-vuetify/-/lib-vuetify-1.12.4.tgz",
- "integrity": "sha512-IjO5f7nqujEBC4m9DgaRnKTF9B35Wgtw7wbbKbq/fp+qKk7rKq9h79tEAzF3smA6TRRujmSMB1+P1otJgWDcRg==",
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/@data-fair/lib-vuetify/-/lib-vuetify-1.13.1.tgz",
+ "integrity": "sha512-Cv6Vr6XJPn7vate+YZx//sh8YT1quMbtliNhV1Eh1jAo4Rb6BU98hJRBD2xIseGCtvsNuCfqw7f5LWA1o8fN/A==",
"license": "MIT",
"dependencies": {
"@data-fair/lib-common-types": "^1.10.4",
@@ -5083,131 +5083,20 @@
}
},
"node_modules/eslint-plugin-vuetify": {
- "version": "2.4.0",
- "resolved": "git+ssh://git@github.com/albanm/eslint-plugin-vuetify.git#e25c604300a03f8b852593c71a5ce9f4d25c2acd",
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vuetify/-/eslint-plugin-vuetify-2.5.3.tgz",
+ "integrity": "sha512-HQQ3HSeg4lOQp+bImVuGsIQBgRexMGudZBZ8iK7ypQsNkKlVu2JSDDslOoTUGTj+QY/SE5PtXOwz0lMITuv8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "eslint-plugin-vue": "^9.6.0",
+ "eslint-plugin-vue": ">=9.6.0",
"requireindex": "^1.2.0"
},
"peerDependencies": {
- "eslint": "^9.0.0",
+ "eslint": "^8.0.0 || ^9.0.0",
"vuetify": "^3.0.0"
}
},
- "node_modules/eslint-plugin-vuetify/node_modules/eslint-plugin-vue": {
- "version": "9.33.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz",
- "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "globals": "^13.24.0",
- "natural-compare": "^1.4.0",
- "nth-check": "^2.1.1",
- "postcss-selector-parser": "^6.0.15",
- "semver": "^7.6.3",
- "vue-eslint-parser": "^9.4.3",
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": "^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
- }
- },
- "node_modules/eslint-plugin-vuetify/node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-plugin-vuetify/node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-plugin-vuetify/node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-plugin-vuetify/node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-plugin-vuetify/node_modules/vue-eslint-parser": {
- "version": "9.4.3",
- "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
- "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "debug": "^4.3.4",
- "eslint-scope": "^7.1.1",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.3.1",
- "esquery": "^1.4.0",
- "lodash": "^4.17.21",
- "semver": "^7.3.6"
- },
- "engines": {
- "node": "^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=6.0.0"
- }
- },
"node_modules/eslint-scope": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
@@ -7215,9 +7104,9 @@
}
},
"node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
"node_modules/lodash.camelcase": {
@@ -11282,7 +11171,7 @@
"@data-fair/frame": "^0.14.0",
"@data-fair/lib-utils": "^1.6.1",
"@data-fair/lib-vue": "^1.21.1",
- "@data-fair/lib-vuetify": "^1.10.1",
+ "@data-fair/lib-vuetify": "^1.13.0",
"@data-fair/processings-shared": "*",
"@intlify/unplugin-vue-i18n": "^6.0.8",
"@koumoul/v-iframe": "^2.4.5",
diff --git a/package.json b/package.json
index 167dbdc3..4f34f18d 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"@types/semver": "^7.7.1",
"eslint": "^9.29.0",
"eslint-plugin-vue": "^10.2.0",
- "eslint-plugin-vuetify": "github:albanm/eslint-plugin-vuetify",
+ "eslint-plugin-vuetify": "^2.5.3",
"husky": "^9.1.6",
"neostandard": "^0.12.1",
"tough-cookie": "^5.0.0",
diff --git a/ui/dts/auto-imports.d.ts b/ui/dts/auto-imports.d.ts
deleted file mode 100644
index 4035690e..00000000
--- a/ui/dts/auto-imports.d.ts
+++ /dev/null
@@ -1,271 +0,0 @@
-/* eslint-disable */
-/* prettier-ignore */
-// @ts-nocheck
-// noinspection JSUnusedGlobalSymbols
-// Generated by unplugin-auto-import
-// biome-ignore lint: disable
-export {}
-declare global {
- const $apiPath: typeof import('~/context')['$apiPath']
- const $cspNonce: typeof import('~/context')['$cspNonce']
- const $fetch: typeof import('~/context')['$fetch']
- const $sitePath: typeof import('~/context')['$sitePath']
- const $uiConfig: typeof import('~/context')['$uiConfig']
- const EffectScope: typeof import('vue')['EffectScope']
- const breadcrumbs: typeof import('../src/utils/breadcrumbs')['default']
- const computed: typeof import('vue')['computed']
- const computedDeepDiff: typeof import('@data-fair/lib-vue/deep-diff.js')['computedDeepDiff']
- const createApp: typeof import('vue')['createApp']
- const customRef: typeof import('vue')['customRef']
- const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
- const defineComponent: typeof import('vue')['defineComponent']
- const dfDateMatchFilter: typeof import('@data-fair/lib-vuetify/date-match-filter.vue')['default']
- const dfDateRangePicker: typeof import('@data-fair/lib-vuetify/date-range-picker.vue')['default']
- const dfLangSwitcher: typeof import('@data-fair/lib-vuetify/lang-switcher.vue')['default']
- const dfNavigationRight: typeof import('@data-fair/lib-vuetify/navigation-right.vue')['default']
- const dfOwnerAvatar: typeof import('@data-fair/lib-vuetify/owner-avatar.vue')['default']
- const dfOwnerPick: typeof import('@data-fair/lib-vuetify/owner-pick.vue')['default']
- const dfPersonalMenu: typeof import('@data-fair/lib-vuetify/personal-menu.vue')['default']
- const dfThemeSwitcher: typeof import('@data-fair/lib-vuetify/theme-switcher.vue')['default']
- const dfTutorialAlert: typeof import('@data-fair/lib-vuetify/tutorial-alert.vue')['default']
- const dfUiNotif: typeof import('@data-fair/lib-vuetify/ui-notif.vue')['default']
- const dfUiNotifAlert: typeof import('@data-fair/lib-vuetify/ui-notif-alert.vue')['default']
- const dfUserAvatar: typeof import('@data-fair/lib-vuetify/ui-user-avatar.vue')['default']
- const effectScope: typeof import('vue')['effectScope']
- const getCurrentInstance: typeof import('vue')['getCurrentInstance']
- const getCurrentScope: typeof import('vue')['getCurrentScope']
- const h: typeof import('vue')['h']
- const inject: typeof import('vue')['inject']
- const isProxy: typeof import('vue')['isProxy']
- const isReactive: typeof import('vue')['isReactive']
- const isReadonly: typeof import('vue')['isReadonly']
- const isRef: typeof import('vue')['isRef']
- const markRaw: typeof import('vue')['markRaw']
- const mdiAccount: typeof import('@mdi/js')['mdiAccount']
- const mdiAlert: typeof import('@mdi/js')['mdiAlert']
- const mdiAlertCircle: typeof import('@mdi/js')['mdiAlertCircle']
- const mdiBell: typeof import('@mdi/js')['mdiBell']
- const mdiBookOpenVariant: typeof import('@mdi/js')['mdiBookOpenVariant']
- const mdiCheckCircle: typeof import('@mdi/js')['mdiCheckCircle']
- const mdiClock: typeof import('@mdi/js')['mdiClock']
- const mdiCloud: typeof import('@mdi/js')['mdiCloud']
- const mdiContentDuplicate: typeof import('@mdi/js')['mdiContentDuplicate']
- const mdiDatabase: typeof import('@mdi/js')['mdiDatabase']
- const mdiDelete: typeof import('@mdi/js')['mdiDelete']
- const mdiDotsVertical: typeof import('@mdi/js')['mdiDotsVertical']
- const mdiDownload: typeof import('@mdi/js')['mdiDownload']
- const mdiInformation: typeof import('@mdi/js')['mdiInformation']
- const mdiMagnify: typeof import('@mdi/js')['mdiMagnify']
- const mdiOpenInNew: typeof import('@mdi/js')['mdiOpenInNew']
- const mdiPencil: typeof import('@mdi/js')['mdiPencil']
- const mdiPlay: typeof import('@mdi/js')['mdiPlay']
- const mdiPlayCircle: typeof import('@mdi/js')['mdiPlayCircle']
- const mdiPlusCircle: typeof import('@mdi/js')['mdiPlusCircle']
- const mdiPlusCircleOutline: typeof import('@mdi/js')['mdiPlusCircleOutline']
- const mdiPowerPlug: typeof import('@mdi/js')['mdiPowerPlug']
- const mdiStop: typeof import('@mdi/js')['mdiStop']
- const mdiToggleSwitch: typeof import('@mdi/js')['mdiToggleSwitch']
- const mdiToggleSwitchOff: typeof import('@mdi/js')['mdiToggleSwitchOff']
- const mdiUpdate: typeof import('@mdi/js')['mdiUpdate']
- const nextTick: typeof import('vue')['nextTick']
- const onActivated: typeof import('vue')['onActivated']
- const onBeforeMount: typeof import('vue')['onBeforeMount']
- const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
- const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
- const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
- const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
- const onDeactivated: typeof import('vue')['onDeactivated']
- const onErrorCaptured: typeof import('vue')['onErrorCaptured']
- const onMounted: typeof import('vue')['onMounted']
- const onRenderTracked: typeof import('vue')['onRenderTracked']
- const onRenderTriggered: typeof import('vue')['onRenderTriggered']
- const onScopeDispose: typeof import('vue')['onScopeDispose']
- const onServerPrefetch: typeof import('vue')['onServerPrefetch']
- const onUnmounted: typeof import('vue')['onUnmounted']
- const onUpdated: typeof import('vue')['onUpdated']
- const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
- const provide: typeof import('vue')['provide']
- const reactive: typeof import('vue')['reactive']
- const readonly: typeof import('vue')['readonly']
- const ref: typeof import('vue')['ref']
- const resolveComponent: typeof import('vue')['resolveComponent']
- const setBreadcrumbs: typeof import('../src/utils/breadcrumbs')['setBreadcrumbs']
- const shallowReactive: typeof import('vue')['shallowReactive']
- const shallowReadonly: typeof import('vue')['shallowReadonly']
- const shallowRef: typeof import('vue')['shallowRef']
- const toRaw: typeof import('vue')['toRaw']
- const toRef: typeof import('vue')['toRef']
- const toRefs: typeof import('vue')['toRefs']
- const toValue: typeof import('vue')['toValue']
- const triggerRef: typeof import('vue')['triggerRef']
- const unref: typeof import('vue')['unref']
- const useAsyncAction: typeof import('@data-fair/lib-vue/async-action.js')['useAsyncAction']
- const useAttrs: typeof import('vue')['useAttrs']
- const useBooleanSearchParam: typeof import('@data-fair/lib-vue/reactive-search-params.js')['useBooleanSearchParam']
- const useConceptFilters: typeof import('@data-fair/lib-vue/concept-filters.js')['useConceptFilters']
- const useCssModule: typeof import('vue')['useCssModule']
- const useCssVars: typeof import('vue')['useCssVars']
- const useFetch: typeof import('@data-fair/lib-vue/fetch.js')['useFetch']
- const useI18n: typeof import('vue-i18n')['useI18n']
- const useId: typeof import('vue')['useId']
- const useLink: typeof import('vue-router')['useLink']
- const useLocaleDayjs: typeof import('@data-fair/lib-vue/locale-dayjs.js')['useLocaleDayjs']
- const useModel: typeof import('vue')['useModel']
- const useNumberSearchParam: typeof import('@data-fair/lib-vue/reactive-search-params.js')['useNumberSearchParam']
- const usePluginFetch: typeof import('../src/composables/use-plugin-fetch')['default']
- const useReactiveSearchParams: typeof import('@data-fair/lib-vue/reactive-search-params.js')['useReactiveSearchParams']
- const useRoute: typeof import('vue-router')['useRoute']
- const useRouter: typeof import('vue-router')['useRouter']
- const useSession: typeof import('@data-fair/lib-vue/session.js')['useSession']
- const useSessionAuthenticated: typeof import('@data-fair/lib-vue/session.js')['useSessionAuthenticated']
- const useSlots: typeof import('vue')['useSlots']
- const useStringSearchParam: typeof import('@data-fair/lib-vue/reactive-search-params.js')['useStringSearchParam']
- const useStringsArraySearchParam: typeof import('@data-fair/lib-vue/reactive-search-params.js')['useStringsArraySearchParam']
- const useTemplateRef: typeof import('vue')['useTemplateRef']
- const useUiNotif: typeof import('@data-fair/lib-vue/ui-notif.js')['useUiNotif']
- const useWS: typeof import('@data-fair/lib-vue/ws.js')['useWS']
- const watch: typeof import('vue')['watch']
- const watchDeepDiff: typeof import('@data-fair/lib-vue/deep-diff.js')['watchDeepDiff']
- const watchEffect: typeof import('vue')['watchEffect']
- const watchPostEffect: typeof import('vue')['watchPostEffect']
- const watchSyncEffect: typeof import('vue')['watchSyncEffect']
- const withUiNotif: typeof import('@data-fair/lib-vue/ui-notif.js')['withUiNotif']
-}
-// for type re-export
-declare global {
- // @ts-ignore
- export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
- import('vue')
-}
-
-// for vue template auto import
-import { UnwrapRef } from 'vue'
-declare module 'vue' {
- interface GlobalComponents {}
- interface ComponentCustomProperties {
- readonly $apiPath: UnwrapRef
- readonly $cspNonce: UnwrapRef
- readonly $fetch: UnwrapRef
- readonly $sitePath: UnwrapRef
- readonly $uiConfig: UnwrapRef
- readonly EffectScope: UnwrapRef
- readonly breadcrumbs: UnwrapRef
- readonly computed: UnwrapRef
- readonly computedDeepDiff: UnwrapRef
- readonly createApp: UnwrapRef
- readonly customRef: UnwrapRef
- readonly defineAsyncComponent: UnwrapRef
- readonly defineComponent: UnwrapRef
- readonly dfDateMatchFilter: UnwrapRef
- readonly dfDateRangePicker: UnwrapRef
- readonly dfLangSwitcher: UnwrapRef
- readonly dfNavigationRight: UnwrapRef
- readonly dfOwnerAvatar: UnwrapRef
- readonly dfOwnerPick: UnwrapRef
- readonly dfPersonalMenu: UnwrapRef
- readonly dfThemeSwitcher: UnwrapRef
- readonly dfTutorialAlert: UnwrapRef
- readonly dfUiNotif: UnwrapRef
- readonly dfUiNotifAlert: UnwrapRef
- readonly dfUserAvatar: UnwrapRef
- readonly effectScope: UnwrapRef
- readonly getCurrentInstance: UnwrapRef
- readonly getCurrentScope: UnwrapRef
- readonly h: UnwrapRef
- readonly inject: UnwrapRef
- readonly isProxy: UnwrapRef
- readonly isReactive: UnwrapRef
- readonly isReadonly: UnwrapRef
- readonly isRef: UnwrapRef
- readonly markRaw: UnwrapRef
- readonly mdiAccount: UnwrapRef
- readonly mdiAlert: UnwrapRef
- readonly mdiAlertCircle: UnwrapRef
- readonly mdiBell: UnwrapRef
- readonly mdiBookOpenVariant: UnwrapRef
- readonly mdiCheckCircle: UnwrapRef
- readonly mdiClock: UnwrapRef
- readonly mdiCloud: UnwrapRef
- readonly mdiContentDuplicate: UnwrapRef
- readonly mdiDatabase: UnwrapRef
- readonly mdiDelete: UnwrapRef
- readonly mdiDotsVertical: UnwrapRef
- readonly mdiDownload: UnwrapRef
- readonly mdiInformation: UnwrapRef
- readonly mdiMagnify: UnwrapRef
- readonly mdiOpenInNew: UnwrapRef
- readonly mdiPencil: UnwrapRef
- readonly mdiPlay: UnwrapRef
- readonly mdiPlayCircle: UnwrapRef
- readonly mdiPlusCircle: UnwrapRef
- readonly mdiPlusCircleOutline: UnwrapRef
- readonly mdiPowerPlug: UnwrapRef
- readonly mdiStop: UnwrapRef
- readonly mdiToggleSwitch: UnwrapRef
- readonly mdiToggleSwitchOff: UnwrapRef
- readonly mdiUpdate: UnwrapRef
- readonly nextTick: UnwrapRef
- readonly onActivated: UnwrapRef
- readonly onBeforeMount: UnwrapRef
- readonly onBeforeRouteLeave: UnwrapRef
- readonly onBeforeRouteUpdate: UnwrapRef
- readonly onBeforeUnmount: UnwrapRef
- readonly onBeforeUpdate: UnwrapRef
- readonly onDeactivated: UnwrapRef
- readonly onErrorCaptured: UnwrapRef
- readonly onMounted: UnwrapRef
- readonly onRenderTracked: UnwrapRef
- readonly onRenderTriggered: UnwrapRef
- readonly onScopeDispose: UnwrapRef
- readonly onServerPrefetch: UnwrapRef
- readonly onUnmounted: UnwrapRef
- readonly onUpdated: UnwrapRef
- readonly onWatcherCleanup: UnwrapRef
- readonly provide: UnwrapRef
- readonly reactive: UnwrapRef
- readonly readonly: UnwrapRef
- readonly ref: UnwrapRef
- readonly resolveComponent: UnwrapRef
- readonly setBreadcrumbs: UnwrapRef
- readonly shallowReactive: UnwrapRef
- readonly shallowReadonly: UnwrapRef
- readonly shallowRef: UnwrapRef
- readonly toRaw: UnwrapRef
- readonly toRef: UnwrapRef
- readonly toRefs: UnwrapRef
- readonly toValue: UnwrapRef
- readonly triggerRef: UnwrapRef
- readonly unref: UnwrapRef
- readonly useAsyncAction: UnwrapRef
- readonly useAttrs: UnwrapRef
- readonly useBooleanSearchParam: UnwrapRef
- readonly useConceptFilters: UnwrapRef
- readonly useCssModule: UnwrapRef
- readonly useCssVars: UnwrapRef
- readonly useFetch: UnwrapRef
- readonly useI18n: UnwrapRef
- readonly useId: UnwrapRef
- readonly useLink: UnwrapRef
- readonly useLocaleDayjs: UnwrapRef
- readonly useModel: UnwrapRef
- readonly useNumberSearchParam: UnwrapRef
- readonly usePluginFetch: UnwrapRef
- readonly useReactiveSearchParams: UnwrapRef
- readonly useRoute: UnwrapRef
- readonly useRouter: UnwrapRef
- readonly useSession: UnwrapRef
- readonly useSessionAuthenticated: UnwrapRef
- readonly useSlots: UnwrapRef
- readonly useStringSearchParam: UnwrapRef
- readonly useStringsArraySearchParam: UnwrapRef
- readonly useTemplateRef: UnwrapRef
- readonly useUiNotif: UnwrapRef
- readonly useWS: UnwrapRef
- readonly watch: UnwrapRef
- readonly watchDeepDiff: UnwrapRef
- readonly watchEffect: UnwrapRef
- readonly watchPostEffect: UnwrapRef
- readonly watchSyncEffect: UnwrapRef
- readonly withUiNotif: UnwrapRef
- }
-}
\ No newline at end of file
diff --git a/ui/dts/components.d.ts b/ui/dts/components.d.ts
deleted file mode 100644
index f7a02057..00000000
--- a/ui/dts/components.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/* eslint-disable */
-// @ts-nocheck
-// Generated by unplugin-vue-components
-// Read more: https://github.com/vuejs/core/pull/3399
-export {}
-
-/* prettier-ignore */
-declare module 'vue' {
- export interface GlobalComponents {
- LayoutActions: typeof import('./../src/components/layout/layout-actions.vue')['default']
- LayoutActionsButton: typeof import('./../src/components/layout/layout-actions-button.vue')['default']
- LayoutActionsRight: typeof import('./../src/components/layout/layout-actions-right.vue')['default']
- PrivateAccess: typeof import('./../src/components/private-access.vue')['default']
- ProcessingActions: typeof import('./../src/components/processing/processing-actions.vue')['default']
- ProcessingActivity: typeof import('./../src/components/processing/processing-activity.vue')['default']
- ProcessingCard: typeof import('./../src/components/processing/processing-card.vue')['default']
- ProcessingRuns: typeof import('./../src/components/processing/processing-runs.vue')['default']
- ProcessingsActions: typeof import('./../src/components/processings-actions.vue')['default']
- RouterLink: typeof import('vue-router')['RouterLink']
- RouterView: typeof import('vue-router')['RouterView']
- RunListItem: typeof import('./../src/components/run/run-list-item.vue')['default']
- RunLogsList: typeof import('./../src/components/run/run-logs-list.vue')['default']
- }
-}
diff --git a/ui/dts/typed-router.d.ts b/ui/dts/typed-router.d.ts
deleted file mode 100644
index e671f935..00000000
--- a/ui/dts/typed-router.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/* eslint-disable */
-/* prettier-ignore */
-// @ts-nocheck
-// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
-// It's recommended to commit this file.
-// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
-
-declare module 'vue-router/auto-routes' {
- import type {
- RouteRecordInfo,
- ParamValue,
- ParamValueOneOrMore,
- ParamValueZeroOrMore,
- ParamValueZeroOrOne,
- } from 'vue-router'
-
- /**
- * Route name map generated by unplugin-vue-router
- */
- export interface RouteNamedMap {
- '/admin/': RouteRecordInfo<'/admin/', '/admin', Record, Record>,
- '/admin/plugins': RouteRecordInfo<'/admin/plugins', '/admin/plugins', Record, Record>,
- '/dev': RouteRecordInfo<'/dev', '/dev', Record, Record>,
- '/processings/': RouteRecordInfo<'/processings/', '/processings', Record, Record>,
- '/processings/[id]/': RouteRecordInfo<'/processings/[id]/', '/processings/:id', { id: ParamValue }, { id: ParamValue }>,
- '/processings/[id]/runs/[runId]': RouteRecordInfo<'/processings/[id]/runs/[runId]', '/processings/:id/runs/:runId', { id: ParamValue, runId: ParamValue }, { id: ParamValue, runId: ParamValue }>,
- '/processings/new': RouteRecordInfo<'/processings/new', '/processings/new', Record, Record>,
- }
-}
diff --git a/ui/eslint.config.mjs b/ui/eslint.config.mjs
index 04edcabe..e408dc5d 100644
--- a/ui/eslint.config.mjs
+++ b/ui/eslint.config.mjs
@@ -1,33 +1,25 @@
import neostandard from 'neostandard'
import pluginVue from 'eslint-plugin-vue'
+import pluginVuetify from 'eslint-plugin-vuetify'
import dfLibRecommended from '@data-fair/lib-utils/eslint/recommended.js'
-// cf https://github.com/vuetifyjs/eslint-plugin-vuetify/pull/98
-// @ts-ignore
-import vuetify from 'eslint-plugin-vuetify/src/index.js'
export default [
...dfLibRecommended,
...pluginVue.configs['flat/recommended'],
- {
- rules: {
- 'vue/multi-word-component-names': 'off'
- }
- },
+ ...pluginVuetify.configs['flat/recommended'],
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: {
parser: '@typescript-eslint/parser'
}
- },
- plugins: { vuetify },
- rules: {
- ...vuetify.configs.base.rules
}
},
...neostandard({ ts: true }),
{
rules: {
+ 'vue/require-default-prop': 'off',
+ 'vue/multi-word-component-names': 'off',
'no-undef': 'off' // typescript takes care of this with autoImport support
}
},
diff --git a/ui/package.json b/ui/package.json
index 8c648eb8..967c6374 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -3,12 +3,12 @@
"private": true,
"type": "module",
"scripts": {
- "dev": "NODE_CONFIG_DIR=../api/config/ vite --port 3039",
- "build": "vue-tsc -b && vite build",
- "preview": "vite preview",
+ "build": "vite build",
"check-types": "vue-tsc",
+ "dev": "NODE_CONFIG_DIR=../api/config/ vite --port 3039",
"lint": "eslint .",
- "lint-fix": "eslint --fix ."
+ "lint-fix": "eslint --fix .",
+ "preview": "vite preview"
},
"imports": {
"#api/doc": "../api/doc/index.ts",
@@ -19,7 +19,7 @@
"@data-fair/frame": "^0.14.0",
"@data-fair/lib-utils": "^1.6.1",
"@data-fair/lib-vue": "^1.21.1",
- "@data-fair/lib-vuetify": "^1.10.1",
+ "@data-fair/lib-vuetify": "^1.13.0",
"@data-fair/processings-shared": "*",
"@intlify/unplugin-vue-i18n": "^6.0.8",
"@koumoul/v-iframe": "^2.4.5",
diff --git a/ui/src/components/layout/layout-actions-button.vue b/ui/src/components/layout/layout-actions-button.vue
deleted file mode 100644
index 7641698d..00000000
--- a/ui/src/components/layout/layout-actions-button.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/ui/src/components/layout/layout-actions-right.vue b/ui/src/components/layout/layout-actions-right.vue
deleted file mode 100644
index 85d2f5b0..00000000
--- a/ui/src/components/layout/layout-actions-right.vue
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
diff --git a/ui/src/components/layout/layout-actions.vue b/ui/src/components/layout/layout-actions.vue
deleted file mode 100644
index f2afab33..00000000
--- a/ui/src/components/layout/layout-actions.vue
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/ui/src/components/processing/processing-actions.vue b/ui/src/components/processing/processing-actions.vue
index 42ae521a..3666a949 100644
--- a/ui/src/components/processing/processing-actions.vue
+++ b/ui/src/components/processing/processing-actions.vue
@@ -1,329 +1,322 @@
-
-
+
-
+
+
+
+
+ Exécuter
+
+
+
+
-
-
+
+ Vous pouvez déclencher une exécution sans être connecté à la plateforme en envoyant une requête HTTP POST à cette URL sécurisée :
+
{{ webhookLink }}
+
+
+
+
+
+
-
-
-
- Exécuter
-
-
+
-
-
+ Déclencher manuellement
+
+
+
+
+
+
+
+
+
-
-
- Vous pouvez déclencher une exécution sans être connecté à la plateforme en envoyant une requête HTTP POST à cette URL sécurisée :
-
{{ webhookLink }}
-
-
-
-
-
-
- Annuler
-
-
+
- Déclencher manuellement
-
-
-
-
-
-
+
+ Dupliquer
+
+
+
-
-
+ Vous êtes sur le point de créer une copie du traitement "{{ processing?.title }}".
+
+
+
+
+
+ Annuler
+
+
-
-
-
Dupliquer
-
-
-
+
+
+
+
+
+
+
+
-
- Vous êtes sur le point de créer une copie du traitement "{{ processing?.title }}".
-
+
-
-
-
-
- Annuler
-
-
- Dupliquer
-
-
-
-
-
-
+ Supprimer
+
+
+
-
-
+ Voulez-vous vraiment supprimer le traitement "{{ processing?.title }}" et tout son historique ? La suppression est définitive et les données ne pourront pas être récupérées.
+
+
+
+
-
-
-
- Supprimer
-
-
-
+
+ Oui
+
+
+
+
+
+
+
+
+
-
- Voulez-vous vraiment supprimer le traitement "{{ processing?.title }}" et tout son historique ? La suppression est définitive et les données ne pourront pas être récupérées.
-
-
-
-
- Non
-
-
+
- Oui
-
-
-
-
-
-
+
+ Changer le propriétaire
+
+
+
-
-
+
+
+
+
+
+
+
-
-
-
- Changer le proriétaire
-
-
-
-
+
-
-
-
-
-
-
-
- Annuler
-
-
- Confirmer
-
-
-
-
+ variant="flat"
+ :disabled="!ownersReady"
+ :loading="confirmChangeOwner.loading.value"
+ @click="confirmChangeOwner.execute()"
+ >
+ Confirmer
+
+
+
+
-
-
-
-
- Voir le jeu de données
-
+
+
+
+
+
+ Voir le jeu de données
+
-
-
-
-
- Tutoriel
-
+
+
+
+
+
+ Tutoriel
+
-
-
-
-
- Utiliser l'API
-
+
+
+
+
+
+ Utiliser l'API
+
-
-
-
-
-
-
- Notifications
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Notifications
+
+
+
+
+
+
+
+
+
+ en:
+ processingDisplayed: No processings | {displayed}/{count} processing displayed | {displayed}/{count} processings displayed
+ noProcessingsCreated: You haven't created any processings yet.
+ noProcessingsDisplayed: No results match the search criteria.
+
+ fr:
+ processingDisplayed: Aucun traitement | {displayed}/{count} traitement affiché | {displayed}/{count} traitements affichés
+ noProcessingsCreated: Vous n'avez pas encore créé de traitement.
+ noProcessingsDisplayed: Aucun résultat ne correspond aux critères de recherche.
+
+
+
diff --git a/ui/src/pages/processings/new.vue b/ui/src/pages/processings/new.vue
index a1d20712..7f12b545 100644
--- a/ui/src/pages/processings/new.vue
+++ b/ui/src/pages/processings/new.vue
@@ -7,7 +7,8 @@
>
+
+
+
+
+
Créer
-
- Retour
-
-
-
+
+
From 962c8dcb53f4fb141961ff50c3e88e1eac70f70b Mon Sep 17 00:00:00 2001
From: BatLeDev
Date: Mon, 9 Feb 2026 11:44:42 +0100
Subject: [PATCH 5/9] fix: build.json path
---
api/src/admin/router.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/api/src/admin/router.ts b/api/src/admin/router.ts
index a0e7bd80..260525fa 100644
--- a/api/src/admin/router.ts
+++ b/api/src/admin/router.ts
@@ -16,7 +16,7 @@ router.use(async (req, res, next) => {
let info = { version: process.env.NODE_ENV }
if (process.env.NODE_ENV === 'production') {
- info = JSON.parse(await readFile(resolve(import.meta.dirname, '../../BUILD.json'), 'utf8'))
+ info = JSON.parse(await readFile(resolve(import.meta.dirname, '../../../BUILD.json'), 'utf8'))
}
router.get('/info', (req, res) => {
res.send(info)
From 16388e45424367aebd4066ca87d91154309d8f7e Mon Sep 17 00:00:00 2001
From: BatLeDev
Date: Wed, 25 Feb 2026 17:23:58 +0100
Subject: [PATCH 6/9] chore: replace tooltip by titles
---
.../components/processing/processing-card.vue | 14 ++++------
ui/src/pages/processings/[id]/index.vue | 26 +++++++++----------
.../pages/processings/[id]/runs/[runId].vue | 2 +-
3 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/ui/src/components/processing/processing-card.vue b/ui/src/components/processing/processing-card.vue
index 616d610b..980572da 100644
--- a/ui/src/components/processing/processing-card.vue
+++ b/ui/src/components/processing/processing-card.vue
@@ -6,16 +6,12 @@
-
- {{ processing.title || processing._id }}
+
+ {{ processing.title }}
-
diff --git a/ui/src/pages/processings/[id]/index.vue b/ui/src/pages/processings/[id]/index.vue
index daaaf5cb..7a2fe079 100644
--- a/ui/src/pages/processings/[id]/index.vue
+++ b/ui/src/pages/processings/[id]/index.vue
@@ -51,20 +51,20 @@
:processing="processing"
class="mt-4"
/>
-
-
-
-
+
+
+
+