maj via codex
This commit is contained in:
8
frontend/src/api/astuces.js
Normal file
8
frontend/src/api/astuces.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import client from './client';
|
||||
export const astucesApi = {
|
||||
list: (params) => client.get('/api/astuces', { params }).then(r => r.data),
|
||||
get: (id) => client.get(`/api/astuces/${id}`).then(r => r.data),
|
||||
create: (a) => client.post('/api/astuces', a).then(r => r.data),
|
||||
update: (id, a) => client.put(`/api/astuces/${id}`, a).then(r => r.data),
|
||||
remove: (id) => client.delete(`/api/astuces/${id}`),
|
||||
};
|
||||
31
frontend/src/api/astuces.ts
Normal file
31
frontend/src/api/astuces.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import client from './client'
|
||||
|
||||
export interface Astuce {
|
||||
id?: number
|
||||
titre: string
|
||||
contenu: string
|
||||
categorie?: string
|
||||
tags?: string
|
||||
mois?: string
|
||||
photos?: string
|
||||
videos?: string
|
||||
source?: string
|
||||
created_at?: string
|
||||
}
|
||||
|
||||
export const astucesApi = {
|
||||
list: (params?: { categorie?: string; mois?: number; tag?: string }) =>
|
||||
client.get<Astuce[]>('/api/astuces', { params }).then(r => r.data),
|
||||
|
||||
get: (id: number) =>
|
||||
client.get<Astuce>(`/api/astuces/${id}`).then(r => r.data),
|
||||
|
||||
create: (a: Omit<Astuce, 'id' | 'created_at'>) =>
|
||||
client.post<Astuce>('/api/astuces', a).then(r => r.data),
|
||||
|
||||
update: (id: number, a: Partial<Astuce>) =>
|
||||
client.put<Astuce>(`/api/astuces/${id}`, a).then(r => r.data),
|
||||
|
||||
remove: (id: number) =>
|
||||
client.delete(`/api/astuces/${id}`),
|
||||
}
|
||||
@@ -4,6 +4,11 @@ export const gardensApi = {
|
||||
get: (id) => client.get(`/api/gardens/${id}`).then(r => r.data),
|
||||
create: (g) => client.post('/api/gardens', g).then(r => r.data),
|
||||
update: (id, g) => client.put(`/api/gardens/${id}`, g).then(r => r.data),
|
||||
uploadPhoto: (id, file) => {
|
||||
const fd = new FormData();
|
||||
fd.append('file', file);
|
||||
return client.post(`/api/gardens/${id}/photo`, fd).then(r => r.data);
|
||||
},
|
||||
delete: (id) => client.delete(`/api/gardens/${id}`),
|
||||
cells: (id) => client.get(`/api/gardens/${id}/cells`).then(r => r.data),
|
||||
measurements: (id) => client.get(`/api/gardens/${id}/measurements`).then(r => r.data),
|
||||
|
||||
@@ -5,8 +5,16 @@ export interface Garden {
|
||||
nom: string
|
||||
description?: string
|
||||
type: string
|
||||
longueur_m?: number
|
||||
largeur_m?: number
|
||||
surface_m2?: number
|
||||
carre_potager?: boolean
|
||||
carre_x_cm?: number
|
||||
carre_y_cm?: number
|
||||
photo_parcelle?: string
|
||||
latitude?: number
|
||||
longitude?: number
|
||||
altitude?: number
|
||||
adresse?: string
|
||||
exposition?: string
|
||||
ombre?: string
|
||||
@@ -41,6 +49,11 @@ export const gardensApi = {
|
||||
get: (id: number) => client.get<Garden>(`/api/gardens/${id}`).then(r => r.data),
|
||||
create: (g: Partial<Garden>) => client.post<Garden>('/api/gardens', g).then(r => r.data),
|
||||
update: (id: number, g: Partial<Garden>) => client.put<Garden>(`/api/gardens/${id}`, g).then(r => r.data),
|
||||
uploadPhoto: (id: number, file: File) => {
|
||||
const fd = new FormData()
|
||||
fd.append('file', file)
|
||||
return client.post<Garden>(`/api/gardens/${id}/photo`, fd).then(r => r.data)
|
||||
},
|
||||
delete: (id: number) => client.delete(`/api/gardens/${id}`),
|
||||
cells: (id: number) => client.get<GardenCell[]>(`/api/gardens/${id}/cells`).then(r => r.data),
|
||||
measurements: (id: number) => client.get<Measurement[]>(`/api/gardens/${id}/measurements`).then(r => r.data),
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface LunarDay {
|
||||
montante_descendante: string
|
||||
signe: string
|
||||
type_jour: string
|
||||
saint_du_jour?: string
|
||||
perigee: boolean
|
||||
apogee: boolean
|
||||
noeud_lunaire: boolean
|
||||
|
||||
@@ -1,4 +1,60 @@
|
||||
import client from './client';
|
||||
const CACHE_TTL_MS = 5 * 60 * 1000;
|
||||
const cache = new Map();
|
||||
const inflight = new Map();
|
||||
function todayIso() {
|
||||
const d = new Date();
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
function cacheKeyTableau(params) {
|
||||
const center = params?.center_date || '';
|
||||
const span = params?.span ?? '';
|
||||
return `tableau:${center}:${span}`;
|
||||
}
|
||||
function getCached(key) {
|
||||
const entry = cache.get(key);
|
||||
if (!entry)
|
||||
return null;
|
||||
if (Date.now() > entry.expires_at) {
|
||||
cache.delete(key);
|
||||
return null;
|
||||
}
|
||||
return entry.value;
|
||||
}
|
||||
function setCached(key, value) {
|
||||
cache.set(key, { value, expires_at: Date.now() + CACHE_TTL_MS });
|
||||
}
|
||||
function fetchWithCache(key, loader) {
|
||||
const cached = getCached(key);
|
||||
if (cached != null)
|
||||
return Promise.resolve(cached);
|
||||
const pending = inflight.get(key);
|
||||
if (pending)
|
||||
return pending;
|
||||
const p = loader()
|
||||
.then((value) => {
|
||||
setCached(key, value);
|
||||
return value;
|
||||
})
|
||||
.finally(() => {
|
||||
inflight.delete(key);
|
||||
});
|
||||
inflight.set(key, p);
|
||||
return p;
|
||||
}
|
||||
export const meteoApi = {
|
||||
getForecast: (days = 14) => client.get('/api/meteo', { params: { days } }).then(r => r.data),
|
||||
getForecast: (days = 14) => fetchWithCache(`forecast:${days}`, () => client.get('/api/meteo', { params: { days } }).then(r => r.data)),
|
||||
getTableau: (params) => fetchWithCache(cacheKeyTableau(params), () => client.get('/api/meteo/tableau', { params }).then(r => r.data)),
|
||||
getStationCurrent: () => fetchWithCache('station-current', () => client.get('/api/meteo/station/current').then(r => r.data)),
|
||||
getPrevisions: (days = 7) => fetchWithCache(`previsions:${days}`, () => client.get('/api/meteo/previsions', { params: { days } }).then(r => r.data)),
|
||||
preloadForMeteoView: (params) => Promise.all([
|
||||
meteoApi.getTableau(params ?? { center_date: todayIso(), span: 15 }),
|
||||
meteoApi.getStationCurrent(),
|
||||
meteoApi.getPrevisions(7),
|
||||
]).then(() => undefined),
|
||||
clearCache: () => {
|
||||
cache.clear();
|
||||
inflight.clear();
|
||||
},
|
||||
refresh: () => client.post('/api/meteo/refresh').then(r => r.data),
|
||||
};
|
||||
|
||||
@@ -11,6 +11,134 @@ export interface MeteoDay {
|
||||
icone: string
|
||||
}
|
||||
|
||||
export const meteoApi = {
|
||||
getForecast: (days = 14) => client.get<{ days: MeteoDay[] }>('/api/meteo', { params: { days } }).then(r => r.data),
|
||||
export interface StationCurrent {
|
||||
temp_ext?: number
|
||||
humidite?: number
|
||||
pression?: number
|
||||
pluie_mm?: number
|
||||
vent_kmh?: number
|
||||
vent_dir?: string
|
||||
uv?: number
|
||||
solaire?: number
|
||||
date_heure?: string
|
||||
}
|
||||
|
||||
export interface StationDay {
|
||||
t_min?: number
|
||||
t_max?: number
|
||||
pluie_mm?: number
|
||||
vent_kmh?: number
|
||||
humidite?: number
|
||||
}
|
||||
|
||||
export interface OpenMeteoDay {
|
||||
date?: string
|
||||
t_min?: number
|
||||
t_max?: number
|
||||
pluie_mm?: number
|
||||
vent_kmh?: number
|
||||
wmo?: number
|
||||
label?: string
|
||||
humidite_moy?: number
|
||||
sol_0cm?: number
|
||||
etp_mm?: number
|
||||
}
|
||||
|
||||
export interface TableauRow {
|
||||
date: string
|
||||
type: 'passe' | 'aujourd_hui' | 'futur'
|
||||
station: StationDay | StationCurrent | null
|
||||
open_meteo: OpenMeteoDay | null
|
||||
}
|
||||
|
||||
const CACHE_TTL_MS = 5 * 60 * 1000
|
||||
|
||||
type CacheEntry<T> = {
|
||||
value: T
|
||||
expires_at: number
|
||||
}
|
||||
|
||||
const cache = new Map<string, CacheEntry<unknown>>()
|
||||
const inflight = new Map<string, Promise<unknown>>()
|
||||
|
||||
function todayIso(): string {
|
||||
const d = new Date()
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
function cacheKeyTableau(params?: { center_date?: string; span?: number }): string {
|
||||
const center = params?.center_date || ''
|
||||
const span = params?.span ?? ''
|
||||
return `tableau:${center}:${span}`
|
||||
}
|
||||
|
||||
function getCached<T>(key: string): T | null {
|
||||
const entry = cache.get(key)
|
||||
if (!entry) return null
|
||||
if (Date.now() > entry.expires_at) {
|
||||
cache.delete(key)
|
||||
return null
|
||||
}
|
||||
return entry.value as T
|
||||
}
|
||||
|
||||
function setCached<T>(key: string, value: T): void {
|
||||
cache.set(key, { value, expires_at: Date.now() + CACHE_TTL_MS })
|
||||
}
|
||||
|
||||
function fetchWithCache<T>(key: string, loader: () => Promise<T>): Promise<T> {
|
||||
const cached = getCached<T>(key)
|
||||
if (cached != null) return Promise.resolve(cached)
|
||||
|
||||
const pending = inflight.get(key)
|
||||
if (pending) return pending as Promise<T>
|
||||
|
||||
const p = loader()
|
||||
.then((value) => {
|
||||
setCached(key, value)
|
||||
return value
|
||||
})
|
||||
.finally(() => {
|
||||
inflight.delete(key)
|
||||
})
|
||||
|
||||
inflight.set(key, p as Promise<unknown>)
|
||||
return p
|
||||
}
|
||||
|
||||
export const meteoApi = {
|
||||
getForecast: (days = 14) =>
|
||||
fetchWithCache(`forecast:${days}`, () =>
|
||||
client.get<{ days: MeteoDay[] }>('/api/meteo', { params: { days } }).then(r => r.data),
|
||||
),
|
||||
|
||||
getTableau: (params?: { center_date?: string; span?: number }) =>
|
||||
fetchWithCache(cacheKeyTableau(params), () =>
|
||||
client.get<{ rows: TableauRow[] }>('/api/meteo/tableau', { params }).then(r => r.data),
|
||||
),
|
||||
|
||||
getStationCurrent: () =>
|
||||
fetchWithCache('station-current', () =>
|
||||
client.get<StationCurrent | null>('/api/meteo/station/current').then(r => r.data),
|
||||
),
|
||||
|
||||
getPrevisions: (days = 7) =>
|
||||
fetchWithCache(`previsions:${days}`, () =>
|
||||
client.get<{ days: OpenMeteoDay[] }>('/api/meteo/previsions', { params: { days } }).then(r => r.data),
|
||||
),
|
||||
|
||||
preloadForMeteoView: (params?: { center_date?: string; span?: number }) =>
|
||||
Promise.all([
|
||||
meteoApi.getTableau(params ?? { center_date: todayIso(), span: 15 }),
|
||||
meteoApi.getStationCurrent(),
|
||||
meteoApi.getPrevisions(7),
|
||||
]).then(() => undefined),
|
||||
|
||||
clearCache: () => {
|
||||
cache.clear()
|
||||
inflight.clear()
|
||||
},
|
||||
|
||||
refresh: () =>
|
||||
client.post('/api/meteo/refresh').then(r => r.data),
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ export interface Planting {
|
||||
date_plantation?: string
|
||||
quantite: number
|
||||
statut: string
|
||||
boutique_nom?: string
|
||||
boutique_url?: string
|
||||
tarif_achat?: number
|
||||
date_achat?: string
|
||||
notes?: string
|
||||
}
|
||||
|
||||
|
||||
6
frontend/src/api/settings.js
Normal file
6
frontend/src/api/settings.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import client from './client';
|
||||
export const settingsApi = {
|
||||
get: () => client.get('/api/settings').then(r => r.data),
|
||||
update: (settings) => client.put('/api/settings', settings).then(r => r.data),
|
||||
getDebugSystemStats: () => client.get('/api/settings/debug/system').then(r => r.data),
|
||||
};
|
||||
33
frontend/src/api/settings.ts
Normal file
33
frontend/src/api/settings.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import client from './client'
|
||||
|
||||
export type SettingsMap = Record<string, string>
|
||||
|
||||
export interface DebugSystemStats {
|
||||
source: string
|
||||
cpu: {
|
||||
usage_usec_total?: number | null
|
||||
quota_cores?: number | null
|
||||
used_pct?: number | null
|
||||
}
|
||||
memory: {
|
||||
used_bytes?: number | null
|
||||
limit_bytes?: number | null
|
||||
used_pct?: number | null
|
||||
}
|
||||
disk: {
|
||||
path?: string
|
||||
total_bytes?: number | null
|
||||
used_bytes?: number | null
|
||||
free_bytes?: number | null
|
||||
used_pct?: number | null
|
||||
uploads_bytes?: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export const settingsApi = {
|
||||
get: () => client.get<SettingsMap>('/api/settings').then(r => r.data),
|
||||
update: (settings: Record<string, string | number | boolean>) =>
|
||||
client.put<{ ok: boolean }>('/api/settings', settings).then(r => r.data),
|
||||
getDebugSystemStats: () =>
|
||||
client.get<DebugSystemStats>('/api/settings/debug/system').then(r => r.data),
|
||||
}
|
||||
@@ -7,6 +7,9 @@ export interface Task {
|
||||
garden_id?: number
|
||||
priorite: string
|
||||
echeance?: string
|
||||
recurrence?: string | null
|
||||
frequence_jours?: number | null
|
||||
date_prochaine?: string | null
|
||||
statut: string
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@ export interface Tool {
|
||||
description?: string
|
||||
categorie?: string
|
||||
photo_url?: string
|
||||
video_url?: string
|
||||
notice_fichier_url?: string
|
||||
boutique_nom?: string
|
||||
boutique_url?: string
|
||||
prix_achat?: number
|
||||
}
|
||||
|
||||
export const toolsApi = {
|
||||
|
||||
Reference in New Issue
Block a user