File de tâches et panneau d’activité #37

Closed
opened 2026-07-18 09:01:18 +02:00 by fy59 · 0 comments
Owner

File de tâches et panneau d’activité

Contexte

Le ticket #036 a introduit BackgroundTask, une primitive asynchrone capable de :

  • lancer un worker dans un thread GLib ;
  • suivre son état ;
  • signaler sa progression ;
  • gérer l’annulation ;
  • conserver un résultat ou une erreur ;
  • revenir sur le contexte principal à la fin ;
  • rester vivante grâce au comptage de références.

Cette primitive ne gère cependant pas encore plusieurs tâches ni leur présentation dans l’interface.

Objectif

Créer un gestionnaire opaque :

TaskManager

chargé de suivre les tâches actives et terminées, puis ajouter un panneau GTK permettant de les consulter.

Le ticket doit permettre de voir :

Titre
État
Progression
Message courant
Bouton Annuler

Le gestionnaire reste indépendant de GTK.


Architecture attendue

Créer :

include/core/task_manager.h
src/core/task_manager.c
tests/test_task_manager.c

include/widgets/task_panel.h
src/widgets/task_panel.c

Relations :

Application
    ├── possède TaskManager
    └── transmet TaskManager à MainWindow

MainWindow
    └── possède TaskPanel

TaskPanel
    └── observe TaskManager

TaskManager
    └── conserve des références vers BackgroundTask

Phase A — TaskManager

1. Type opaque

Dans :

include/core/task_manager.h

déclarer :

typedef struct TaskManager TaskManager;

Le type doit rester indépendant de GTK, SQLite et des enquêtes.


2. Callback de changement

Définir :

typedef void (*TaskManagerChangedCallback)(
    TaskManager *task_manager,
    gpointer user_data
);

Le callback signale qu’un changement visible a eu lieu :

  • tâche ajoutée ;
  • progression modifiée ;
  • tâche terminée ;
  • tâche retirée ;
  • annulation demandée.

Le callback est une notification globale. Il ne transmet pas directement une tâche particulière.


3. API publique

Construction

TaskManager *task_manager_new(void);

void task_manager_free(
    TaskManager *task_manager
);

Ajouter une tâche

gboolean task_manager_add(
    TaskManager *task_manager,
    BackgroundTask *task,
    GError **error
);

Règles :

  • task_manager devient propriétaire d’une référence supplémentaire ;
  • l’appelant conserve sa propre référence ;
  • une même tâche ne peut pas être ajoutée deux fois ;
  • une tâche déjà terminée peut être ajoutée, mais elle est immédiatement visible comme terminée ;
  • NULL est refusé.

Consulter les tâches

gsize task_manager_get_count(
    const TaskManager *task_manager
);

BackgroundTask *task_manager_get_task(
    const TaskManager *task_manager,
    gsize index
);

task_manager_get_task() retourne une nouvelle référence que l’appelant doit libérer.

Retirer une tâche

gboolean task_manager_remove(
    TaskManager *task_manager,
    BackgroundTask *task
);

La tâche n’est pas annulée automatiquement.

Supprimer les tâches terminées

gsize task_manager_remove_finished(
    TaskManager *task_manager
);

États concernés :

COMPLETED
FAILED
CANCELLED

Annuler toutes les tâches actives

void task_manager_cancel_all(
    TaskManager *task_manager
);

Callback de changement

void task_manager_set_changed_callback(
    TaskManager *task_manager,
    TaskManagerChangedCallback callback,
    gpointer user_data,
    GDestroyNotify user_data_destroy
);

Le manager possède user_data après l’appel.

Remplacer le callback existant doit détruire les anciennes données exactement une fois.


4. Domaine d’erreur

Définir :

typedef enum
{
    TASK_MANAGER_ERROR_INVALID_ARGUMENT,
    TASK_MANAGER_ERROR_ALREADY_ADDED
} TaskManagerError;

