fix(search) : préserver la recherche des listes via le fil d'Ariane
Auto Tag Develop / tag (push) Successful in 9s
Auto Tag Develop / tag (push) Successful in 9s
Le bouton Retour (cb49c69) restaurait l'état des listes via router.back(),
mais le fil d'Ariane faisait des liens en chemin nu (sans ?q=...), ce qui
réinitialisait recherche/tri/pagination en cliquant un crumb de liste depuis
une fiche.
- useListQueryMemory : singleton mémorisant la dernière query vue sur chaque
route-liste (SPA).
- AppBreadcrumb : mémorise la query des routes-listes et la réinjecte dans les
crumbs pointant vers une liste (helper listTo). Couvre composants, pièces,
produits et machines, y compris pages catégorie/création.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<ul>
|
||||
<!-- First crumb (always visible) -->
|
||||
<li>
|
||||
<NuxtLink :to="crumbs[0].path" class="text-base-content/60 hover:text-primary transition-colors">
|
||||
<NuxtLink :to="crumbs[0].to" class="text-base-content/60 hover:text-primary transition-colors">
|
||||
{{ crumbs[0].label }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
@@ -18,7 +18,7 @@
|
||||
:key="i"
|
||||
class="hidden sm:list-item"
|
||||
>
|
||||
<NuxtLink :to="crumb.path" class="text-base-content/60 hover:text-primary transition-colors">
|
||||
<NuxtLink :to="crumb.to" class="text-base-content/60 hover:text-primary transition-colors">
|
||||
{{ crumb.label }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
@@ -32,15 +32,40 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
import { useListQueryMemory } from '~/composables/useListQueryMemory'
|
||||
|
||||
interface Crumb {
|
||||
label: string
|
||||
path: string
|
||||
to: RouteLocationRaw
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const { remember, recall } = useListQueryMemory()
|
||||
|
||||
// Routes-listes dont la recherche / tri / pagination doit survivre à une
|
||||
// navigation par fil d'Ariane ou menu (qui ne passe pas par l'historique).
|
||||
const LIST_PATHS = ['/machines', '/catalogues/composants', '/catalogues/pieces', '/catalogues/produits']
|
||||
|
||||
// On enregistre la query courante dès qu'on est sur une route-liste (et à chaque
|
||||
// changement de recherche/tri/pagination, qui modifie fullPath).
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => {
|
||||
if (LIST_PATHS.includes(route.path)) remember(route.path, route.query)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// Cible d'un crumb pointant vers une liste : on réinjecte la dernière query
|
||||
// mémorisée pour restaurer l'état, sinon chemin nu (liste neuve).
|
||||
const listTo = (path: string): RouteLocationRaw => {
|
||||
const query = recall(path)
|
||||
return query && Object.keys(query).length > 0 ? { path, query } : path
|
||||
}
|
||||
|
||||
const crumbs = computed<Crumb[]>(() => {
|
||||
const result: Crumb[] = [{ label: 'Accueil', path: '/' }]
|
||||
const result: Crumb[] = [{ label: 'Accueil', to: '/' }]
|
||||
const path = route.path
|
||||
|
||||
// Home page — no breadcrumb
|
||||
@@ -48,88 +73,88 @@ const crumbs = computed<Crumb[]>(() => {
|
||||
|
||||
// Machine context from query param (when navigating from a machine detail page)
|
||||
if (route.query.from === 'machine' && route.query.machineId) {
|
||||
result.push({ label: 'Parc machines', path: '/machines' })
|
||||
result.push({ label: 'Machine', path: `/machine/${route.query.machineId}` })
|
||||
result.push({ label: 'Parc machines', to: listTo('/machines') })
|
||||
result.push({ label: 'Machine', to: `/machine/${route.query.machineId}` })
|
||||
}
|
||||
|
||||
// Machines
|
||||
if (path === '/machines') {
|
||||
result.push({ label: 'Parc machines', path: '/machines' })
|
||||
result.push({ label: 'Parc machines', to: listTo('/machines') })
|
||||
} else if (path.startsWith('/machine/') && !route.query.from) {
|
||||
result.push({ label: 'Parc machines', path: '/machines' })
|
||||
result.push({ label: 'Machine', path })
|
||||
result.push({ label: 'Parc machines', to: listTo('/machines') })
|
||||
result.push({ label: 'Machine', to: path })
|
||||
}
|
||||
|
||||
// Catalogs
|
||||
else if (path.startsWith('/catalogues/composants')) {
|
||||
result.push({ label: 'Composants', path: '/catalogues/composants' })
|
||||
result.push({ label: 'Composants', to: listTo('/catalogues/composants') })
|
||||
} else if (path.startsWith('/catalogues/pieces')) {
|
||||
result.push({ label: 'Pièces', path: '/catalogues/pieces' })
|
||||
result.push({ label: 'Pièces', to: listTo('/catalogues/pieces') })
|
||||
} else if (path.startsWith('/catalogues/produits')) {
|
||||
result.push({ label: 'Produits', path: '/catalogues/produits' })
|
||||
result.push({ label: 'Produits', to: listTo('/catalogues/produits') })
|
||||
}
|
||||
|
||||
// Entity detail pages (when NOT from machine context)
|
||||
else if (path.startsWith('/component/') && !route.query.from) {
|
||||
result.push({ label: 'Composants', path: '/catalogues/composants' })
|
||||
result.push({ label: 'Composant', path })
|
||||
result.push({ label: 'Composants', to: listTo('/catalogues/composants') })
|
||||
result.push({ label: 'Composant', to: path })
|
||||
} else if (path.startsWith('/piece/') && !route.query.from) {
|
||||
result.push({ label: 'Pièces', path: '/catalogues/pieces' })
|
||||
result.push({ label: 'Pièce', path })
|
||||
result.push({ label: 'Pièces', to: listTo('/catalogues/pieces') })
|
||||
result.push({ label: 'Pièce', to: path })
|
||||
} else if (path.startsWith('/product/') && !route.query.from) {
|
||||
result.push({ label: 'Produits', path: '/catalogues/produits' })
|
||||
result.push({ label: 'Produit', path })
|
||||
result.push({ label: 'Produits', to: listTo('/catalogues/produits') })
|
||||
result.push({ label: 'Produit', to: path })
|
||||
}
|
||||
|
||||
// Entity detail pages WITH machine context — add entity as last crumb
|
||||
else if (path.startsWith('/component/') && route.query.from === 'machine') {
|
||||
result.push({ label: 'Composant', path })
|
||||
result.push({ label: 'Composant', to: path })
|
||||
} else if (path.startsWith('/piece/') && route.query.from === 'machine') {
|
||||
result.push({ label: 'Pièce', path })
|
||||
result.push({ label: 'Pièce', to: path })
|
||||
} else if (path.startsWith('/product/') && route.query.from === 'machine') {
|
||||
result.push({ label: 'Produit', path })
|
||||
result.push({ label: 'Produit', to: path })
|
||||
}
|
||||
|
||||
// Admin pages
|
||||
else if (path.startsWith('/sites')) {
|
||||
result.push({ label: 'Sites', path: '/sites' })
|
||||
result.push({ label: 'Sites', to: '/sites' })
|
||||
} else if (path.startsWith('/constructeurs')) {
|
||||
result.push({ label: 'Fournisseurs', path: '/constructeurs' })
|
||||
result.push({ label: 'Fournisseurs', to: '/constructeurs' })
|
||||
} else if (path.startsWith('/activity-log')) {
|
||||
result.push({ label: 'Journal d\'activité', path: '/activity-log' })
|
||||
result.push({ label: 'Journal d\'activité', to: '/activity-log' })
|
||||
} else if (path.startsWith('/admin')) {
|
||||
result.push({ label: 'Administration', path: '/admin' })
|
||||
result.push({ label: 'Administration', to: '/admin' })
|
||||
} else if (path.startsWith('/documents')) {
|
||||
result.push({ label: 'Documents', path: '/documents' })
|
||||
result.push({ label: 'Documents', to: '/documents' })
|
||||
} else if (path.startsWith('/comments')) {
|
||||
result.push({ label: 'Commentaires', path: '/comments' })
|
||||
result.push({ label: 'Commentaires', to: '/comments' })
|
||||
}
|
||||
|
||||
// Category pages
|
||||
else if (path.startsWith('/component-category')) {
|
||||
result.push({ label: 'Composants', path: '/catalogues/composants' })
|
||||
result.push({ label: 'Catégorie', path })
|
||||
result.push({ label: 'Composants', to: listTo('/catalogues/composants') })
|
||||
result.push({ label: 'Catégorie', to: path })
|
||||
} else if (path.startsWith('/piece-category')) {
|
||||
result.push({ label: 'Pièces', path: '/catalogues/pieces' })
|
||||
result.push({ label: 'Catégorie', path })
|
||||
result.push({ label: 'Pièces', to: listTo('/catalogues/pieces') })
|
||||
result.push({ label: 'Catégorie', to: path })
|
||||
} else if (path.startsWith('/product-category')) {
|
||||
result.push({ label: 'Produits', path: '/catalogues/produits' })
|
||||
result.push({ label: 'Catégorie', path })
|
||||
result.push({ label: 'Produits', to: listTo('/catalogues/produits') })
|
||||
result.push({ label: 'Catégorie', to: path })
|
||||
}
|
||||
|
||||
// Create pages
|
||||
else if (path.startsWith('/pieces/create')) {
|
||||
result.push({ label: 'Pièces', path: '/catalogues/pieces' })
|
||||
result.push({ label: 'Nouvelle pièce', path })
|
||||
result.push({ label: 'Pièces', to: listTo('/catalogues/pieces') })
|
||||
result.push({ label: 'Nouvelle pièce', to: path })
|
||||
} else if (path.startsWith('/component/create')) {
|
||||
result.push({ label: 'Composants', path: '/catalogues/composants' })
|
||||
result.push({ label: 'Nouveau composant', path })
|
||||
result.push({ label: 'Composants', to: listTo('/catalogues/composants') })
|
||||
result.push({ label: 'Nouveau composant', to: path })
|
||||
} else if (path.startsWith('/product/create')) {
|
||||
result.push({ label: 'Produits', path: '/catalogues/produits' })
|
||||
result.push({ label: 'Nouveau produit', path })
|
||||
result.push({ label: 'Produits', to: listTo('/catalogues/produits') })
|
||||
result.push({ label: 'Nouveau produit', to: path })
|
||||
} else if (path === '/machines/new') {
|
||||
result.push({ label: 'Parc machines', path: '/machines' })
|
||||
result.push({ label: 'Nouvelle machine', path })
|
||||
result.push({ label: 'Parc machines', to: listTo('/machines') })
|
||||
result.push({ label: 'Nouvelle machine', to: path })
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user