@osfarm/itineraire-technique 1.2.0 → 1.2.1
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.
- package/.github/copilot-instructions.md +56 -0
- package/.github/workflows/publish.yml +34 -0
- package/README.md +2 -34
- package/css/styles-editor.css +1 -1
- package/css/styles-editor.css.map +1 -1
- package/editor.html +38 -748
- package/js/chart-render.js +16 -11
- package/js/editor-interventions.js +315 -189
- package/js/editor-loader-default.js +238 -0
- package/js/editor-loader-itinera.js +135 -0
- package/js/{editor-wiki-editor.js → editor-loader-wiki.js} +99 -11
- package/js/editor-main.js +752 -0
- package/js/intervention.js +12 -0
- package/js/step-model.js +69 -0
- package/package.json +6 -59
- package/scss/styles-editor.scss +145 -0
- package/scss/styles-rendering.scss +184 -0
- package/examples/README.md +0 -137
- package/examples/nextjs-_document.tsx +0 -66
- package/examples/nextjs-api-route.ts +0 -122
- package/examples/nextjs-app-router-editor.tsx +0 -304
- package/examples/nextjs-app-router-viewer.tsx +0 -90
- package/js/editor-attributes.js +0 -99
- package/js/editor-crops.js +0 -136
- package/js/editor-export.js +0 -118
- package/react/QUICKSTART.md +0 -172
- package/react/README.md +0 -305
- package/react/TikaEditor.jsx +0 -212
- package/react/TikaRenderer.jsx +0 -116
- package/react/hooks.ts +0 -217
- package/react/index.ts +0 -19
- package/react/types.ts +0 -152
package/react/README.md
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
# Utilisation avec React et Next.js
|
|
2
|
-
|
|
3
|
-
Ce package peut être utilisé dans des applications React et Next.js. Voici comment l'intégrer.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @osfarm/itineraire-technique
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Dépendances à inclure
|
|
12
|
-
|
|
13
|
-
Les composants React dépendent de plusieurs bibliothèques externes qui doivent être chargées. Vous avez deux options :
|
|
14
|
-
|
|
15
|
-
### Option 1 : Via CDN (recommandé pour Next.js)
|
|
16
|
-
|
|
17
|
-
Dans votre `_document.tsx` ou `_app.tsx` (Next.js) ou dans votre `index.html` (React) :
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
// pages/_document.tsx (Next.js)
|
|
21
|
-
import { Html, Head, Main, NextScript } from 'next/document'
|
|
22
|
-
|
|
23
|
-
export default function Document() {
|
|
24
|
-
return (
|
|
25
|
-
<Html>
|
|
26
|
-
<Head>
|
|
27
|
-
{/* ECharts */}
|
|
28
|
-
<script src="https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.js"></script>
|
|
29
|
-
|
|
30
|
-
{/* jQuery */}
|
|
31
|
-
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
|
32
|
-
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1.14.1/dist/jquery-ui.min.js"></script>
|
|
33
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-ui@1.14.1/themes/base/jquery-ui.css" />
|
|
34
|
-
|
|
35
|
-
{/* Underscore */}
|
|
36
|
-
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.7/underscore-umd-min.js"></script>
|
|
37
|
-
|
|
38
|
-
{/* Bootstrap (pour l'éditeur) */}
|
|
39
|
-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
|
|
40
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
41
|
-
|
|
42
|
-
{/* Font Awesome */}
|
|
43
|
-
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet" />
|
|
44
|
-
|
|
45
|
-
{/* Scripts TIKA */}
|
|
46
|
-
<script src="/chart-render.js"></script>
|
|
47
|
-
<script src="/editor-attributes.js"></script>
|
|
48
|
-
<script src="/editor-interventions.js"></script>
|
|
49
|
-
<script src="/editor-crops.js"></script>
|
|
50
|
-
<script src="/editor-export.js"></script>
|
|
51
|
-
<script src="/editor-wiki-editor.js"></script>
|
|
52
|
-
|
|
53
|
-
{/* Styles TIKA */}
|
|
54
|
-
<link href="/styles-rendering.css" rel="stylesheet" />
|
|
55
|
-
<link href="/styles-editor.css" rel="stylesheet" />
|
|
56
|
-
</Head>
|
|
57
|
-
<body>
|
|
58
|
-
<Main />
|
|
59
|
-
<NextScript />
|
|
60
|
-
</body>
|
|
61
|
-
</Html>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Option 2 : Via NPM
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
npm install echarts jquery jquery-ui underscore bootstrap
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Puis importez-les dans votre application.
|
|
73
|
-
|
|
74
|
-
## Copier les fichiers statiques
|
|
75
|
-
|
|
76
|
-
Copiez les fichiers JS et CSS depuis `node_modules/@osfarm/itineraire-technique/` vers votre dossier `public/` :
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# Créer les dossiers
|
|
80
|
-
mkdir -p public/js public/css
|
|
81
|
-
|
|
82
|
-
# Copier les fichiers JS
|
|
83
|
-
cp node_modules/@osfarm/itineraire-technique/js/*.js public/
|
|
84
|
-
|
|
85
|
-
# Copier les fichiers CSS
|
|
86
|
-
cp node_modules/@osfarm/itineraire-technique/css/*.css public/
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Utilisation du composant de visualisation
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
'use client'; // Pour Next.js App Router
|
|
93
|
-
|
|
94
|
-
import { TikaRenderer } from '@osfarm/itineraire-technique/react';
|
|
95
|
-
import { useEffect, useState } from 'react';
|
|
96
|
-
|
|
97
|
-
export default function ItinerairePage() {
|
|
98
|
-
const [data, setData] = useState(null);
|
|
99
|
-
const [loading, setLoading] = useState(true);
|
|
100
|
-
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
// Charger vos données depuis une API ou un fichier
|
|
103
|
-
fetch('/api/itineraire')
|
|
104
|
-
.then(res => res.json())
|
|
105
|
-
.then(data => {
|
|
106
|
-
setData(data);
|
|
107
|
-
setLoading(false);
|
|
108
|
-
});
|
|
109
|
-
}, []);
|
|
110
|
-
|
|
111
|
-
if (loading) return <div>Chargement...</div>;
|
|
112
|
-
if (!data) return <div>Aucune donnée</div>;
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
<div className="container">
|
|
116
|
-
<h1>Itinéraire Technique</h1>
|
|
117
|
-
<TikaRenderer
|
|
118
|
-
data={data}
|
|
119
|
-
width="100%"
|
|
120
|
-
height="600px"
|
|
121
|
-
onItemClick={(itemId, event) => {
|
|
122
|
-
console.log('Item clicked:', itemId);
|
|
123
|
-
}}
|
|
124
|
-
/>
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Utilisation du composant éditeur
|
|
131
|
-
|
|
132
|
-
```tsx
|
|
133
|
-
'use client';
|
|
134
|
-
|
|
135
|
-
import { TikaEditor } from '@osfarm/itineraire-technique/react';
|
|
136
|
-
import { useState } from 'react';
|
|
137
|
-
|
|
138
|
-
export default function EditorPage() {
|
|
139
|
-
const [data, setData] = useState({
|
|
140
|
-
title: "Ma rotation",
|
|
141
|
-
options: {
|
|
142
|
-
view: "horizontal",
|
|
143
|
-
show_transcript: true,
|
|
144
|
-
title_top_interventions: "Cultures principales",
|
|
145
|
-
title_bottom_interventions: "Couverts",
|
|
146
|
-
title_steps: "Rotation",
|
|
147
|
-
region: "France"
|
|
148
|
-
},
|
|
149
|
-
steps: []
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
const handleSave = (newData) => {
|
|
153
|
-
console.log('Données sauvegardées:', newData);
|
|
154
|
-
setData(newData);
|
|
155
|
-
|
|
156
|
-
// Envoyer à votre API
|
|
157
|
-
fetch('/api/itineraire', {
|
|
158
|
-
method: 'POST',
|
|
159
|
-
headers: { 'Content-Type': 'application/json' },
|
|
160
|
-
body: JSON.stringify(newData)
|
|
161
|
-
});
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const handleExport = (data) => {
|
|
165
|
-
// Télécharger le JSON
|
|
166
|
-
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
167
|
-
const url = URL.createObjectURL(blob);
|
|
168
|
-
const a = document.createElement('a');
|
|
169
|
-
a.href = url;
|
|
170
|
-
a.download = 'itineraire.json';
|
|
171
|
-
a.click();
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
return (
|
|
175
|
-
<div className="container">
|
|
176
|
-
<h1>Éditeur d'Itinéraire Technique</h1>
|
|
177
|
-
<TikaEditor
|
|
178
|
-
initialData={data}
|
|
179
|
-
onSave={handleSave}
|
|
180
|
-
onExport={handleExport}
|
|
181
|
-
enableAutoSave={true}
|
|
182
|
-
autoSaveInterval={10000}
|
|
183
|
-
/>
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## Utilisation avec le hook personnalisé
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
'use client';
|
|
193
|
-
|
|
194
|
-
import { useItineraire } from '@osfarm/itineraire-technique/react';
|
|
195
|
-
import { TikaRenderer } from '@osfarm/itineraire-technique/react';
|
|
196
|
-
|
|
197
|
-
export default function MyComponent() {
|
|
198
|
-
const {
|
|
199
|
-
data,
|
|
200
|
-
loading,
|
|
201
|
-
error,
|
|
202
|
-
addStep,
|
|
203
|
-
updateStep,
|
|
204
|
-
deleteStep,
|
|
205
|
-
exportToJson
|
|
206
|
-
} = useItineraire(initialData);
|
|
207
|
-
|
|
208
|
-
const handleAddStep = () => {
|
|
209
|
-
const newStep = {
|
|
210
|
-
id: crypto.randomUUID(),
|
|
211
|
-
name: 'Nouvelle culture',
|
|
212
|
-
startDate: new Date().toISOString(),
|
|
213
|
-
endDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(),
|
|
214
|
-
color: '#4CAF50',
|
|
215
|
-
interventions: []
|
|
216
|
-
};
|
|
217
|
-
addStep(newStep);
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
if (loading) return <div>Chargement...</div>;
|
|
221
|
-
if (error) return <div>Erreur: {error.message}</div>;
|
|
222
|
-
if (!data) return <div>Aucune donnée</div>;
|
|
223
|
-
|
|
224
|
-
return (
|
|
225
|
-
<div>
|
|
226
|
-
<button onClick={handleAddStep}>Ajouter une étape</button>
|
|
227
|
-
<button onClick={() => console.log(exportToJson())}>Exporter JSON</button>
|
|
228
|
-
<TikaRenderer data={data} />
|
|
229
|
-
</div>
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## TypeScript
|
|
235
|
-
|
|
236
|
-
Les types TypeScript sont inclus. Importez-les depuis le package :
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
import type {
|
|
240
|
-
ItineraireData,
|
|
241
|
-
Step,
|
|
242
|
-
Intervention
|
|
243
|
-
} from '@osfarm/itineraire-technique/react';
|
|
244
|
-
|
|
245
|
-
const myData: ItineraireData = {
|
|
246
|
-
title: "Ma rotation",
|
|
247
|
-
options: {
|
|
248
|
-
view: "horizontal",
|
|
249
|
-
show_transcript: true
|
|
250
|
-
},
|
|
251
|
-
steps: []
|
|
252
|
-
};
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## Configuration Next.js
|
|
256
|
-
|
|
257
|
-
Si vous utilisez Next.js 13+ avec App Router, assurez-vous que vos composants sont marqués avec `'use client'` car ils utilisent des hooks React et accèdent au DOM.
|
|
258
|
-
|
|
259
|
-
### next.config.js
|
|
260
|
-
|
|
261
|
-
```javascript
|
|
262
|
-
/** @type {import('next').NextConfig} */
|
|
263
|
-
const nextConfig = {
|
|
264
|
-
// Permettre les scripts externes
|
|
265
|
-
experimental: {
|
|
266
|
-
externalDir: true
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
module.exports = nextConfig
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
## Exemples complets
|
|
274
|
-
|
|
275
|
-
Consultez le dossier `examples/` pour des exemples complets d'intégration avec :
|
|
276
|
-
- Next.js App Router
|
|
277
|
-
- Next.js Pages Router
|
|
278
|
-
- Create React App
|
|
279
|
-
- Vite + React
|
|
280
|
-
|
|
281
|
-
## Troubleshooting
|
|
282
|
-
|
|
283
|
-
### "RotationRenderer is not defined"
|
|
284
|
-
|
|
285
|
-
Assurez-vous que `chart-render.js` est chargé avant le rendu de votre composant. Utilisez `useItineraireDependencies` pour vérifier :
|
|
286
|
-
|
|
287
|
-
```tsx
|
|
288
|
-
import { useItineraireDependencies } from '@osfarm/itineraire-technique/react';
|
|
289
|
-
|
|
290
|
-
function MyComponent() {
|
|
291
|
-
const { loaded, error } = useItineraireDependencies();
|
|
292
|
-
|
|
293
|
-
if (!loaded) return <div>Chargement des dépendances...</div>;
|
|
294
|
-
if (error) return <div>Erreur: {error.message}</div>;
|
|
295
|
-
|
|
296
|
-
return <TikaRenderer data={data} />;
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Problèmes de styles
|
|
301
|
-
|
|
302
|
-
Assurez-vous que les fichiers CSS sont bien importés :
|
|
303
|
-
- `styles-rendering.css` pour le visualiseur
|
|
304
|
-
- `styles-editor.css` pour l'éditeur
|
|
305
|
-
- Bootstrap pour l'interface de l'éditeur
|
package/react/TikaEditor.jsx
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TikaEditor - Composant React pour éditer un itinéraire technique
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* import TikaEditor from '@osfarm/itineraire-technique/react/TikaEditor';
|
|
6
|
-
*
|
|
7
|
-
* function MyComponent() {
|
|
8
|
-
* const [data, setData] = useState(initialData);
|
|
9
|
-
*
|
|
10
|
-
* const handleSave = (newData) => {
|
|
11
|
-
* console.log('Data saved:', newData);
|
|
12
|
-
* setData(newData);
|
|
13
|
-
* };
|
|
14
|
-
*
|
|
15
|
-
* return <TikaEditor initialData={data} onSave={handleSave} />;
|
|
16
|
-
* }
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
20
|
-
|
|
21
|
-
const TikaEditor = ({
|
|
22
|
-
initialData = null,
|
|
23
|
-
onSave = null,
|
|
24
|
-
onExport = null,
|
|
25
|
-
className = '',
|
|
26
|
-
showWikiButtons = false,
|
|
27
|
-
enableAutoSave = false,
|
|
28
|
-
autoSaveInterval = 5000
|
|
29
|
-
}) => {
|
|
30
|
-
const containerRef = useRef(null);
|
|
31
|
-
const editorInitialized = useRef(false);
|
|
32
|
-
const autoSaveTimer = useRef(null);
|
|
33
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
34
|
-
const [currentData, setCurrentData] = useState(initialData);
|
|
35
|
-
|
|
36
|
-
// Fonction pour récupérer les données actuelles de l'éditeur
|
|
37
|
-
const getCurrentData = () => {
|
|
38
|
-
if (typeof window === 'undefined' || !window.rotation_data) return null;
|
|
39
|
-
return JSON.parse(JSON.stringify(window.rotation_data));
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Fonction pour sauvegarder
|
|
43
|
-
const handleSave = () => {
|
|
44
|
-
const data = getCurrentData();
|
|
45
|
-
if (data && onSave) {
|
|
46
|
-
onSave(data);
|
|
47
|
-
setCurrentData(data);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Fonction pour exporter
|
|
52
|
-
const handleExport = () => {
|
|
53
|
-
const data = getCurrentData();
|
|
54
|
-
if (data && onExport) {
|
|
55
|
-
onExport(data);
|
|
56
|
-
} else if (data && window.exportToJsonFile) {
|
|
57
|
-
// Utiliser la fonction d'export native si pas de callback personnalisé
|
|
58
|
-
window.exportToJsonFile(data);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// Auto-save
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (enableAutoSave && onSave) {
|
|
65
|
-
autoSaveTimer.current = setInterval(() => {
|
|
66
|
-
handleSave();
|
|
67
|
-
}, autoSaveInterval);
|
|
68
|
-
|
|
69
|
-
return () => {
|
|
70
|
-
if (autoSaveTimer.current) {
|
|
71
|
-
clearInterval(autoSaveTimer.current);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}, [enableAutoSave, autoSaveInterval, onSave]);
|
|
76
|
-
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
if (typeof window === 'undefined') return;
|
|
79
|
-
|
|
80
|
-
// Vérifier les dépendances
|
|
81
|
-
const checkDependencies = () => {
|
|
82
|
-
const missing = [];
|
|
83
|
-
if (!window.$) missing.push('jQuery');
|
|
84
|
-
if (!window.echarts) missing.push('ECharts');
|
|
85
|
-
if (!window._) missing.push('Underscore');
|
|
86
|
-
if (!window.RotationRenderer) missing.push('chart-render.js');
|
|
87
|
-
|
|
88
|
-
// Vérifier les fonctions de l'éditeur
|
|
89
|
-
if (!window.refreshAttributesTable) missing.push('editor-attributes.js');
|
|
90
|
-
if (!window.refreshStepsButtonList) missing.push('editor-crops.js');
|
|
91
|
-
if (!window.exportToJsonFile) missing.push('editor-export.js');
|
|
92
|
-
if (!window.refreshInterventionsList) missing.push('editor-interventions.js');
|
|
93
|
-
|
|
94
|
-
return missing;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const missingDeps = checkDependencies();
|
|
98
|
-
if (missingDeps.length > 0) {
|
|
99
|
-
console.error('Missing dependencies for TikaEditor:', missingDeps.join(', '));
|
|
100
|
-
setIsLoading(false);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Initialiser l'éditeur seulement une fois
|
|
105
|
-
if (!editorInitialized.current && containerRef.current) {
|
|
106
|
-
editorInitialized.current = true;
|
|
107
|
-
|
|
108
|
-
// Initialiser la structure globale de données si nécessaire
|
|
109
|
-
if (!window.rotation_data) {
|
|
110
|
-
window.rotation_data = initialData || {
|
|
111
|
-
title: "Nouvel itinéraire",
|
|
112
|
-
options: {
|
|
113
|
-
view: "horizontal",
|
|
114
|
-
show_transcript: true,
|
|
115
|
-
title_top_interventions: "Cultures principales",
|
|
116
|
-
title_bottom_interventions: "Couverts et CIVE",
|
|
117
|
-
title_steps: "Rotation",
|
|
118
|
-
region: "France",
|
|
119
|
-
show_climate_diagram: false
|
|
120
|
-
},
|
|
121
|
-
steps: []
|
|
122
|
-
};
|
|
123
|
-
} else if (initialData) {
|
|
124
|
-
window.rotation_data = initialData;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Appeler les fonctions d'initialisation de l'éditeur
|
|
128
|
-
try {
|
|
129
|
-
if (window.refreshAttributesTable) window.refreshAttributesTable();
|
|
130
|
-
if (window.refreshStepsButtonList) window.refreshStepsButtonList();
|
|
131
|
-
if (window.refreshInterventionsList) window.refreshInterventionsList();
|
|
132
|
-
|
|
133
|
-
// Rendre le graphique initial
|
|
134
|
-
if (window.renderChart) {
|
|
135
|
-
window.renderChart();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
setIsLoading(false);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
console.error('Error initializing editor:', error);
|
|
141
|
-
setIsLoading(false);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Exposer les fonctions de save/export via window pour que le HTML interne puisse les appeler
|
|
146
|
-
window.reactEditorSave = handleSave;
|
|
147
|
-
window.reactEditorExport = handleExport;
|
|
148
|
-
|
|
149
|
-
}, [initialData]);
|
|
150
|
-
|
|
151
|
-
// Mettre à jour les données si initialData change
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
if (initialData && window.rotation_data) {
|
|
154
|
-
window.rotation_data = initialData;
|
|
155
|
-
if (window.refreshAttributesTable) window.refreshAttributesTable();
|
|
156
|
-
if (window.refreshStepsButtonList) window.refreshStepsButtonList();
|
|
157
|
-
if (window.refreshInterventionsList) window.refreshInterventionsList();
|
|
158
|
-
if (window.renderChart) window.renderChart();
|
|
159
|
-
}
|
|
160
|
-
}, [initialData]);
|
|
161
|
-
|
|
162
|
-
if (isLoading) {
|
|
163
|
-
return (
|
|
164
|
-
<div className={`itineraire-editor-loading ${className}`}>
|
|
165
|
-
<div className="spinner-border" role="status">
|
|
166
|
-
<span className="visually-hidden">Chargement...</span>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
<div ref={containerRef} className={`itineraire-editor ${className}`}>
|
|
174
|
-
{/* Boutons de contrôle React */}
|
|
175
|
-
<div className="react-editor-controls mb-3">
|
|
176
|
-
<div className="btn-group" role="group">
|
|
177
|
-
{onSave && (
|
|
178
|
-
<button
|
|
179
|
-
type="button"
|
|
180
|
-
className="btn btn-primary"
|
|
181
|
-
onClick={handleSave}
|
|
182
|
-
>
|
|
183
|
-
<i className="fa fa-save"></i> Enregistrer
|
|
184
|
-
</button>
|
|
185
|
-
)}
|
|
186
|
-
{onExport && (
|
|
187
|
-
<button
|
|
188
|
-
type="button"
|
|
189
|
-
className="btn btn-outline-primary"
|
|
190
|
-
onClick={handleExport}
|
|
191
|
-
>
|
|
192
|
-
<i className="fa fa-download"></i> Exporter JSON
|
|
193
|
-
</button>
|
|
194
|
-
)}
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
{/* Le contenu HTML de l'éditeur sera injecté ici via un portail ou iframe */}
|
|
199
|
-
{/* Pour l'instant, on délègue au HTML existant */}
|
|
200
|
-
<div id="editor-content-container">
|
|
201
|
-
{/* L'éditeur HTML existant sera chargé ici */}
|
|
202
|
-
<iframe
|
|
203
|
-
src="/editor.html"
|
|
204
|
-
style={{ width: '100%', height: '800px', border: 'none' }}
|
|
205
|
-
title="Éditeur d'itinéraire technique"
|
|
206
|
-
/>
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
export default TikaEditor;
|
package/react/TikaRenderer.jsx
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TikaRenderer - Composant React pour visualiser un itinéraire technique
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* import TikaRenderer from '@osfarm/itineraire-technique/react/TikaRenderer';
|
|
6
|
-
*
|
|
7
|
-
* function MyComponent() {
|
|
8
|
-
* const data = { ... }; // Données JSON de l'itinéraire
|
|
9
|
-
* return <TikaRenderer data={data} />;
|
|
10
|
-
* }
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import React, { useEffect, useRef } from 'react';
|
|
14
|
-
|
|
15
|
-
const TikaRenderer = ({
|
|
16
|
-
data,
|
|
17
|
-
width = '100%',
|
|
18
|
-
height = 'auto',
|
|
19
|
-
className = '',
|
|
20
|
-
onItemClick = null,
|
|
21
|
-
onItemHover = null
|
|
22
|
-
}) => {
|
|
23
|
-
const containerRef = useRef(null);
|
|
24
|
-
const rendererRef = useRef(null);
|
|
25
|
-
const divId = useRef(`itk-${Math.random().toString(36).substr(2, 9)}`);
|
|
26
|
-
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
// Vérifier que les dépendances sont chargées
|
|
29
|
-
if (typeof window === 'undefined') return;
|
|
30
|
-
|
|
31
|
-
if (!window.RotationRenderer) {
|
|
32
|
-
console.error('RotationRenderer not loaded. Make sure chart-render.js is included.');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!window.echarts) {
|
|
37
|
-
console.error('ECharts not loaded. Make sure ECharts is included.');
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!window.$) {
|
|
42
|
-
console.error('jQuery not loaded. Make sure jQuery is included.');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Créer le conteneur si nécessaire
|
|
47
|
-
if (containerRef.current && !containerRef.current.querySelector('.mainITKContainer')) {
|
|
48
|
-
// Initialiser le renderer
|
|
49
|
-
try {
|
|
50
|
-
rendererRef.current = new window.RotationRenderer(divId.current, data);
|
|
51
|
-
rendererRef.current.render();
|
|
52
|
-
|
|
53
|
-
// Attacher les événements personnalisés si fournis
|
|
54
|
-
if (onItemClick) {
|
|
55
|
-
containerRef.current.addEventListener('click', (e) => {
|
|
56
|
-
const item = e.target.closest('.rotation_item');
|
|
57
|
-
if (item) {
|
|
58
|
-
const itemId = item.dataset.id || item.id;
|
|
59
|
-
onItemClick(itemId, e);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (onItemHover) {
|
|
65
|
-
containerRef.current.addEventListener('mouseover', (e) => {
|
|
66
|
-
const item = e.target.closest('.rotation_item');
|
|
67
|
-
if (item) {
|
|
68
|
-
const itemId = item.dataset.id || item.id;
|
|
69
|
-
onItemHover(itemId, e);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error('Error initializing RotationRenderer:', error);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Cleanup
|
|
79
|
-
return () => {
|
|
80
|
-
if (rendererRef.current && rendererRef.current.chart) {
|
|
81
|
-
try {
|
|
82
|
-
rendererRef.current.chart.dispose();
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.error('Error disposing chart:', error);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
}, [data, onItemClick, onItemHover]);
|
|
89
|
-
|
|
90
|
-
// Réagir aux changements de données
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (rendererRef.current && data) {
|
|
93
|
-
try {
|
|
94
|
-
// Recréer le renderer avec les nouvelles données
|
|
95
|
-
if (rendererRef.current.chart) {
|
|
96
|
-
rendererRef.current.chart.dispose();
|
|
97
|
-
}
|
|
98
|
-
rendererRef.current = new window.RotationRenderer(divId.current, data);
|
|
99
|
-
rendererRef.current.render();
|
|
100
|
-
} catch (error) {
|
|
101
|
-
console.error('Error updating chart data:', error);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}, [data]);
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<div
|
|
108
|
-
ref={containerRef}
|
|
109
|
-
id={divId.current}
|
|
110
|
-
className={`itineraire-renderer ${className}`}
|
|
111
|
-
style={{ width, height }}
|
|
112
|
-
/>
|
|
113
|
-
);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
export default TikaRenderer;
|