diff --git a/client/public/__manus__/version.json b/client/public/__manus__/version.json index e32a7a8..0b4a46e 100644 --- a/client/public/__manus__/version.json +++ b/client/public/__manus__/version.json @@ -1,4 +1,4 @@ { - "version": "6c88c7af", - "timestamp": 1782767248272 + "version": "3967f6c2", + "timestamp": 1782655834971 } \ No newline at end of file diff --git a/client/src/pages/Settings.tsx b/client/src/pages/Settings.tsx index b14b1e5..e436f35 100644 --- a/client/src/pages/Settings.tsx +++ b/client/src/pages/Settings.tsx @@ -220,10 +220,8 @@ export default function SettingsPage() { sharepoint_token: "", auth_mode: "local", import_time: "06:00", - fetch_mode: "daily", + fetch_mode: "scheduled", fetch_interval_minutes: "1440", - fetch_week_day: "1", - fetch_month_day: "1", }); useEffect(() => { @@ -467,106 +465,57 @@ export default function SettingsPage() { Configurez la fréquence et l'heure de déclenchement des mises à jour automatiques (import Excel + lecture RSS). - {/* Fréquence */} + {/* Mode */}
- -
- {([ - { value: "daily", label: "Quotidienne", desc: "Chaque jour à l'heure choisie" }, - { value: "weekly", label: "Hebdomadaire", desc: "Un jour précis chaque semaine" }, - { value: "monthly", label: "Mensuelle", desc: "Un jour précis chaque mois" }, - { value: "interval", label: "Intervalle", desc: "Toutes les N heures" }, - ] as const).map((opt) => ( + +
+ {(["scheduled", "interval"] as const).map((mode) => ( ))}
- {/* Heure (tous les modes sauf intervalle) */} - {(form.fetch_mode || "daily") !== "interval" && ( + {/* Heure fixe */} + {(form.fetch_mode || "scheduled") === "scheduled" && (
- + set("import_time", e.target.value)} /> -
- )} - - {/* Jour de la semaine (hebdomadaire) */} - {(form.fetch_mode || "daily") === "weekly" && ( -
- -
- {[ - { label: "Lun", value: "1" }, - { label: "Mar", value: "2" }, - { label: "Mer", value: "3" }, - { label: "Jeu", value: "4" }, - { label: "Ven", value: "5" }, - { label: "Sam", value: "6" }, - { label: "Dim", value: "0" }, - ].map((d) => ( - - ))} -
-
- )} - - {/* Jour du mois (mensuel) */} - {(form.fetch_mode || "daily") === "monthly" && ( -
- - set("fetch_month_day", e.target.value)} - /> -

Maximum 28 pour garantir l'exécution tous les mois

+

+ Prochain import : demain à {form.import_time || "06:00"} +

)} {/* Intervalle */} - {(form.fetch_mode || "daily") === "interval" && ( -
- -
+ {(form.fetch_mode || "scheduled") === "interval" && ( +
+ +
{[ - { label: "1h", value: "60" }, - { label: "2h", value: "120" }, - { label: "4h", value: "240" }, - { label: "6h", value: "360" }, + { label: "1h", value: "60" }, + { label: "2h", value: "120" }, + { label: "4h", value: "240" }, + { label: "6h", value: "360" }, { label: "12h", value: "720" }, { label: "24h", value: "1440" }, ].map((opt) => ( @@ -575,7 +524,7 @@ export default function SettingsPage() { type="button" onClick={() => set("fetch_interval_minutes", opt.value)} className={cn( - "w-14 py-2 rounded-lg border-2 text-sm font-medium transition-all", + "py-2 px-3 rounded-lg border-2 text-sm font-medium transition-all", (form.fetch_interval_minutes || "1440") === opt.value ? "border-primary bg-primary/5 text-primary" : "border-border hover:border-primary/40 text-foreground" @@ -586,9 +535,7 @@ export default function SettingsPage() { ))}

- Import toutes les {parseInt(form.fetch_interval_minutes || "1440") >= 60 - ? `${parseInt(form.fetch_interval_minutes || "1440") / 60}h` - : `${form.fetch_interval_minutes || "1440"} min`} + Import toutes les {(form.fetch_interval_minutes || "1440") === "60" ? "heure" : `${parseInt(form.fetch_interval_minutes || "1440") / 60} heures`}

)} diff --git a/server/_core/index.ts b/server/_core/index.ts index ee3955a..94531cc 100644 --- a/server/_core/index.ts +++ b/server/_core/index.ts @@ -35,46 +35,27 @@ let cronJob: ReturnType | null = null; export async function scheduleDailyImport() { const importTime = (await getSetting("import_time")) || "06:00"; - const fetchMode = (await getSetting("fetch_mode")) || "daily"; + const fetchMode = (await getSetting("fetch_mode")) || "scheduled"; const fetchIntervalMinutes = parseInt((await getSetting("fetch_interval_minutes")) || "1440", 10); - const fetchWeekDay = (await getSetting("fetch_week_day")) || "1"; // 0=dim, 1=lun, ..., 6=sam - const fetchMonthDay = (await getSetting("fetch_month_day")) || "1"; // 1-28 - - const [hour, minute] = importTime.split(":").map(Number); - const h = hour ?? 6; - const m = minute ?? 0; let cronExpr: string; - let cronLabel: string; - if (fetchMode === "interval") { const intervalMin = Math.max(60, fetchIntervalMinutes); - if (intervalMin % 60 === 0) { + if (intervalMin < 60) { + cronExpr = `*/${intervalMin} * * * *`; + } else if (intervalMin % 60 === 0) { const hours = intervalMin / 60; - cronExpr = hours === 24 ? `0 ${m} ${h} * * *` : `0 ${m} */${hours} * * *`; + cronExpr = hours === 24 ? `0 0 * * *` : `0 */${hours} * * *`; } else { - cronExpr = `0 */${intervalMin} * * * *`; + cronExpr = `*/${intervalMin} * * * *`; } - const hours = intervalMin / 60; - cronLabel = `Mode intervalle — toutes les ${hours >= 1 ? hours + "h" : intervalMin + "min"} (${cronExpr})`; - } else if (fetchMode === "weekly") { - // hebdomadaire : le jour choisi à l'heure choisie - cronExpr = `0 ${m} ${h} * * ${fetchWeekDay}`; - const jours = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]; - cronLabel = `Mode hebdomadaire — chaque ${jours[parseInt(fetchWeekDay)] ?? "lundi"} à ${importTime} (${cronExpr})`; - } else if (fetchMode === "monthly") { - // mensuel : le jour du mois choisi à l'heure choisie - const day = Math.min(28, Math.max(1, parseInt(fetchMonthDay))); - cronExpr = `0 ${m} ${h} ${day} * *`; - cronLabel = `Mode mensuel — le ${day} de chaque mois à ${importTime} (${cronExpr})`; + console.log(`[Cron] Mode intervalle — toutes les ${intervalMin} minutes (${cronExpr})`); } else { - // daily (défaut) - cronExpr = `0 ${m} ${h} * * *`; - cronLabel = `Mode quotidien — tous les jours à ${importTime} (${cronExpr})`; + const [hour, minute] = importTime.split(":").map(Number); + cronExpr = `0 ${minute ?? 0} ${hour ?? 6} * * *`; + console.log(`[Cron] Mode heure fixe — tous les jours à ${importTime} (${cronExpr})`); } - console.log(`[Cron] ${cronLabel}`); - if (cronJob) { cronJob.stop(); cronJob = null; diff --git a/server/routers.ts b/server/routers.ts index 5652515..01a84c2 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -372,10 +372,8 @@ export const appRouter = router({ sharepoint_token: z.string().optional(), auth_mode: z.enum(["local", "free"]).optional(), import_time: z.string().optional(), - fetch_mode: z.enum(["daily", "weekly", "monthly", "interval", "scheduled"]).optional(), + fetch_mode: z.enum(["scheduled", "interval"]).optional(), fetch_interval_minutes: z.string().optional(), - fetch_week_day: z.string().optional(), - fetch_month_day: z.string().optional(), }) ) .mutation(async ({ input }) => { @@ -385,7 +383,7 @@ export const appRouter = router({ } await setSettings(toSave); // Recharger le cron si la planification a changé - if (toSave.import_time || toSave.fetch_mode || toSave.fetch_interval_minutes || toSave.fetch_week_day || toSave.fetch_month_day) { + if (toSave.import_time || toSave.fetch_mode || toSave.fetch_interval_minutes) { await scheduleDailyImport(); } return { success: true }; diff --git a/server/rssEngine.ts b/server/rssEngine.ts index 9d4bf21..e1e3b34 100644 --- a/server/rssEngine.ts +++ b/server/rssEngine.ts @@ -203,11 +203,29 @@ export function detectVeilleNiveauTerritoire(text: string): { niveau: VeilleNive // ─── Extraction automatique pour les AAP ───────────────────────────────────── +/** + * Détecte le niveau de localisation le plus fin dans le texte : + * - Département AuRA si mentionné → region = "Auvergne-Rhône-Alpes", departement = "Nom (num)" + * - Région AuRA si mentionnée → region = "Auvergne-Rhône-Alpes", departement = null + * - Sinon → region = "National", departement = null + */ export function detectAapGeo(text: string): { region: string; departement: string | null } { const dept = detectDepartment(text); + if (dept) { + return { + region: "Auvergne-Rhône-Alpes", + departement: `${dept.name} (${dept.num})`, + }; + } + if (isRegional(text)) { + return { + region: "Auvergne-Rhône-Alpes", + departement: null, + }; + } return { - region: "Auvergne-Rhône-Alpes", - departement: dept ? `${dept.name} (${dept.num})` : null, + region: "National", + departement: null, }; } diff --git a/todo.md b/todo.md index 3666b0d..5759101 100644 --- a/todo.md +++ b/todo.md @@ -182,8 +182,3 @@ - [x] Backend routers.ts : exposer et sauvegarder ces deux nouveaux paramètres - [x] Frontend Settings.tsx : sélecteur mode (heure fixe / intervalle) + sélecteur intervalle (1h, 2h, 4h, 6h, 12h, 24h) - [x] Déployer en recette - -## Fréquence de planification enrichie -- [x] Backend index.ts : générer l'expression cron selon quotidien/hebdomadaire (jour)/mensuel/intervalle -- [x] Frontend Settings.tsx : sélecteur fréquence (quotidien, hebdo + jour, mensuel, intervalle) + heure -- [ ] Déployer en recette