Puis :

#define TASK_MANAGER_ERROR \
    task_manager_error_quark()

GQuark task_manager_error_quark(void);

5. Structure interne recommandée

struct TaskManager
{
    GMutex mutex;
    GPtrArray *tasks;

    TaskManagerChangedCallback changed_callback;
    gpointer changed_user_data;
    GDestroyNotify changed_user_data_destroy;
};

tasks doit contenir des références BackgroundTask *.

Configurer le GPtrArray avec :

background_task_unref

comme fonction de destruction.


6. Notification périodique

BackgroundTask ne possède pas encore de callback de progression.

Pour ce ticket, TaskPanel peut rafraîchir périodiquement l’affichage avec :

g_timeout_add()

fréquence recommandée :

200 à 300 ms

TaskManager notifie immédiatement les changements structurels.

La progression sera relue par le panneau.

Une API d’observation plus fine pourra être ajoutée plus tard si nécessaire.


Phase B — Tests de TaskManager

Créer :

tests/test_task_manager.c

Tests minimaux

Construction

Vérifier :

manager non NULL
compteur initial à zéro

Ajout

Ajouter une tâche et vérifier :

compteur à un
callback déclenché
tâche récupérable
référence indépendante

Doublon

Ajouter deux fois la même tâche :

FALSE
TASK_MANAGER_ERROR_ALREADY_ADDED
compteur inchangé

Retrait

Retirer une tâche :

TRUE
compteur décrémenté
callback déclenché

Retrait inconnu

Retirer une tâche absente :

FALSE
aucun crash

Nettoyage des tâches terminées

Ajouter :

  • une tâche en attente ;
  • une tâche terminée ;
  • une tâche échouée ;
  • une tâche annulée.

Vérifier que seules les tâches terminées sont supprimées.

Annulation globale

Ajouter plusieurs tâches actives et appeler :

task_manager_cancel_all()

Vérifier que chaque GCancellable reçoit une demande d’annulation.

Durée de vie

Vérifier que :

  • le manager conserve ses références ;
  • la destruction du manager libère toutes les tâches ;
  • le remplacement du callback détruit les anciennes données une seule fois.

Phase C — TaskPanel

7. Type opaque

Dans :

include/widgets/task_panel.h

déclarer :

typedef struct TaskPanel TaskPanel;

API :

TaskPanel *task_panel_new(
    TaskManager *task_manager
);

GtkWidget *task_panel_get_widget(
    const TaskPanel *task_panel
);

void task_panel_refresh(
    TaskPanel *task_panel
);

void task_panel_free(
    TaskPanel *task_panel
);

TaskPanel ne devient pas propriétaire de TaskManager.

TaskPanel doit rester valide tant que le manager existe.


8. Interface recommandée

Premier rendu simple :

┌──────────────────────────────────────────────────────────┐
│ Activité                                  [ Nettoyer ]    │
├──────────────────────────────────────────────────────────┤
│ Extraction des métadonnées                              │
│ En cours — 45 %                                         │
│ [████████░░░░░░░░░░]                     [ Annuler ]     │
├──────────────────────────────────────────────────────────┤
│ Calcul SHA-256                                          │
│ Terminé                                                 │
│ [████████████████████]                                  │
└──────────────────────────────────────────────────────────┘

Widgets GTK possibles :

  • GtkBox ;
  • GtkLabel ;
  • GtkProgressBar ;
  • GtkButton ;
  • GtkScrolledWindow.

Ne pas utiliser encore de GtkListView si cela complexifie inutilement le ticket.


9. État visuel

Créer une fonction privée traduisant les états :

PENDING   → En attente
RUNNING   → En cours
COMPLETED → Terminée
FAILED    → Échouée
CANCELLED → Annulée

Une tâche en erreur doit afficher son message d’erreur sous forme courte.

Une tâche en cours doit afficher son message de progression lorsqu’il existe.


