@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/hooks.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook React personnalisé pour gérer les données d'itinéraire technique
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { useState, useCallback, useEffect } from 'react';
|
|
6
|
-
import type { ItineraireData, Step, Intervention } from './types';
|
|
7
|
-
|
|
8
|
-
export interface UseItineraireResult {
|
|
9
|
-
data: ItineraireData | null;
|
|
10
|
-
loading: boolean;
|
|
11
|
-
error: Error | null;
|
|
12
|
-
updateData: (newData: ItineraireData) => void;
|
|
13
|
-
addStep: (step: Step) => void;
|
|
14
|
-
updateStep: (stepId: string, updates: Partial<Step>) => void;
|
|
15
|
-
deleteStep: (stepId: string) => void;
|
|
16
|
-
addIntervention: (stepId: string, intervention: Intervention) => void;
|
|
17
|
-
updateIntervention: (stepId: string, interventionId: string, updates: Partial<Intervention>) => void;
|
|
18
|
-
deleteIntervention: (stepId: string, interventionId: string) => void;
|
|
19
|
-
exportToJson: () => string;
|
|
20
|
-
importFromJson: (jsonString: string) => void;
|
|
21
|
-
reset: () => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Hook pour gérer les données d'itinéraire technique
|
|
26
|
-
* @param initialData Données initiales
|
|
27
|
-
* @param onUpdate Callback appelé à chaque modification
|
|
28
|
-
*/
|
|
29
|
-
export const useItineraire = (
|
|
30
|
-
initialData: ItineraireData | null = null,
|
|
31
|
-
onUpdate?: (data: ItineraireData) => void
|
|
32
|
-
): UseItineraireResult => {
|
|
33
|
-
const [data, setData] = useState<ItineraireData | null>(initialData);
|
|
34
|
-
const [loading, setLoading] = useState(false);
|
|
35
|
-
const [error, setError] = useState<Error | null>(null);
|
|
36
|
-
|
|
37
|
-
// Appeler onUpdate quand les données changent
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (data && onUpdate) {
|
|
40
|
-
onUpdate(data);
|
|
41
|
-
}
|
|
42
|
-
}, [data, onUpdate]);
|
|
43
|
-
|
|
44
|
-
const updateData = useCallback((newData: ItineraireData) => {
|
|
45
|
-
setData(newData);
|
|
46
|
-
setError(null);
|
|
47
|
-
}, []);
|
|
48
|
-
|
|
49
|
-
const addStep = useCallback((step: Step) => {
|
|
50
|
-
setData((prevData) => {
|
|
51
|
-
if (!prevData) return prevData;
|
|
52
|
-
return {
|
|
53
|
-
...prevData,
|
|
54
|
-
steps: [...prevData.steps, step]
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
}, []);
|
|
58
|
-
|
|
59
|
-
const updateStep = useCallback((stepId: string, updates: Partial<Step>) => {
|
|
60
|
-
setData((prevData) => {
|
|
61
|
-
if (!prevData) return prevData;
|
|
62
|
-
return {
|
|
63
|
-
...prevData,
|
|
64
|
-
steps: prevData.steps.map((step) =>
|
|
65
|
-
step.id === stepId ? { ...step, ...updates } : step
|
|
66
|
-
)
|
|
67
|
-
};
|
|
68
|
-
});
|
|
69
|
-
}, []);
|
|
70
|
-
|
|
71
|
-
const deleteStep = useCallback((stepId: string) => {
|
|
72
|
-
setData((prevData) => {
|
|
73
|
-
if (!prevData) return prevData;
|
|
74
|
-
return {
|
|
75
|
-
...prevData,
|
|
76
|
-
steps: prevData.steps.filter((step) => step.id !== stepId)
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
}, []);
|
|
80
|
-
|
|
81
|
-
const addIntervention = useCallback((stepId: string, intervention: Intervention) => {
|
|
82
|
-
setData((prevData) => {
|
|
83
|
-
if (!prevData) return prevData;
|
|
84
|
-
return {
|
|
85
|
-
...prevData,
|
|
86
|
-
steps: prevData.steps.map((step) =>
|
|
87
|
-
step.id === stepId
|
|
88
|
-
? {
|
|
89
|
-
...step,
|
|
90
|
-
interventions: [...(step.interventions || []), intervention]
|
|
91
|
-
}
|
|
92
|
-
: step
|
|
93
|
-
)
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
}, []);
|
|
97
|
-
|
|
98
|
-
const updateIntervention = useCallback(
|
|
99
|
-
(stepId: string, interventionId: string, updates: Partial<Intervention>) => {
|
|
100
|
-
setData((prevData) => {
|
|
101
|
-
if (!prevData) return prevData;
|
|
102
|
-
return {
|
|
103
|
-
...prevData,
|
|
104
|
-
steps: prevData.steps.map((step) =>
|
|
105
|
-
step.id === stepId
|
|
106
|
-
? {
|
|
107
|
-
...step,
|
|
108
|
-
interventions: (step.interventions || []).map((intervention) =>
|
|
109
|
-
intervention.id === interventionId
|
|
110
|
-
? { ...intervention, ...updates }
|
|
111
|
-
: intervention
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
: step
|
|
115
|
-
)
|
|
116
|
-
};
|
|
117
|
-
});
|
|
118
|
-
},
|
|
119
|
-
[]
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
const deleteIntervention = useCallback((stepId: string, interventionId: string) => {
|
|
123
|
-
setData((prevData) => {
|
|
124
|
-
if (!prevData) return prevData;
|
|
125
|
-
return {
|
|
126
|
-
...prevData,
|
|
127
|
-
steps: prevData.steps.map((step) =>
|
|
128
|
-
step.id === stepId
|
|
129
|
-
? {
|
|
130
|
-
...step,
|
|
131
|
-
interventions: (step.interventions || []).filter(
|
|
132
|
-
(intervention) => intervention.id !== interventionId
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
: step
|
|
136
|
-
)
|
|
137
|
-
};
|
|
138
|
-
});
|
|
139
|
-
}, []);
|
|
140
|
-
|
|
141
|
-
const exportToJson = useCallback(() => {
|
|
142
|
-
if (!data) return '{}';
|
|
143
|
-
return JSON.stringify(data, null, 2);
|
|
144
|
-
}, [data]);
|
|
145
|
-
|
|
146
|
-
const importFromJson = useCallback((jsonString: string) => {
|
|
147
|
-
try {
|
|
148
|
-
setLoading(true);
|
|
149
|
-
const parsed = JSON.parse(jsonString);
|
|
150
|
-
setData(parsed);
|
|
151
|
-
setError(null);
|
|
152
|
-
} catch (err) {
|
|
153
|
-
setError(err instanceof Error ? err : new Error('Invalid JSON'));
|
|
154
|
-
} finally {
|
|
155
|
-
setLoading(false);
|
|
156
|
-
}
|
|
157
|
-
}, []);
|
|
158
|
-
|
|
159
|
-
const reset = useCallback(() => {
|
|
160
|
-
setData(initialData);
|
|
161
|
-
setError(null);
|
|
162
|
-
}, [initialData]);
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
data,
|
|
166
|
-
loading,
|
|
167
|
-
error,
|
|
168
|
-
updateData,
|
|
169
|
-
addStep,
|
|
170
|
-
updateStep,
|
|
171
|
-
deleteStep,
|
|
172
|
-
addIntervention,
|
|
173
|
-
updateIntervention,
|
|
174
|
-
deleteIntervention,
|
|
175
|
-
exportToJson,
|
|
176
|
-
importFromJson,
|
|
177
|
-
reset
|
|
178
|
-
};
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Hook pour charger les dépendances nécessaires (ECharts, jQuery, etc.)
|
|
183
|
-
*/
|
|
184
|
-
export const useItineraireDependencies = () => {
|
|
185
|
-
const [loaded, setLoaded] = useState(false);
|
|
186
|
-
const [error, setError] = useState<Error | null>(null);
|
|
187
|
-
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
if (typeof window === 'undefined') return;
|
|
190
|
-
|
|
191
|
-
const checkDependencies = () => {
|
|
192
|
-
const hasEcharts = !!window.echarts;
|
|
193
|
-
const hasJQuery = !!window.$;
|
|
194
|
-
const hasUnderscore = !!window._;
|
|
195
|
-
const hasRotationRenderer = !!window.RotationRenderer;
|
|
196
|
-
|
|
197
|
-
return hasEcharts && hasJQuery && hasUnderscore && hasRotationRenderer;
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
if (checkDependencies()) {
|
|
201
|
-
setLoaded(true);
|
|
202
|
-
} else {
|
|
203
|
-
// Attendre un peu que les scripts se chargent
|
|
204
|
-
const timeout = setTimeout(() => {
|
|
205
|
-
if (checkDependencies()) {
|
|
206
|
-
setLoaded(true);
|
|
207
|
-
} else {
|
|
208
|
-
setError(new Error('Required dependencies not loaded'));
|
|
209
|
-
}
|
|
210
|
-
}, 1000);
|
|
211
|
-
|
|
212
|
-
return () => clearTimeout(timeout);
|
|
213
|
-
}
|
|
214
|
-
}, []);
|
|
215
|
-
|
|
216
|
-
return { loaded, error };
|
|
217
|
-
};
|
package/react/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Point d'entrée principal pour les composants React
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { default as TikaRenderer } from './TikaRenderer';
|
|
6
|
-
export { default as TikaEditor } from './TikaEditor';
|
|
7
|
-
export { useItineraire, useItineraireDependencies } from './hooks';
|
|
8
|
-
export type {
|
|
9
|
-
ItineraireData,
|
|
10
|
-
ItineraireOptions,
|
|
11
|
-
Step,
|
|
12
|
-
Intervention,
|
|
13
|
-
ClimateData,
|
|
14
|
-
RotationData,
|
|
15
|
-
TimelineData,
|
|
16
|
-
TikaRendererProps,
|
|
17
|
-
TikaEditorProps,
|
|
18
|
-
IRotationRenderer
|
|
19
|
-
} from './types';
|
package/react/types.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Types TypeScript pour les données d'itinéraire technique TIKA
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface ClimateData {
|
|
6
|
-
/** Températures moyennes mensuelles (12 valeurs, en °C) */
|
|
7
|
-
temperatures: number[];
|
|
8
|
-
/** Précipitations moyennes mensuelles (12 valeurs, en mm) */
|
|
9
|
-
precipitations: number[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ItineraireOptions {
|
|
13
|
-
/** Type de vue: 'horizontal', 'vertical', ou 'donut' */
|
|
14
|
-
view?: 'horizontal' | 'vertical' | 'donut';
|
|
15
|
-
/** Afficher la transcription textuelle */
|
|
16
|
-
show_transcript?: boolean;
|
|
17
|
-
/** Titre pour les interventions supérieures */
|
|
18
|
-
title_top_interventions?: string;
|
|
19
|
-
/** Titre pour les interventions inférieures */
|
|
20
|
-
title_bottom_interventions?: string;
|
|
21
|
-
/** Titre pour les étapes */
|
|
22
|
-
title_steps?: string;
|
|
23
|
-
/** Région géographique */
|
|
24
|
-
region?: string;
|
|
25
|
-
/** Afficher le diagramme climatique */
|
|
26
|
-
show_climate_diagram?: boolean;
|
|
27
|
-
/** Données climatiques */
|
|
28
|
-
climate_data?: ClimateData;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface Intervention {
|
|
32
|
-
/** Identifiant unique de l'intervention */
|
|
33
|
-
id: string;
|
|
34
|
-
/** Jour relatif au début de l'étape (peut être négatif pour avant) */
|
|
35
|
-
day: string | number;
|
|
36
|
-
/** Nom de l'intervention */
|
|
37
|
-
name: string;
|
|
38
|
-
/** Type d'intervention: 'intervention_top' ou 'intervention_bottom' */
|
|
39
|
-
type: 'intervention_top' | 'intervention_bottom';
|
|
40
|
-
/** Description détaillée de l'intervention */
|
|
41
|
-
description?: string;
|
|
42
|
-
/** Icône associée (nom FontAwesome ou URL) */
|
|
43
|
-
icon?: string;
|
|
44
|
-
/** Couleur de l'intervention (hex) */
|
|
45
|
-
color?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface Step {
|
|
49
|
-
/** Identifiant unique de l'étape */
|
|
50
|
-
id: string;
|
|
51
|
-
/** Nom de la culture/étape */
|
|
52
|
-
name: string;
|
|
53
|
-
/** Date de début (ISO 8601 string ou Date) */
|
|
54
|
-
startDate: string | Date;
|
|
55
|
-
/** Date de fin (ISO 8601 string ou Date) */
|
|
56
|
-
endDate: string | Date;
|
|
57
|
-
/** Couleur de l'étape (hex) */
|
|
58
|
-
color?: string;
|
|
59
|
-
/** Description de l'étape */
|
|
60
|
-
description?: string;
|
|
61
|
-
/** Liste des interventions */
|
|
62
|
-
interventions?: Intervention[];
|
|
63
|
-
/** Durée calculée en mois */
|
|
64
|
-
duration?: number;
|
|
65
|
-
/** Attributs personnalisés */
|
|
66
|
-
attributes?: Record<string, string | number>;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface ItineraireData {
|
|
70
|
-
/** Titre de la rotation */
|
|
71
|
-
title: string;
|
|
72
|
-
/** Options de configuration */
|
|
73
|
-
options: ItineraireOptions;
|
|
74
|
-
/** Liste des étapes de la rotation */
|
|
75
|
-
steps: Step[];
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface TimelineData extends Array<ItineraireData> {}
|
|
79
|
-
|
|
80
|
-
export type RotationData = ItineraireData | TimelineData;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Props pour le composant TikaRenderer
|
|
84
|
-
*/
|
|
85
|
-
export interface TikaRendererProps {
|
|
86
|
-
/** Données de l'itinéraire à afficher */
|
|
87
|
-
data: RotationData;
|
|
88
|
-
/** Largeur du conteneur */
|
|
89
|
-
width?: string | number;
|
|
90
|
-
/** Hauteur du conteneur */
|
|
91
|
-
height?: string | number;
|
|
92
|
-
/** Classes CSS additionnelles */
|
|
93
|
-
className?: string;
|
|
94
|
-
/** Callback lors du clic sur un élément */
|
|
95
|
-
onItemClick?: (itemId: string, event: Event) => void;
|
|
96
|
-
/** Callback lors du survol d'un élément */
|
|
97
|
-
onItemHover?: (itemId: string, event: Event) => void;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Props pour le composant TikaEditor
|
|
102
|
-
*/
|
|
103
|
-
export interface TikaEditorProps {
|
|
104
|
-
/** Données initiales de l'itinéraire */
|
|
105
|
-
initialData?: ItineraireData;
|
|
106
|
-
/** Callback lors de la sauvegarde */
|
|
107
|
-
onSave?: (data: ItineraireData) => void;
|
|
108
|
-
/** Callback lors de l'export */
|
|
109
|
-
onExport?: (data: ItineraireData) => void;
|
|
110
|
-
/** Classes CSS additionnelles */
|
|
111
|
-
className?: string;
|
|
112
|
-
/** Afficher les boutons Wiki (si intégration avec Wiki) */
|
|
113
|
-
showWikiButtons?: boolean;
|
|
114
|
-
/** Activer la sauvegarde automatique */
|
|
115
|
-
enableAutoSave?: boolean;
|
|
116
|
-
/** Intervalle de sauvegarde automatique (ms) */
|
|
117
|
-
autoSaveInterval?: number;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Interface de la classe RotationRenderer (pour référence)
|
|
122
|
-
*/
|
|
123
|
-
export interface IRotationRenderer {
|
|
124
|
-
data: RotationData;
|
|
125
|
-
chart: any; // Type echarts
|
|
126
|
-
render(): void;
|
|
127
|
-
renderChart(): void;
|
|
128
|
-
buildHTML(): string;
|
|
129
|
-
highlightItem(id: string): void;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Déclarations globales pour l'intégration avec le code existant
|
|
134
|
-
*/
|
|
135
|
-
declare global {
|
|
136
|
-
interface Window {
|
|
137
|
-
RotationRenderer: new (divID: string, data: RotationData) => IRotationRenderer;
|
|
138
|
-
echarts: any;
|
|
139
|
-
$: any;
|
|
140
|
-
_: any;
|
|
141
|
-
rotation_data?: ItineraireData;
|
|
142
|
-
refreshAttributesTable?: () => void;
|
|
143
|
-
refreshStepsButtonList?: () => void;
|
|
144
|
-
refreshInterventionsList?: () => void;
|
|
145
|
-
renderChart?: () => void;
|
|
146
|
-
exportToJsonFile?: (data: ItineraireData, fileName?: string) => void;
|
|
147
|
-
reactEditorSave?: () => void;
|
|
148
|
-
reactEditorExport?: () => void;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export {};
|