Funzionalita Avanzate
Ricerche Salvate
Persistenza dello stato di ricerca completo tramite adapter custom (v2).
Panoramica
Le ricerche salvate permettono agli utenti di salvare, caricare e gestire configurazioni di ricerca complete (filtri + preset + regole + group-by). La libreria fornisce solo l'interfaccia SavedSearchAdapter: l'implementazione dello storage è a carico del consumer (REST, GraphQL, IndexedDB, in-memory).
Il pannello viene renderizzato solo se la prop savedSearchAdapter è presente nella SearchToolbar. La ricerca con isDefault: true viene applicata automaticamente al mount.
Anteprima live (con adapter in-memory)
Interfaccia adapter
interface SavedSearchAdapter {
/** Carica tutte le ricerche accessibili all'utente */
list(): Promise<SavedSearch[]>
/** Salva con nome e stato corrente */
save(
name: string,
state: SavedSearchState,
options?: { isDefault?: boolean; isShared?: boolean }
): Promise<SavedSearch>
/** Aggiorna metadati (opzionale — se assente la UI nasconde "Modifica") */
update?(
id: string,
patch: Partial<Pick<SavedSearch, 'name' | 'isDefault' | 'isShared' | 'sharedWith'>>
): Promise<SavedSearch>
/** Elimina per ID */
delete(id: string): Promise<void>
/** Soft delete (opzionale — se assente la UI mostra solo "Elimina") */
archive?(id: string): Promise<void>
/** Imposta/rimuove il flag default (id=null rimuove) */
setDefault(id: string | null): Promise<void>
}
Struttura SavedSearch
interface SavedSearchState {
filters: Record<string, unknown>
activePresets: string[]
rules: RuleGroup | null
groupByFields: GroupByEntry[]
}
interface SavedSearch {
id: string
name: string
state: SavedSearchState
isDefault: boolean // applicata automaticamente al mount se true
isShared: boolean
sharedWith?: string[]
createdAt: string // ISO 8601
updatedAt: string // ISO 8601
}
Implementazione adapter (esempio con API REST)
import type { SavedSearchAdapter, SavedSearch, SavedSearchState } from '@pzeta/vue-ricerca'
const searchAdapter: SavedSearchAdapter = {
async list() {
const res = await fetch('/api/ricerche-salvate')
return res.json()
},
async save(name, state, options) {
const res = await fetch('/api/ricerche-salvate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, state, ...options }),
})
return res.json()
},
async delete(id) {
await fetch(`/api/ricerche-salvate/${id}`, { method: 'DELETE' })
},
async setDefault(id) {
await fetch(`/api/ricerche-salvate/default`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id }),
})
},
}
Utilizzo in SearchToolbar
<SearchToolbar
v-model="filtri"
:fields="fields"
:saved-search-adapter="searchAdapter"
@apply="onApply"
/>
Via useSearchToolbar
const {
savedSearches,
savedSearchesLoading,
canUpdateSearch,
canArchiveSearch,
saveSearch,
updateSearch,
archiveSearch,
loadSearch,
deleteSearch,
setDefaultSearch,
} = useSearchToolbar({
fields,
savedSearchAdapter: searchAdapter,
onApply: (state) => { /* ... */ },
})
// Salva ricerca corrente (snapshot di searchState.value)
await saveSearch('Ricerca clienti attivi', {
isDefault: false,
isShared: false,
sharedWith: ['user-1', 'user-2'],
})
// Ripristina una ricerca salvata (aggiorna filtri, preset, rules, groupBy)
loadSearch('uuid-ricerca')
// Aggiorna metadati (richiede adapter.update)
if (canUpdateSearch) {
await updateSearch('uuid-ricerca', { name: 'Nuovo nome', isShared: true })
}
// Soft delete (richiede adapter.archive)
if (canArchiveSearch) {
await archiveSearch('uuid-ricerca')
}
// Hard delete
await deleteSearch('uuid-ricerca')
// Imposta come default (al prossimo mount verrà applicata automaticamente)
await setDefaultSearch('uuid-ricerca')
// Rimuove il default
await setDefaultSearch(null)
Note
- La ricerca con
isDefault: trueviene applicata automaticamente al mount del componente. canUpdateSearchètruese l'adapter implementa il metodoupdate.canArchiveSearchètruese l'adapter implementa il metodoarchive.- La libreria non interpreta
sharedWith: è un array opaco passato all'adapter senza elaborazione.