10. Bouton d’annulation

Le bouton Annuler doit être visible uniquement pour :

RUNNING

Son callback appelle :

background_task_cancel(task);

Le bouton ne doit pas retirer la tâche.


11. Bouton de nettoyage

Ajouter :

Nettoyer

Il appelle :

task_manager_remove_finished()

Les tâches actives restent visibles.


12. Rafraîchissement périodique

TaskPanel doit enregistrer une source GLib :

g_timeout_add()

Elle appelle :

task_panel_refresh()

Lors de task_panel_free() :

  • retirer la source avec g_source_remove() ;
  • empêcher tout callback après destruction ;
  • ne pas détruire TaskManager.

Phase D — Intégration GTK

13. Ajouter le panneau à MainWindow

Modifier :

include/views/main_window.h
src/views/main_window.c

Changer la construction :

MainWindow *main_window_new(
    GtkApplication *application,
    TaskManager *task_manager
);

MainWindow doit créer :

TaskPanel *task_panel;

Le panneau peut être placé :

  • sous la zone de travail ;
  • dans un volet inférieur ;
  • ou temporairement dans une colonne latérale secondaire.

Pour ce ticket, un volet inférieur sous GtkPaned est acceptable.


14. Ajouter TaskManager à Application

Dans la structure privée :

TaskManager *task_manager;

Dans application_new() :

application->task_manager =
    task_manager_new();

En cas d’échec, nettoyer l’application.

Dans application_on_activate() :

application->main_window = main_window_new(
    gtk_application,
    application->task_manager
);

Dans application_free() :

  1. fermer/détruire MainWindow ;
  2. libérer TaskManager après le panneau ;
  3. poursuivre le nettoyage existant.

L’ordre doit éviter que TaskPanel lise un manager déjà détruit.


Phase E — Tâche de démonstration

15. Ajouter temporairement une tâche de test

Pour valider l’interface, ajouter un bouton temporaire :

Tâche de test

Il lance une BackgroundTask qui :

  • dure environ deux secondes ;
  • progresse de 0 à 100 % ;
  • accepte l’annulation ;
  • retourne un résultat simple.

Cette tâche doit être ajoutée au TaskManager.

Le bouton pourra être supprimé lorsque le premier véritable traitement asynchrone sera disponible.

Le code de démonstration doit rester clairement identifié :

/* Temporary demonstration task for ticket #035. */

Hors périmètre

Ne pas ajouter encore :

  • de limite de concurrence ;
  • de priorité ;
  • de persistance SQLite ;
  • de reprise après redémarrage ;
  • d’historique permanent ;
  • d’exécution de commandes ;
  • de recherche DNS ;
  • d’ExifTool ;
  • de notifications système ;
  • de tri avancé ;
  • de pagination.

Critères d’acceptation

  • TaskManager est opaque.
  • TaskManager ne dépend pas de GTK.
  • TaskManager protège sa collection avec GMutex.
  • Le manager conserve une référence par tâche.
  • Une tâche ne peut pas être ajoutée deux fois.
  • Une tâche peut être retirée.
  • Les tâches terminées peuvent être nettoyées.
  • Toutes les tâches actives peuvent être annulées.
  • Le callback de changement fonctionne.
  • TaskPanel affiche toutes les tâches.
  • La progression est visible.
  • L’état est lisible.
  • Une tâche active peut être annulée.
  • Les tâches terminées peuvent être supprimées.
  • Le rafraîchissement périodique est correctement détruit.
  • MainWindow ne devient pas propriétaire du manager.
  • L’ordre de destruction ne provoque aucun crash.
  • La tâche de démonstration fonctionne.
  • make réussit.
  • make test réussit.
  • git diff --check ne retourne aucune erreur.

Audit attendu

Vérifier l’indépendance du manager :

