92e67d0769
- Stack : Expo Router, Axios, Zustand, React Native Paper (thème sombre), date-fns - Sécurité : secrets dans Android Keystore via expo-secure-store, TLS obligatoire, headers X-N8N-API-KEY + X-App-Token injectés par intercepteur Axios - API : client.ts centralisé + workflows.ts + executions.ts (TypeScript strict) - Store : Zustand appStore avec chargement depuis secure store au démarrage - Hooks : usePolling (générique), useWorkflows, useExecutions - Composants : StatusBadge, WorkflowCard, ExecutionCard, SkeletonLoader - Screens : Dashboard, Workflows, Executions, Logs (détail exécution), Settings - Navigation Expo Router : 4 tabs + stack Logs + écran Setup initial - Docs : INSTALL.md, UPDATE.md, BACKUP.md, HAPROXY.md, SECURITY.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
115 lines
3.3 KiB
TypeScript
115 lines
3.3 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
import { useAppStore } from '../store/appStore';
|
|
import {
|
|
fetchWorkflows,
|
|
activateWorkflow,
|
|
deactivateWorkflow,
|
|
runWorkflow,
|
|
Workflow,
|
|
} from '../api/workflows';
|
|
import { usePolling } from './usePolling';
|
|
|
|
/** Interface des valeurs et actions exposées par le hook */
|
|
interface UseWorkflowsResult {
|
|
workflows: Workflow[];
|
|
isLoading: boolean;
|
|
isRefreshing: boolean;
|
|
/**
|
|
* Recharge manuellement la liste des workflows.
|
|
* Utilisé pour le pull-to-refresh.
|
|
*/
|
|
refresh: () => Promise<void>;
|
|
/**
|
|
* Bascule le statut actif/inactif d'un workflow.
|
|
* Met à jour l'état local après confirmation serveur.
|
|
*
|
|
* @param workflow - Workflow à basculer
|
|
*/
|
|
toggleWorkflow: (workflow: Workflow) => Promise<void>;
|
|
/**
|
|
* Déclenche manuellement l'exécution d'un workflow.
|
|
*
|
|
* @param id - Identifiant du workflow à déclencher
|
|
*/
|
|
triggerWorkflow: (id: string) => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* Hook de gestion des workflows : chargement, polling automatique et actions.
|
|
* Délègue la gestion des erreurs à l'intercepteur Axios (errorHandler).
|
|
* Les screens ne font pas d'appels API directs — tout passe par ce hook.
|
|
*/
|
|
export const useWorkflows = (): UseWorkflowsResult => {
|
|
const { preferences, config } = useAppStore();
|
|
const [workflows, setWorkflows] = useState<Workflow[]>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
|
|
/** Charge la liste des workflows depuis la couche API */
|
|
const loadWorkflows = useCallback(async (): Promise<void> => {
|
|
try {
|
|
const data = await fetchWorkflows();
|
|
setWorkflows(data);
|
|
} catch {
|
|
// Erreur déjà remontée via l'intercepteur Axios → toast affiché
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Polling automatique déclenché uniquement si l'app est configurée.
|
|
* L'intervalle est lu depuis les préférences utilisateur (configurable dans Settings).
|
|
*/
|
|
usePolling({
|
|
callback: loadWorkflows,
|
|
interval: preferences.pollingInterval,
|
|
enabled: config.isConfigured,
|
|
immediate: true,
|
|
});
|
|
|
|
/** Pull-to-refresh : indicateur distinct du chargement initial */
|
|
const refresh = useCallback(async (): Promise<void> => {
|
|
setIsRefreshing(true);
|
|
try {
|
|
await loadWorkflows();
|
|
} finally {
|
|
setIsRefreshing(false);
|
|
}
|
|
}, [loadWorkflows]);
|
|
|
|
/**
|
|
* Bascule actif/inactif d'un workflow.
|
|
* Met à jour l'entrée correspondante dans l'état local après retour serveur.
|
|
*/
|
|
const toggleWorkflow = useCallback(async (workflow: Workflow): Promise<void> => {
|
|
try {
|
|
const updated = workflow.active
|
|
? await deactivateWorkflow(workflow.id)
|
|
: await activateWorkflow(workflow.id);
|
|
|
|
// Mise à jour ciblée sans recharger toute la liste
|
|
setWorkflows((prev) => prev.map((w) => (w.id === updated.id ? updated : w)));
|
|
} catch {
|
|
// Géré par l'intercepteur Axios
|
|
}
|
|
}, []);
|
|
|
|
const triggerWorkflow = useCallback(async (id: string): Promise<void> => {
|
|
try {
|
|
await runWorkflow(id);
|
|
} catch {
|
|
// Géré par l'intercepteur Axios
|
|
}
|
|
}, []);
|
|
|
|
return {
|
|
workflows,
|
|
isLoading,
|
|
isRefreshing,
|
|
refresh,
|
|
toggleWorkflow,
|
|
triggerWorkflow,
|
|
};
|
|
};
|