data-primals-engine 1.6.5 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,260 +1,275 @@
1
- import React, {createContext, useContext, useState, useCallback, useRef, useEffect, useMemo} from 'react';
2
- import { useQueryClient } from 'react-query';
3
- import { useNotificationContext } from '../NotificationProvider.jsx';
4
- import { useTranslation } from 'react-i18next';
5
- import {elementsPerPage} from "../../../src/constants.js";
6
- import {useModelContext} from "./ModelContext.jsx";
7
-
8
- const CommandContext = createContext({});
9
-
10
- export const useCommand = () => useContext(CommandContext);
11
-
12
- // --- Command Manager ---
13
- class CommandManager {
14
- constructor() {
15
- this.history = [];
16
- this.currentIndex = -1;
17
- // Les dépendances seront injectées via updateDependencies
18
- this.addNotification = () => {};
19
- this.t = (key) => key;
20
- this.onResetQueryClient = () => {};
21
- this.queryClient = null; // Ajout pour stocker le queryClient
22
- }
23
-
24
- updateDependencies(addNotification, t, onResetQueryClient, queryClient) {
25
- this.addNotification = addNotification;
26
- this.t = t;
27
- this.onResetQueryClient = onResetQueryClient;
28
- this.queryClient = queryClient; // Injection du client
29
- }
30
-
31
- async execute(command) {
32
- try {
33
- // Supprimer l'historique "redo" si on exécute une nouvelle commande
34
- this.history = this.history.slice(0, this.currentIndex + 1);
35
- await command.execute();
36
- this.history.push(command);
37
- this.currentIndex++;
38
- await this.invalidateQueries(command.modelName, command.constructor.name);
39
- // On vide la sélection APRÈS avoir invalidé, pour éviter les conflits de rendu.
40
- if (command instanceof DeleteCommand && this.context?.setCheckedItems) {
41
- this.context.setCheckedItems([]);
42
- }
43
- this.addNotification({ title: command.successMessage, status: 'completed' });
44
- } catch (error) {
45
- console.error("Command execution failed:", error);
46
- this.addNotification({ title: this.t('command.error.execute', 'Erreur d\'exécution'), message: error.message, status: 'error' });
47
- }
48
- }
49
-
50
- async undo() {
51
- if (this.canUndo()) {
52
- try {
53
- const command = this.history[this.currentIndex];
54
- await command.undo();
55
- this.currentIndex--;
56
- await this.invalidateQueries(command.modelName, command.constructor.name + 'Undo');
57
- this.addNotification({ title: this.t('command.success.undo', 'Action annulée'), status: 'completed' });
58
- } catch (error) {
59
- console.error("Command undo failed:", error);
60
- this.addNotification({ title: this.t('command.error.undo', 'Erreur d\'annulation'), message: error.message, status: 'error' });
61
- }
62
- }
63
- }
64
-
65
- async redo() {
66
- if (this.canRedo()) {
67
- try {
68
- this.currentIndex++;
69
- const command = this.history[this.currentIndex];
70
- await command.execute();
71
- await this.invalidateQueries(command.modelName, command.constructor.name);
72
- this.addNotification({ title: this.t('command.success.redo', 'Action rétablie'), status: 'completed' });
73
- } catch (error) {
74
- console.error("Command redo failed:", error);
75
- this.addNotification({ title: this.t('command.error.redo', 'Erreur de rétablissement'), message: error.message, status: 'error' });
76
- }
77
- }
78
- }
79
-
80
- canUndo() {
81
- return this.currentIndex >= 0;
82
- }
83
-
84
- canRedo() {
85
- return this.currentIndex < this.history.length - 1;
86
- }
87
-
88
- async invalidateQueries(modelName, commandType) {
89
- // Solution plus fine : on invalide seulement les requêtes concernées.
90
- // React Query s'occupera de rafraîchir les données de manière optimisée.
91
- if (this.queryClient && modelName) {
92
- // Invalide toutes les requêtes liées à ce modèle (listes, paginations, etc.)
93
- await this.queryClient.invalidateQueries(['api/data', modelName]);
94
- }
95
- }
96
- }
97
-
98
- // --- Command Definitions ---
99
-
100
- export class InsertCommand {
101
- constructor(apiCall, modelName, formData) {
102
- this.apiCall = apiCall;
103
- this.modelName = modelName;
104
- this.formData = { ...formData };
105
- this.insertedItem = null; // On va stocker l'objet complet inséré
106
- this.successMessage = "Donnée ajoutée";
107
- }
108
-
109
- async execute() {
110
- // Si on a déjà un item (cas du redo), on le ré-insère. Sinon, on utilise le formData initial.
111
- const dataToInsert = this.insertedItem ? { ...this.insertedItem, _id: undefined, _hash: undefined } : this.formData;
112
-
113
- const response = await this.apiCall({ formData: dataToInsert, record: null });
114
- if (!response.success) throw new Error(response.error || 'Insert failed');
115
-
116
- // On stocke l'objet complet retourné par l'API, qui inclut le nouvel _id.
117
- this.insertedItem = response.data;
118
- if (!this.insertedItem?._id) throw new Error('No inserted data returned from API');
119
- }
120
-
121
- async undo() {
122
- // On garde une copie de l'item avant de le supprimer pour le redo.
123
- if (!this.insertedItem?._id) throw new Error("Cannot undo insert: item ID is missing.");
124
- const response = await fetch(`/api/data/${this.insertedItem._id}`, { method: 'DELETE' });
125
- const result = await response.json();
126
- if (!response.ok || !result.success) {
127
- throw new Error(result.error || 'Undo (delete) failed');
128
- }
129
- }
130
- }
131
-
132
- export class UpdateCommand {
133
- constructor(apiCall, modelName, originalData, newData) {
134
- this.apiCall = apiCall;
135
- this.modelName = modelName;
136
- this.originalData = { ...originalData }; // Copie pour l'undo
137
- this.newData = { ...newData };
138
- this.recordId = originalData._id;
139
- this.successMessage = "Donnée mise à jour";
140
- }
141
-
142
- async execute() {
143
- const response = await this.apiCall({ formData: this.newData, record: this.originalData });
144
- if (!response.success) throw new Error(response.error || 'Update failed');
145
- }
146
-
147
- async undo() {
148
- // Pour annuler, on ré-applique les données originales
149
- await this.apiCall({ formData: this.originalData, record: this.originalData });
150
- }
151
- }
152
-
153
- export class DeleteCommand {
154
- constructor(apiCall, modelName, itemsToDelete) { // queryClient a été retiré
155
- this.apiCall = apiCall;
156
- this.modelName = modelName;
157
- this.itemsToDelete = Array.isArray(itemsToDelete) ? [...itemsToDelete] : [itemsToDelete];
158
- this.successMessage = "Donnée(s) supprimée(s)";
159
- }
160
-
161
- async execute() {
162
- const response = await this.apiCall(this.itemsToDelete);
163
- if (!response.success) throw new Error(response.error || 'Delete failed');
164
- }
165
-
166
- async undo() {
167
- // Pour annuler, on ré-insère chaque document supprimé
168
- // Note : cela crée de nouveaux _id, mais restaure les données.
169
- const reinsertPromises = this.itemsToDelete.map(item => {
170
- const reinsertData = { ...item };
171
- delete reinsertData._id; // L'API doit générer un nouvel ID
172
- delete reinsertData._hash;
173
-
174
- return fetch('/api/data?_user=system', { // On ajoute _user=system pour tracer l'origine de l'action
175
- method: 'POST',
176
- headers: { 'Content-Type': 'application/json' },
177
- body: JSON.stringify({ model: this.modelName, data: reinsertData }),
178
- }).then(res => res.json().then(data => {
179
- if (!res.ok || !data.success) {
180
- throw new Error(data.error || `Undo (re-insert) failed for item ${item._id}.`);
181
- }
182
- // On retourne l'objet complet retourné par l'API, qui contient le nouvel _id
183
- return data.data;
184
- }));
185
- });
186
-
187
- // On attend que toutes les réinsertions soient terminées.
188
- const reinsertedItems = await Promise.all(reinsertPromises);
189
-
190
- // *** CORRECTION CRUCIALE ***
191
- // On met à jour la liste des items de la commande avec les nouvelles données (et les nouveaux _id).
192
- // Ainsi, si un "redo" est exécuté, il ciblera les bons documents à supprimer.
193
- this.itemsToDelete = reinsertedItems;
194
- }
195
- }
196
-
197
- // --- Singleton Command Manager ---
198
- // On crée l'instance du manager EN DEHORS du composant React.
199
- // Ainsi, elle ne sera pas détruite et recréée à chaque re-rendu de l'application,
200
- // ce qui permet de conserver l'historique des commandes (undo/redo).
201
- const commandManagerInstance = new CommandManager();
202
-
203
- // --- Provider Component ---
204
- export const CommandProvider = ({ children, onResetQueryClient }) => {
205
- const { addNotification } = useNotificationContext();
206
- const { t, i18n } = useTranslation();
207
- const queryClient = useQueryClient(); // On récupère le client ici
208
- const lang = (i18n.resolvedLanguage || i18n.language).split(/[-_]/)?.[0];
209
-
210
- // On utilise l'instance unique et on met à jour ses dépendances via useEffect
211
- // pour s'assurer qu'elle a toujours les dernières fonctions (qui sont recréées à chaque rendu).
212
- const commandManagerRef = useRef(commandManagerInstance);
213
- useEffect(() => {
214
- commandManagerInstance.updateDependencies(addNotification, t, onResetQueryClient, queryClient);
215
- }, [addNotification, t, onResetQueryClient, queryClient]);
216
-
217
- const [canUndo, setCanUndo] = useState(commandManagerRef.current.canUndo());
218
- const [canRedo, setCanRedo] = useState(commandManagerRef.current.canRedo());
219
-
220
- const updateUndoRedoState = () => {
221
- setCanUndo(commandManagerRef.current.canUndo());
222
- setCanRedo(commandManagerRef.current.canRedo());
223
- };
224
-
225
- const execute = async (command) => {
226
- await commandManagerRef.current.execute(command);
227
- updateUndoRedoState();
228
- };
229
-
230
- const undo = async () => {
231
- await commandManagerRef.current.undo();
232
- updateUndoRedoState();
233
- };
234
-
235
- const redo = async () => {
236
- await commandManagerRef.current.redo();
237
- updateUndoRedoState();
238
- };
239
-
240
- // --- CORRECTION ---
241
- // On inclut `setManagerContext` directement dans la valeur du contexte
242
- // et on mémorise l'objet avec `useMemo` pour la stabilité.
243
- const value = useMemo(() => ({
244
- execute,
245
- undo,
246
- redo,
247
- canUndo,
248
- canRedo,
249
- InsertCommand,
250
- UpdateCommand,
251
- DeleteCommand,
252
- setManagerContext: (context) => {
253
- commandManagerRef.current.context = context;
254
- }
255
- }), [canUndo, canRedo]); // Dépendances pour la mémorisation
256
-
257
- return (
258
- <CommandContext.Provider value={value}>{children}</CommandContext.Provider>
259
- );
1
+ import React, {createContext, useContext, useState, useCallback, useRef, useEffect, useMemo} from 'react';
2
+ import { useQueryClient } from 'react-query';
3
+ import { useNotificationContext } from '../NotificationProvider.jsx';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ const CommandContext = createContext({});
7
+
8
+ export const useCommand = () => useContext(CommandContext);
9
+
10
+ // --- Command Manager ---
11
+ class CommandManager {
12
+ constructor() {
13
+ this.history = [];
14
+ this.currentIndex = -1;
15
+ // Les dépendances seront injectées via updateDependencies
16
+ this.addNotification = () => {};
17
+ this.t = (key) => key;
18
+ this.onResetQueryClient = () => {};
19
+ this.queryClient = null; // Ajout pour stocker le queryClient
20
+ }
21
+
22
+ updateDependencies(addNotification, t, onResetQueryClient, queryClient) {
23
+ this.addNotification = addNotification;
24
+ this.t = t;
25
+ this.onResetQueryClient = onResetQueryClient;
26
+ this.queryClient = queryClient; // Injection du client
27
+ }
28
+
29
+ // La méthode execute est maintenant beaucoup plus simple.
30
+ // Elle n'appelle plus de fonction API, elle enregistre juste la commande.
31
+ add(command) {
32
+ try {
33
+ // Supprimer l'historique "redo" si on exécute une nouvelle commande
34
+ this.history = this.history.slice(0, this.currentIndex + 1);
35
+ this.history.push(command);
36
+ this.currentIndex++;
37
+ this.invalidateQueries(command.modelName, command.constructor.name);
38
+ } catch (e) {
39
+
40
+ }
41
+ }
42
+
43
+ async undo() {
44
+ if (this.canUndo()) {
45
+ try {
46
+ const command = this.history[this.currentIndex];
47
+ await command.undo();
48
+ this.currentIndex--;
49
+ await this.invalidateQueries(command.modelName, command.constructor.name + 'Undo');
50
+ this.addNotification({ title: this.t('command.success.undo', 'Action annulée'), status: 'completed' });
51
+ } catch (error) {
52
+ console.error("Command undo failed:", error);
53
+ this.addNotification({ title: this.t('command.error.undo', 'Erreur d\'annulation'), message: error.message, status: 'error' });
54
+ }
55
+ }
56
+ }
57
+
58
+ async redo() {
59
+ if (this.canRedo()) {
60
+ try {
61
+ this.currentIndex++;
62
+ const commandToRedo = this.history[this.currentIndex]; // Renommé pour plus de clarté
63
+ // Pour refaire, on exécute à nouveau l'action originale.
64
+ await commandToRedo.execute(this.context.apiCall); // *** CORRECTION: On passe la fonction apiCall ***
65
+ await this.invalidateQueries(commandToRedo.modelName, commandToRedo.constructor.name);
66
+ this.addNotification({ title: this.t('command.success.redo', 'Action rétablie'), status: 'completed' });
67
+ } catch (error) {
68
+ console.error("Command redo failed:", error);
69
+ this.addNotification({ title: this.t('command.error.redo', 'Erreur de rétablissement'), message: error.message, status: 'error' });
70
+ }
71
+ }
72
+ }
73
+
74
+ canUndo() {
75
+ return this.currentIndex >= 0;
76
+ }
77
+
78
+ canRedo() {
79
+ return this.currentIndex < this.history.length - 1;
80
+ }
81
+
82
+ async invalidateQueries(modelName, commandType) {
83
+ // Solution plus fine : on invalide seulement les requêtes concernées.
84
+ // React Query s'occupera de rafraîchir les données de manière optimisée.
85
+ if (this.queryClient && modelName) {
86
+ // Invalide toutes les requêtes liées à ce modèle (listes, paginations, etc.)
87
+ await this.queryClient.invalidateQueries(['api/data', modelName]);
88
+ }
89
+ }
90
+ }
91
+
92
+ // --- Command Definitions ---
93
+
94
+ export class InsertCommand {
95
+ constructor(modelName, apiCallParams) {
96
+ this.modelName = modelName;
97
+ this.apiCallParams = apiCallParams; // Stocke directement les paramètres
98
+ this.insertedItem = null; // On va stocker l'objet complet inséré
99
+ this.successMessage = "Donnée ajoutée";
100
+ }
101
+
102
+ // La méthode execute est maintenant utilisée uniquement pour le 'redo'.
103
+ // Elle doit refaire l'appel API initial.
104
+ async execute(apiCall) {
105
+ const redoVariables = {
106
+ apiCallParams: this.apiCallParams
107
+ };
108
+ const response = await apiCall(redoVariables);
109
+ if (!response.success) throw new Error(response.error || 'Redo (Insert) failed');
110
+ // On stocke l'objet complet retourné par l'API, qui inclut le nouvel _id.
111
+ // C'est important pour que le 'undo' suivant fonctionne.
112
+ this.insertedItem = response.data;
113
+ if (!this.insertedItem?._id) throw new Error('No inserted data returned from API');
114
+ }
115
+
116
+ async undo() {
117
+ // On garde une copie de l'item avant de le supprimer pour le redo.
118
+ if (!this.insertedItem?._id) throw new Error("Cannot undo insert: item ID is missing.");
119
+ const response = await fetch(`/api/data/${this.insertedItem._id}`, { method: 'DELETE' });
120
+ const result = await response.json();
121
+ if (!response.ok || !result.success) {
122
+ throw new Error(result.error || 'Undo (delete) failed');
123
+ }
124
+ }
125
+ }
126
+
127
+ export class UpdateCommand {
128
+ constructor(modelName, originalData, apiCallParams, apiCall) {
129
+ this.modelName = modelName;
130
+ this.originalData = Array.isArray(originalData) ? [...originalData] : [{ ...originalData }]; // Copie pour l'undo, s'assure que c'est un tableau
131
+ this.apiCallParams = apiCallParams;
132
+ this.apiCall = apiCall; // Stocke la fonction pour l'undo
133
+ this.recordIds = this.originalData.map(d => d._id);
134
+ this.successMessage = "Donnée mise à jour";
135
+ }
136
+
137
+ // La méthode execute est utilisée pour le 'redo'.
138
+ // Elle refait la mise à jour avec les nouvelles données.
139
+ async execute(apiCall) { // *** CORRECTION: Accepte apiCall en paramètre ***
140
+ const redoVariables = {
141
+ record: this.apiCallParams.record, // Le `record` est dans les params
142
+ apiCallParams: this.apiCallParams
143
+ };
144
+ const response = await (apiCall || this.apiCall)(redoVariables); // Utilise l'apiCall passée ou celle stockée
145
+ if (!response.success) throw new Error(response.error || 'Update failed');
146
+ }
147
+
148
+ async undo() {
149
+ // Pour annuler, on ré-applique les données originales pour chaque document
150
+ const undoPromises = this.originalData.map(doc => {
151
+ const undoVariables = {
152
+ record: doc, // Le document à restaurer
153
+ apiCallParams: { ...this.apiCallParams, formData: doc } // Les paramètres, en s'assurant que formData est bien le document original
154
+ };
155
+ return this.apiCall(undoVariables);
156
+ });
157
+ await Promise.all(undoPromises);
158
+ }
159
+ }
160
+
161
+ export class DeleteCommand {
162
+ constructor(apiCall, modelName, itemsToDelete) {
163
+ this.apiCall = apiCall; // *** CORRECTION: Stocker apiCall pour l'undo ***
164
+ this.modelName = modelName;
165
+ this.itemsToDelete = Array.isArray(itemsToDelete) ? [...itemsToDelete] : [itemsToDelete];
166
+ this.successMessage = "Donnée(s) supprimée(s)";
167
+ }
168
+
169
+ // La méthode execute est utilisée pour le 'redo'.
170
+ // Elle doit refaire la suppression.
171
+ async execute(apiCall) { // *** CORRECTION: Accepte apiCall en paramètre ***
172
+ // On utilise la fonction stockée dans le constructeur.
173
+ const response = await this.apiCall(this.itemsToDelete);
174
+ if (!response.success) throw new Error(response.error || 'Delete failed');
175
+ }
176
+
177
+ async undo() {
178
+ // Pour annuler, on ré-insère chaque document supprimé
179
+ // Note : cela crée de nouveaux _id, mais restaure les données.
180
+ const reinsertPromises = this.itemsToDelete.map(item => {
181
+ const reinsertData = { ...item };
182
+ delete reinsertData._id; // L'API doit générer un nouvel ID
183
+ delete reinsertData._hash;
184
+
185
+ return fetch('/api/data?_user=system', { // On ajoute _user=system pour tracer l'origine de l'action
186
+ method: 'POST',
187
+ headers: { 'Content-Type': 'application/json' },
188
+ body: JSON.stringify({ model: this.modelName, data: reinsertData }),
189
+ }).then(res => res.json().then(data => {
190
+ if (!res.ok || !data.success) {
191
+ throw new Error(data.error || `Undo (re-insert) failed for item ${item._id}.`);
192
+ }
193
+ // On retourne l'objet complet retourné par l'API, qui contient le nouvel _id
194
+ return data.data;
195
+ }));
196
+ });
197
+
198
+ // On attend que toutes les réinsertions soient terminées.
199
+ const reinsertedItems = await Promise.all(reinsertPromises);
200
+
201
+ // *** CORRECTION CRUCIALE ***
202
+ // On met à jour la liste des items de la commande avec les nouvelles données (et les nouveaux _id).
203
+ // Ainsi, si un "redo" est exécuté, il ciblera les bons documents à supprimer.
204
+ this.itemsToDelete = reinsertedItems;
205
+ }
206
+ }
207
+
208
+ // --- Singleton Command Manager ---
209
+ // On crée l'instance du manager EN DEHORS du composant React.
210
+ // Ainsi, elle ne sera pas détruite et recréée à chaque re-rendu de l'application,
211
+ // ce qui permet de conserver l'historique des commandes (undo/redo).
212
+ const commandManagerInstance = new CommandManager();
213
+
214
+ export const createInsertCommand = (modelName, apiCallParams) => new InsertCommand(modelName, apiCallParams);
215
+ export const createUpdateCommand = (modelName, record, apiCallParams, apiCall) => new UpdateCommand(modelName, record, apiCallParams, apiCall);
216
+ export const createDeleteCommand = (apiCall, modelName, itemsToDelete) => new DeleteCommand(apiCall, modelName, itemsToDelete);
217
+
218
+ // --- Provider Component ---
219
+ export const CommandProvider = ({ children, onResetQueryClient }) => {
220
+ const { addNotification } = useNotificationContext();
221
+ const { t, i18n } = useTranslation();
222
+ const queryClient = useQueryClient(); // On récupère le client ici
223
+ const lang = (i18n.resolvedLanguage || i18n.language).split(/[-_]/)?.[0];
224
+
225
+ // On utilise l'instance unique et on met à jour ses dépendances via useEffect
226
+ // pour s'assurer qu'elle a toujours les dernières fonctions (qui sont recréées à chaque rendu).
227
+ const commandManagerRef = useRef(commandManagerInstance);
228
+ useEffect(() => {
229
+ commandManagerInstance.updateDependencies(addNotification, t, onResetQueryClient, queryClient);
230
+ }, [addNotification, t, onResetQueryClient, queryClient]);
231
+
232
+ const [canUndo, setCanUndo] = useState(commandManagerRef.current.canUndo());
233
+ const [canRedo, setCanRedo] = useState(commandManagerRef.current.canRedo());
234
+
235
+ const updateUndoRedoState = () => {
236
+ setCanUndo(commandManagerRef.current.canUndo());
237
+ setCanRedo(commandManagerRef.current.canRedo());
238
+ };
239
+
240
+ // Renommée en 'addCommand' pour plus de clarté.
241
+ const addCommand = (command) => {
242
+ commandManagerRef.current.add(command);
243
+ updateUndoRedoState();
244
+ };
245
+
246
+ const undo = async () => {
247
+ await commandManagerRef.current.undo();
248
+ updateUndoRedoState();
249
+ };
250
+
251
+ const redo = async () => {
252
+ await commandManagerRef.current.redo();
253
+ updateUndoRedoState();
254
+ };
255
+ // --- CORRECTION ---
256
+ // On inclut `setManagerContext` directement dans la valeur du contexte
257
+ // et on mémorise l'objet avec `useMemo` pour la stabilité.
258
+ const value = useMemo(() => ({
259
+ addCommand, // (command)
260
+ undo,
261
+ redo,
262
+ canUndo, // boolean
263
+ canRedo, // boolean
264
+ createInsertCommand,
265
+ createUpdateCommand,
266
+ createDeleteCommand,
267
+ setManagerContext: (context) => {
268
+ commandManagerRef.current.context = context;
269
+ }
270
+ }), [canUndo, canRedo]); // Dépendances pour la mémorisation
271
+
272
+ return (
273
+ <CommandContext.Provider value={value}>{children}</CommandContext.Provider>
274
+ );
260
275
  };
@@ -1,30 +1,30 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- // https://vite.dev/config/
5
- export default defineConfig({
6
- plugins: [react()],
7
- base: "/",
8
- build: {
9
- outDir: "dist"
10
- },
11
- server : {
12
- proxy: {
13
- '/api': {
14
- target: 'http://localhost:7633',
15
- secure: false,
16
- changeOrigin: true,
17
- // Optionnel mais utile pour le débogage :
18
- // Affiche les requêtes proxy dans la console de Vite.
19
- configure: (proxy, options) => {
20
- proxy.on('proxyReq', (proxyReq, req, res) => {
21
- console.log(`[Vite Proxy] Forwarding request: ${req.method} ${req.url} -> ${options.target}${proxyReq.path}`);
22
- });
23
- }
24
- }
25
- }
26
- },
27
- fs: {
28
- allow: ["./src"]
29
- }
30
- })
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ base: "/",
8
+ build: {
9
+ outDir: "dist"
10
+ },
11
+ server : {
12
+ proxy: {
13
+ '/api': {
14
+ target: 'http://localhost:7633',
15
+ secure: false,
16
+ changeOrigin: true,
17
+ // Optionnel mais utile pour le débogage :
18
+ // Affiche les requêtes proxy dans la console de Vite.
19
+ configure: (proxy, options) => {
20
+ proxy.on('proxyReq', (proxyReq, req, res) => {
21
+ console.log(`[Vite Proxy] Forwarding request: ${req.method} ${req.url} -> ${options.target}${proxyReq.path}`);
22
+ });
23
+ }
24
+ }
25
+ }
26
+ },
27
+ fs: {
28
+ allow: ["./src", "../src"]
29
+ }
30
+ })