rg -n \
    '#include <gtk|sqlite3_|Database|Investigation' \
    include/core/task_manager.h \
    src/core/task_manager.c

Résultat attendu :

aucune sortie

Vérifier les références :

rg -n \
    'background_task_ref|background_task_unref' \
    src/core/task_manager.c

Vérifier le rafraîchissement GTK :

rg -n \
    'g_timeout_add|g_source_remove|task_panel_refresh' \
    src/widgets/task_panel.c

Vérifier l’absence de threads bruts :

rg -n \
    'pthread_|pthread.h' \
    include/core/task_manager.h \
    src/core/task_manager.c \
    src/widgets/task_panel.c

Résultat attendu :

aucune sortie

Fichiers concernés

include/core/task_manager.h
src/core/task_manager.c
tests/test_task_manager.c

include/widgets/task_panel.h
src/widgets/task_panel.c

include/views/main_window.h
src/views/main_window.c

src/core/application.c
Makefile

Commit attendu

make clean
make
make test
git diff --check
git status --short
git add \
    include/core/task_manager.h \
    src/core/task_manager.c \
    tests/test_task_manager.c \
    include/widgets/task_panel.h \
    src/widgets/task_panel.c \
    include/views/main_window.h \
    src/views/main_window.c \
    src/core/application.c \
    Makefile
git diff --cached --stat
git diff --cached
git commit -m "feat(ui): add task manager and activity panel"
git push

Résultat attendu

Après ce ticket, Labfy possédera une infrastructure visible pour tous les futurs traitements longs :

Utilisateur
    ↓
Action GTK
    ↓
BackgroundTask
    ↓
TaskManager
    ↓
TaskPanel

Le ticket suivant pourra ajouter le registre des dépendances et lancer les premiers contrôles d’outils externes sans bloquer l’interface.

