mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-22 14:38:10 +02:00
perf: lot 1 — chargements plus rapides et corrections, sans changement visuel
Grille (navigateur) - « Rafraîchir » ne passe plus par l'URL : le paramètre _refresh restait mémorisé et chaque retour par le menu forçait un recalcul serveur complet (migration du store pour nettoyer les valeurs déjà enregistrées). - Lignes reçues regroupées toutes les 300 ms au lieu de reconstruire tout le tableau à chaque paquet de 150 (chargement quadratique). - Sélection indexée par code article (getRowId) : après un filtre, l'action groupée visait d'autres produits. Seules les lignes affichées comptent. - Recherche : un passage par ligne au lieu d'un par colonne ; formateurs de nombres partagés (lib/format.ts) ; colonnes mensuelles mémorisées ; plus de transition-all sur les lignes positionnées par transform. - exceljs, jspdf et xlsx chargés au clic seulement. Grille (serveur) - Requêtes Qlik et snapshot lancées en parallèle de la phase SQL. - Cache mémoire borné (LRU) ; calcul en cours réutilisé même en forcé ; flux interrompu quand le client part. - Après un enregistrement, les gammes sont reportées dans le cache et dans grid_rows au lieu d'invalider (recalcul de ~40 s évité). Données et API - lib/ff-cache.ts : cache mémoire 30 min des lectures FF (stock, hit-parade, CA mensuel, fournisseurs, dernière réception, publicités), vidé en fin de synchro nocturne ; erreurs jamais gardées. - Pool PostgreSQL unique (globalThis), réglage sans workers parallèles posé une fois par connexion au lieu d'une transaction autour de chaque requête. - Délai maximal sur tous les appels à l'API FF. - Index session_snapshots ; commandes : plus de double rechargement ; synchro : saisies regroupées ; paramètres : configuration lue une fois ; journal de capture en ajout seul, rien de formaté sans capture ouverte. Corrections - Historique : l'échec de chargement s'affiche (au lieu de « Aucun snapshot »). - Sessions et validations enregistrent le magasin affiché, plus « TOTAL ». - Publicités : libellé du statut « passées ». Plan complet : docs/plan-optimisation-webui.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AcA129WzGTH6zxPHFBGWmn
This commit is contained in:
35 files changed
+1010
-240
No files matched your search
@@ -16,6 +16,14 @@ interface GridState {
|
||||
displayDensity: "compact" | "normal" | "comfortable";
|
||||
/** The active URL search parameters (e.g. ?fournisseur=123&magasin=TOTAL) */
|
||||
activeGridQuery: string;
|
||||
/**
|
||||
* Compteur de demandes de rechargement forcé (ignore le cache serveur).
|
||||
* Volontairement hors URL et non persisté : un paramètre `_refresh` dans
|
||||
* l'URL restait mémorisé dans `activeGridQuery`, et chaque retour sur la
|
||||
* Grille par le menu relançait un recalcul complet.
|
||||
*/
|
||||
refreshRequest: number;
|
||||
requestRefresh: () => void;
|
||||
/** Persisted column visibility state */
|
||||
columnVisibility: Record<string, boolean>;
|
||||
/** Persisted column sizing state */
|
||||
@@ -59,6 +67,15 @@ interface GridState {
|
||||
|
||||
let summaryTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
/** Retire l'ancien paramètre `_refresh` (cache-buster) d'une query string mémorisée. */
|
||||
function sansParamRefresh(query: string): string {
|
||||
if (!query.includes("_refresh")) return query;
|
||||
const params = new URLSearchParams(query.startsWith("?") ? query.slice(1) : query);
|
||||
params.delete("_refresh");
|
||||
const qs = params.toString();
|
||||
return qs ? `?${qs}` : "";
|
||||
}
|
||||
|
||||
function indexRows(rows: ProductRow[]): Record<string, ProductRow> {
|
||||
const indexed: Record<string, ProductRow> = {};
|
||||
for (const row of rows) indexed[row.codein] = row;
|
||||
@@ -117,6 +134,7 @@ export const useGridStore = create<GridState>()(
|
||||
},
|
||||
displayDensity: "normal",
|
||||
activeGridQuery: "",
|
||||
refreshRequest: 0,
|
||||
columnVisibility: {},
|
||||
columnSizing: {},
|
||||
showMonthlySales: true,
|
||||
@@ -202,7 +220,8 @@ export const useGridStore = create<GridState>()(
|
||||
set((state) => ({ ...state, filters: { ...state.filters, code3: codes } }));
|
||||
},
|
||||
setDisplayDensity: (density) => set({ displayDensity: density }),
|
||||
setActiveGridQuery: (query) => set({ activeGridQuery: query }),
|
||||
setActiveGridQuery: (query) => set({ activeGridQuery: sansParamRefresh(query) }),
|
||||
requestRefresh: () => set((state) => ({ refreshRequest: state.refreshRequest + 1 })),
|
||||
restoreSnapshot: (changes) => {
|
||||
set({ draftChanges: changes, summary: computeSummary(get().rows, changes, get().activeMagasin) });
|
||||
},
|
||||
@@ -249,8 +268,11 @@ export const useGridStore = create<GridState>()(
|
||||
* dans le navigateur restait une chaîne : `new Set("320211")` produit un
|
||||
* ensemble de caractères, plus aucune ligne ne correspond, et la Grille
|
||||
* apparaît vide. Le numéro de version force la reprise de l'existant.
|
||||
*
|
||||
* v2 — `activeGridQuery` pouvait contenir `_refresh=…` : le lien « Grille »
|
||||
* du menu forçait alors un recalcul serveur complet à chaque retour.
|
||||
*/
|
||||
version: 1,
|
||||
version: 2,
|
||||
migrate: (persisted: unknown, version: number): GridPersisted => {
|
||||
const etat = (persisted ?? {}) as GridPersisted & { filters?: Record<string, unknown> };
|
||||
if (version < 1 && etat.filters) {
|
||||
@@ -262,6 +284,9 @@ export const useGridStore = create<GridState>()(
|
||||
// à la fusion (le bloc disparaîtrait sans raison).
|
||||
if (typeof etat.showMonthlySales !== "boolean") etat.showMonthlySales = true;
|
||||
if (typeof etat.showPrices !== "boolean") etat.showPrices = true;
|
||||
if (typeof etat.activeGridQuery === "string") {
|
||||
etat.activeGridQuery = sansParamRefresh(etat.activeGridQuery);
|
||||
}
|
||||
return etat;
|
||||
},
|
||||
// Only persist filters, display density, drafts, active grid query, and column visibility/sizing
|
||||
|
||||
Reference in new issue
Block a user