Éditeur de stock
Valider les cellules et recalculer les stocks.
Ce que vous allez construire
Modifiez le stock directement, refusez les quantités invalides et gardez les totaux cohérents après écriture.
Partez de l’installation React ou Vue. Assemblez les fichiers complets ci-dessous et les modules partagés. Le stockage mémoire se réinitialise au rechargement ; une API doit conserver les mêmes contrats.
Fichiers nécessaires : shared/products.ts, shared/store.ts, product-config.ts, list-records.ts, view-actions.ts, editable-actions.ts, product-form.ts, get-form-config.ts, stock-config.ts, recipe-stock.
Copiez le stockage et l’adaptateur communs, puis le catalogue de formulaire produit. La colonne stock utilise ce schéma et la même action update que le formulaire complet.
stock-config.ts
import { defineTableConfig } from "@/components/ui/yayaw-table/config/helpers";
import { productConfig } from "./product-config";
export const stockConfig = defineTableConfig({
...productConfig,
columns: {
...productConfig.columns,
definitions: productConfig.columns.definitions.map((column) =>
column.id === "stock"
? {
...column,
inlineEdit: { enabled: true, editor: "number" },
defaultCalculation: "sum",
}
: column
),
},
table: {
...productConfig.table,
allowInlineEdit: true,
allowEdit: true,
enableCalculations: true,
inlineEdit: { enabled: true, debounceMs: 400, optimistic: true },
rowClickMode: "none",
},
});import { defineTableConfig } from "@/components/ui/yayaw-table-vue/config";
import { productConfig } from "./product-config";
export const stockConfig = defineTableConfig({
...productConfig,
columns: {
...productConfig.columns,
definitions: productConfig.columns.definitions.map((column) =>
column.id === "stock"
? {
...column,
inlineEdit: { enabled: true, editor: "number" },
defaultCalculation: "sum",
}
: column
),
},
table: {
...productConfig.table,
allowInlineEdit: true,
allowEdit: true,
enableCalculations: true,
inlineEdit: { enabled: true, debounceMs: 400, optimistic: true },
rowClickMode: "none",
},
});Composant d’entrée
Données de démonstration. Les modifications restent dans cet aperçu.
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { NuqsAdapter } from "nuqs/adapters/react";
import { useState } from "react";
import { Toaster } from "sonner";
import { DataTable } from "@/components/ui/yayaw-table";
import { productStore } from "../shared/store";
import { editableActions } from "./editable-actions";
import { getFormConfig } from "./get-form-config";
import type { ExamplePresentation } from "./presentation";
import { stockConfig } from "./stock-config";
const getConfig = () => stockConfig;
export default function StockRecipe(presentation: ExamplePresentation = {}) {
const [queryClient] = useState(() => new QueryClient());
const [getStockActions] = useState(() => {
const actions = {
...editableActions,
update: async (id: string, patch: Record<string, unknown>) => {
const result = productStore.update(id, patch);
if (result.success) {
// The copied React registry caches footer totals separately from row data.
await queryClient.invalidateQueries({
queryKey: ["tableColumnCalculations", "recipe-stock"],
});
}
return result;
},
};
return (tableType: string) =>
tableType === "products" ? actions : undefined;
});
return (
<QueryClientProvider client={queryClient}>
<NuqsAdapter>
<DataTable
{...presentation}
getFormConfig={getFormConfig}
getRowId={(row) => String(row.id)}
getTableActions={getStockActions}
getTableConfig={getConfig}
tableId="recipe-stock"
tableType="products"
title={presentation.title ?? "Stock"}
/>
<Toaster />
</NuqsAdapter>
</QueryClientProvider>
);
}Données de démonstration. Les modifications restent dans cet aperçu.
<script setup lang="ts">
import type { ExamplePresentation } from "./presentation";
defineProps<ExamplePresentation>();
import { YayawDataTable } from "@/components/ui/yayaw-table-vue";
import { getEditableActions } from "./editable-actions";
import { getFormConfig } from "./get-form-config";
import { stockConfig } from "./stock-config";
const getRowId = (row: Record<string, unknown>) => String(row.id);
</script>
<template>
<YayawDataTable v-bind="$props" table-type="products" table-id="recipe-stock" :title="title ?? 'Stock'"
:config="stockConfig" :get-table-actions="getEditableActions" :get-row-id="getRowId"
:get-form-config="getFormConfig" />
</template>Vérifier le résultat
Le stock initial total est 18.
Passez le stock Oak desk de 12 à 15 et validez : le total devient 21.
Essayez -1 ou 1,5 : la validation refuse.
Filtrez le statut sur Draft : le total est zéro.
Effacez les filtres et vérifiez que la modification valide reste présente.
Utilisez le playground existant pour explorer les contrôles de la bibliothèque.
La recette React invalide le cache des calculs après une mise à jour réussie. Dans le registre vérifié, ce cache utilise ["tableColumnCalculations", tableId] séparément des lignes. Conservez ce rafraîchissement lorsque vous branchez une action serveur ; une erreur de validation laisse le total inchangé.
Vérifier le résultat pas à pas
| Action | Résultat attendu |
|---|---|
| Ouvrez le tableau de stock. | Le total est 18 : 12 + 0 + 6. |
Remplacez le stock de Oak desk par 15. | La ligne est enregistrée et le total devient 21. |
Essayez -1 ou 1.5. | La validation refuse l’écriture et conserve la dernière valeur enregistrée. |
Saisissez 0 pour Desk lamp. | Zéro reste un nombre valide ; ce n’est pas un champ vide. |
Sur mobile, utilisez les Réglages de la vue pour la présentation, le menu Données pour l’export, et le bouton de recherche de la barre d’outils. Réinitialiser une vue n’annule pas les écritures. Testez aussi le clavier.