# File de tâches et panneau d’activité ## Contexte Le ticket #036 a introduit `BackgroundTask`, une primitive asynchrone capable de : - lancer un worker dans un thread GLib ; - suivre son état ; - signaler sa progression ; - gérer l’annulation ; - conserver un résultat ou une erreur ; - revenir sur le contexte principal à la fin ; - rester vivante grâce au comptage de références. Cette primitive ne gère cependant pas encore plusieurs tâches ni leur présentation dans l’interface. ## Objectif Créer un gestionnaire opaque : ```c TaskManager ``` chargé de suivre les tâches actives et terminées, puis ajouter un panneau GTK permettant de les consulter. Le ticket doit permettre de voir : ```text Titre État Progression Message courant Bouton Annuler ``` Le gestionnaire reste indépendant de GTK. --- # Architecture attendue Créer : ```text include/core/task_manager.h src/core/task_manager.c tests/test_task_manager.c include/widgets/task_panel.h src/widgets/task_panel.c ``` Relations : ```text Application ├── possède TaskManager └── transmet TaskManager à MainWindow MainWindow └── possède TaskPanel TaskPanel └── observe TaskManager TaskManager └── conserve des références vers BackgroundTask ``` --- # Phase A — `TaskManager` ## 1. Type opaque Dans : ```text include/core/task_manager.h ``` déclarer : ```c typedef struct TaskManager TaskManager; ``` Le type doit rester indépendant de GTK, SQLite et des enquêtes. --- ## 2. Callback de changement Définir : ```c typedef void (*TaskManagerChangedCallback)( TaskManager *task_manager, gpointer user_data ); ``` Le callback signale qu’un changement visible a eu lieu : - tâche ajoutée ; - progression modifiée ; - tâche terminée ; - tâche retirée ; - annulation demandée. Le callback est une notification globale. Il ne transmet pas directement une tâche particulière. --- ## 3. API publique ### Construction ```c TaskManager *task_manager_new(void); void task_manager_free( TaskManager *task_manager ); ``` ### Ajouter une tâche ```c gboolean task_manager_add( TaskManager *task_manager, BackgroundTask *task, GError **error ); ``` Règles : - `task_manager` devient propriétaire d’une référence supplémentaire ; - l’appelant conserve sa propre référence ; - une même tâche ne peut pas être ajoutée deux fois ; - une tâche déjà terminée peut être ajoutée, mais elle est immédiatement visible comme terminée ; - `NULL` est refusé. ### Consulter les tâches ```c gsize task_manager_get_count( const TaskManager *task_manager ); BackgroundTask *task_manager_get_task( const TaskManager *task_manager, gsize index ); ``` `task_manager_get_task()` retourne une nouvelle référence que l’appelant doit libérer. ### Retirer une tâche ```c gboolean task_manager_remove( TaskManager *task_manager, BackgroundTask *task ); ``` La tâche n’est pas annulée automatiquement. ### Supprimer les tâches terminées ```c gsize task_manager_remove_finished( TaskManager *task_manager ); ``` États concernés : ```text COMPLETED FAILED CANCELLED ``` ### Annuler toutes les tâches actives ```c void task_manager_cancel_all( TaskManager *task_manager ); ``` ### Callback de changement ```c void task_manager_set_changed_callback( TaskManager *task_manager, TaskManagerChangedCallback callback, gpointer user_data, GDestroyNotify user_data_destroy ); ``` Le manager possède `user_data` après l’appel. Remplacer le callback existant doit détruire les anciennes données exactement une fois. --- ## 4. Domaine d’erreur Définir : ```c typedef enum { TASK_MANAGER_ERROR_INVALID_ARGUMENT, TASK_MANAGER_ERROR_ALREADY_ADDED } TaskManagerError; ``` Puis : ```c #define TASK_MANAGER_ERROR \ task_manager_error_quark() GQuark task_manager_error_quark(void); ``` --- ## 5. Structure interne recommandée ```c struct TaskManager { GMutex mutex; GPtrArray *tasks; TaskManagerChangedCallback changed_callback; gpointer changed_user_data; GDestroyNotify changed_user_data_destroy; }; ``` `tasks` doit contenir des références `BackgroundTask *`. Configurer le `GPtrArray` avec : ```c background_task_unref ``` comme fonction de destruction. --- ## 6. Notification périodique `BackgroundTask` ne possède pas encore de callback de progression. Pour ce ticket, `TaskPanel` peut rafraîchir périodiquement l’affichage avec : ```c g_timeout_add() ``` fréquence recommandée : ```text 200 à 300 ms ``` `TaskManager` notifie immédiatement les changements structurels. La progression sera relue par le panneau. Une API d’observation plus fine pourra être ajoutée plus tard si nécessaire. --- # Phase B — Tests de `TaskManager` Créer : ```text tests/test_task_manager.c ``` ## Tests minimaux ### Construction Vérifier : ```text manager non NULL compteur initial à zéro ``` ### Ajout Ajouter une tâche et vérifier : ```text compteur à un callback déclenché tâche récupérable référence indépendante ``` ### Doublon Ajouter deux fois la même tâche : ```text FALSE TASK_MANAGER_ERROR_ALREADY_ADDED compteur inchangé ``` ### Retrait Retirer une tâche : ```text TRUE compteur décrémenté callback déclenché ``` ### Retrait inconnu Retirer une tâche absente : ```text FALSE aucun crash ``` ### Nettoyage des tâches terminées Ajouter : - une tâche en attente ; - une tâche terminée ; - une tâche échouée ; - une tâche annulée. Vérifier que seules les tâches terminées sont supprimées. ### Annulation globale Ajouter plusieurs tâches actives et appeler : ```c task_manager_cancel_all() ``` Vérifier que chaque `GCancellable` reçoit une demande d’annulation. ### Durée de vie Vérifier que : - le manager conserve ses références ; - la destruction du manager libère toutes les tâches ; - le remplacement du callback détruit les anciennes données une seule fois. --- # Phase C — `TaskPanel` ## 7. Type opaque Dans : ```text include/widgets/task_panel.h ``` déclarer : ```c typedef struct TaskPanel TaskPanel; ``` API : ```c TaskPanel *task_panel_new( TaskManager *task_manager ); GtkWidget *task_panel_get_widget( const TaskPanel *task_panel ); void task_panel_refresh( TaskPanel *task_panel ); void task_panel_free( TaskPanel *task_panel ); ``` `TaskPanel` ne devient pas propriétaire de `TaskManager`. `TaskPanel` doit rester valide tant que le manager existe. --- ## 8. Interface recommandée Premier rendu simple : ```text ┌──────────────────────────────────────────────────────────┐ │ Activité [ Nettoyer ] │ ├──────────────────────────────────────────────────────────┤ │ Extraction des métadonnées │ │ En cours — 45 % │ │ [████████░░░░░░░░░░] [ Annuler ] │ ├──────────────────────────────────────────────────────────┤ │ Calcul SHA-256 │ │ Terminé │ │ [████████████████████] │ └──────────────────────────────────────────────────────────┘ ``` Widgets GTK possibles : - `GtkBox` ; - `GtkLabel` ; - `GtkProgressBar` ; - `GtkButton` ; - `GtkScrolledWindow`. Ne pas utiliser encore de `GtkListView` si cela complexifie inutilement le ticket. --- ## 9. État visuel Créer une fonction privée traduisant les états : ```text PENDING → En attente RUNNING → En cours COMPLETED → Terminée FAILED → Échouée CANCELLED → Annulée ``` Une tâche en erreur doit afficher son message d’erreur sous forme courte. Une tâche en cours doit afficher son message de progression lorsqu’il existe. --- ## 10. Bouton d’annulation Le bouton `Annuler` doit être visible uniquement pour : ```text RUNNING ``` Son callback appelle : ```c background_task_cancel(task); ``` Le bouton ne doit pas retirer la tâche. --- ## 11. Bouton de nettoyage Ajouter : ```text Nettoyer ``` Il appelle : ```c task_manager_remove_finished() ``` Les tâches actives restent visibles. --- ## 12. Rafraîchissement périodique `TaskPanel` doit enregistrer une source GLib : ```c g_timeout_add() ``` Elle appelle : ```c task_panel_refresh() ``` Lors de `task_panel_free()` : - retirer la source avec `g_source_remove()` ; - empêcher tout callback après destruction ; - ne pas détruire `TaskManager`. --- # Phase D — Intégration GTK ## 13. Ajouter le panneau à `MainWindow` Modifier : ```text include/views/main_window.h src/views/main_window.c ``` Changer la construction : ```c MainWindow *main_window_new( GtkApplication *application, TaskManager *task_manager ); ``` `MainWindow` doit créer : ```c TaskPanel *task_panel; ``` Le panneau peut être placé : - sous la zone de travail ; - dans un volet inférieur ; - ou temporairement dans une colonne latérale secondaire. Pour ce ticket, un volet inférieur sous `GtkPaned` est acceptable. --- ## 14. Ajouter `TaskManager` à `Application` Dans la structure privée : ```c TaskManager *task_manager; ``` Dans `application_new()` : ```c application->task_manager = task_manager_new(); ``` En cas d’échec, nettoyer l’application. Dans `application_on_activate()` : ```c application->main_window = main_window_new( gtk_application, application->task_manager ); ``` Dans `application_free()` : 1. fermer/détruire `MainWindow` ; 2. libérer `TaskManager` après le panneau ; 3. poursuivre le nettoyage existant. L’ordre doit éviter que `TaskPanel` lise un manager déjà détruit. --- # Phase E — Tâche de démonstration ## 15. Ajouter temporairement une tâche de test Pour valider l’interface, ajouter un bouton temporaire : ```text Tâche de test ``` Il lance une `BackgroundTask` qui : - dure environ deux secondes ; - progresse de 0 à 100 % ; - accepte l’annulation ; - retourne un résultat simple. Cette tâche doit être ajoutée au `TaskManager`. Le bouton pourra être supprimé lorsque le premier véritable traitement asynchrone sera disponible. Le code de démonstration doit rester clairement identifié : ```c /* Temporary demonstration task for ticket #035. */ ``` --- # Hors périmètre Ne pas ajouter encore : - de limite de concurrence ; - de priorité ; - de persistance SQLite ; - de reprise après redémarrage ; - d’historique permanent ; - d’exécution de commandes ; - de recherche DNS ; - d’ExifTool ; - de notifications système ; - de tri avancé ; - de pagination. --- # Critères d’acceptation - [x] `TaskManager` est opaque. - [x] `TaskManager` ne dépend pas de GTK. - [x] `TaskManager` protège sa collection avec `GMutex`. - [x] Le manager conserve une référence par tâche. - [x] Une tâche ne peut pas être ajoutée deux fois. - [x] Une tâche peut être retirée. - [x] Les tâches terminées peuvent être nettoyées. - [x] Toutes les tâches actives peuvent être annulées. - [x] Le callback de changement fonctionne. - [x] `TaskPanel` affiche toutes les tâches. - [x] La progression est visible. - [x] L’état est lisible. - [x] Une tâche active peut être annulée. - [x] Les tâches terminées peuvent être supprimées. - [x] Le rafraîchissement périodique est correctement détruit. - [x] `MainWindow` ne devient pas propriétaire du manager. - [x] L’ordre de destruction ne provoque aucun crash. - [x] La tâche de démonstration fonctionne. - [x] `make` réussit. - [x] `make test` réussit. - [x] `git diff --check` ne retourne aucune erreur. --- # Audit attendu Vérifier l’indépendance du manager : ```bash rg -n \ '#include <gtk|sqlite3_|Database|Investigation' \ include/core/task_manager.h \ src/core/task_manager.c ``` Résultat attendu : ```text aucune sortie ``` Vérifier les références : ```bash rg -n \ 'background_task_ref|background_task_unref' \ src/core/task_manager.c ``` Vérifier le rafraîchissement GTK : ```bash rg -n \ 'g_timeout_add|g_source_remove|task_panel_refresh' \ src/widgets/task_panel.c ``` Vérifier l’absence de threads bruts : ```bash rg -n \ 'pthread_|pthread.h' \ include/core/task_manager.h \ src/core/task_manager.c \ src/widgets/task_panel.c ``` Résultat attendu : ```text aucune sortie ``` --- # Fichiers concernés ```text include/core/task_manager.h src/core/task_manager.c tests/test_task_manager.c include/widgets/task_panel.h src/widgets/task_panel.c include/views/main_window.h src/views/main_window.c src/core/application.c Makefile ``` --- # Commit attendu ```bash make clean make make test git diff --check git status --short ``` ```bash git add \ include/core/task_manager.h \ src/core/task_manager.c \ tests/test_task_manager.c \ include/widgets/task_panel.h \ src/widgets/task_panel.c \ include/views/main_window.h \ src/views/main_window.c \ src/core/application.c \ Makefile ``` ```bash git diff --cached --stat git diff --cached ``` ```bash git commit -m "feat(ui): add task manager and activity panel" git push ``` --- # Résultat attendu Après ce ticket, Labfy possédera une infrastructure visible pour tous les futurs traitements longs : ```text Utilisateur ↓ Action GTK ↓ BackgroundTask ↓ TaskManager ↓ TaskPanel ``` Le ticket suivant pourra ajouter le registre des dépendances et lancer les premiers contrôles d’outils externes sans bloquer l’interface.
fy59 closed this issue 2026-07-18 09:01:56 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: fy59/labfy-investigation#37
No description provided.