Skip to content

Fork feature update: node/edge editing, formula columns, selection panel, mobile UX & pre-production CI#327

Open
JeanGarf wants to merge 155 commits into
gephi:mainfrom
JeanGarf:develop
Open

Fork feature update: node/edge editing, formula columns, selection panel, mobile UX & pre-production CI#327
JeanGarf wants to merge 155 commits into
gephi:mainfrom
JeanGarf:develop

Conversation

@JeanGarf

Copy link
Copy Markdown

Pull request type

Check the type of change your PR introduces:

  • Bugfix
  • Feature
  • Code style update (formatting, renaming)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Documentation content changes
  • Other (please describe):

Summary of changes (d906a959db74cb)

This range covers the full set of changes accumulated on this fork since the base commit, spanning many feature/fix branches merged into develop and periodically promoted to main_jg.

Save & session

  • Fix GitHub file being overwritten after creating a new workspace (Critical Bug)

  • Add a save icon next to "Workspace", greyed out until there are unsaved changes

  • Persist session settings (layout & metrics parameters) together with the graph

Node & Edge editing

  • Avoid Gephi Lite to crash when deleting an Edge [Deleting Edge makes Gephi lite to crash #318] (critical bug)

  • Prevent creation of duplicate nodes/edges

  • Support changing edge extremities (source/target) via updateEdge, add a swap button in the edit form, and an "Invert arrow's direction" menu item [Add button to invert Source and Target of an Edge #321 ]

  • Pre-fill default attribute values on node/edge creation [Default value for attributes #326 ]

  • Auto-focus the first empty field in node/edge modals

  • Numeric attributes: cross-platform +/− stepper

  • Add a validation button in the modal header and duplicate the OK button in the modal footer (espacially for Android)

  • Fix edge weight resetting to 1 on creation [weight field is reseted to 1 #322 ]

  • Move ID field to the end of node/edge create/edit forms and data columns; move x/y position fields to the end of the edit form

Formula (scripted) columns & data columns

  • Scripted columns: persisted script, live recompute, editable label, and a "Freeze values" action to materialize computed values into a static attribute

  • Add automatic "Update Date" / "Creation Date" columns, with backfill for graphs already loaded in session

  • GEXF export now materializes formula column values

  • Rename "Delete attribute" → "Delete column"; rename "Identifier" → "ID"

Selection panel & Graph view

  • Add a title and selected-item count to the selection panel;
  • Make selected nodes/edges clickable to locate them
  • Click a node's label to locate it;
  • Add quick-action icons (locate, select neighbors, edit, invert direction, delete);
  • Add icons to create an edge from a node and select a node's edges
  • Sort selected edges by source, target, then label; show only endpoint labels for a selected edge and refocus dimming on it
  • Improve camera framing when locating an edge; unify multi-edge zoom between table and panel (mobile-aware); fix excessive zoom-out on multi-node framing
  • Scroll the selection panel to top after locating an item

Data tables

Color palette

  • Sort the color legend alphabetically and keep existing colors when a new category is added
  • Remove obsolete categories from the palette; sync the palette when data changes, not only when fields change

Mobile & navigation

  • Add mobile header with node/edge creation icons; expand the Workspace toolbar by default on mobile
  • Fix the Layout submenu appearing unexpectedly on mobile
  • Android Back button closes the popup instead of navigating; prevent Back from popping Graph/Data views or exiting the app with unsaved work; warn before leaving the app with unsaved changes

Default labels

  • Use ID as the default label for nodes/edges; don't show the ID when "No label" is selected

Pre-production banner & CI

  • Add CI deployment of pre-production to GitHub Pages from develop; configure GitHub Pages for this fork; grant contents:write permission to the deploy workflow
  • Move the pre-production banner to the top of the graph; detect preprod via URL

Misc / internal

  • Factor the duplicated data-creation menu into a shared constant; add it to the Graph view above Spatialisation [Data Creation Menu also on Graph View #319 ]
  • Refresh the filtered graph cache on node/edge data changes, not only on fullGraph reference changes
  • Documentation: factoring rule (avoid divergent behavior across call sites) and feature-branch sync rule (merge --no-ff)

JeanGarf and others added 30 commits July 13, 2026 01:27
…ion, delete) to the graph view selection panel

Reuses the existing Data view icon buttons for the per-item panel in the Graph view, adds a select-neighbors button for nodes and an invert-direction button for edges, placed just above the attribute list.
Keeps it consistent with the Node ID/Edge ID column already moved to the end in the data table views.
# Conflicts:
#	packages/gephi-lite/src/views/graphPage/Selection.tsx
Remove the CNAME pointing to the upstream lite.gephi.org domain,
switch redirect URLs to relative paths, trigger deploy-app on
push to main_jg instead of main (kept in sync with upstream),
and disable the automatic Docker Hub publish workflow.
- Nouvelle icône dans le volet de sélection d'un nœud ouvrant le formulaire
  de création d'edge avec ce nœud pré-rempli comme source et le focus placé
  sur le champ cible.
- Support d'un prop autoFocus dans GraphSearch.
- Correction d'un crash latent : le rendu d'un item de sélection était tenté
  avant que le dataset ait rattrapé la sélection (fenêtre transitoire après
  création), provoquant un accès sur des données undefined. Le rendu est
  désormais ignoré pour ce frame et se corrige au rendu suivant. Les deux
  listes partagent le même renderItem factorisé.
- Traductions create_edge_from_node ajoutées (dev, en, fr, hu, ko, uk).
Lors de la sélection d'un ou plusieurs edges, les nœuds source et cible
sont désormais mis en avant (labels forcés) et tous les autres nœuds sont
estompés avec leur label masqué, de la même façon que lors de la sélection
d'un nœud.
claude and others added 30 commits July 19, 2026 12:23
Les deux blocs Nodes/Edges se retrouvaient empilés au lieu d'être côte à
côte, car le panneau (largeur fixe 256px) était trop étroit pour deux
colonnes de largeur minimale 8rem avec retour à la ligne. En passant
chaque colonne en flex égal (au lieu d'une largeur minimale fixe), les
deux colonnes tiennent désormais côte à côte.

Le type de graphe (ex : "Réseau mixte") est déplacé de son emplacement
au-dessus des compteurs vers la colonne Nodes, juste sous la date du
nœud le plus récent : il se retrouve ainsi sur la même ligne que la
cible du lien le plus récent dans la colonne Edges.
…de nœud/lien

Sur mobile, le clavier virtuel peut recouvrir le bouton de validation
situé en bas de la modale pendant la saisie d'un champ. Le composant
Modal partagé accepte désormais un prop submitLabel : quand il est
fourni, un bouton de soumission est affiché dans l'en-tête, à gauche de
la croix de fermeture, toujours visible au-dessus du clavier.

Pour l'édition de nœud et de lien, ce bouton (libellé "OK") remplace
celui du pied de la modale, qui reprenait jusqu'ici le texte du titre
("Edit existing node"/"Create new node", etc). Le panneau latéral de
création (Data page), qui réutilise le même formulaire hors modale,
garde inchangé son bouton de soumission en pied de panneau.
…ran, et fiabiliser le bandeau pré-production

1) Le bouton "OK" des modales d'édition de nœud/lien apparaît maintenant
   aussi en pied de modale (en plus de l'en-tête), placé à gauche de la
   croix d'annulation pour rester homogène avec l'en-tête.

2) L'icône du bouton plein écran des contrôles du graphe reprend
   désormais le glyphe de l'icône "Localiser", pour rester homogène
   avec les boutons de localisation ailleurs dans l'application. Le
   bouton garde sa fonction (bascule plein écran) inchangée.

3) Le bandeau "PRÉ-PRODUCTION" dépendait uniquement d'une variable
   positionnée par la CI/CD, donc invisible en développement local. La
   valeur est maintenant stockée dans packages/gephi-lite/.env ("true"
   sur cette branche), un fichier suivi par git, propre à chaque branche
   longue (develop / main_jg), qui prend effet aussi en local sans CI/CD.
   La variable CI/CD redondante a été retirée du workflow de préprod.
1) L'icône "Localiser" avait été appliquée au mauvais bouton (plein
   écran au lieu du bouton "Voir tout le graphe"/reset zoom). Le bouton
   plein écran retrouve son icône d'origine ; c'est le bouton de reset
   zoom qui reprend désormais le glyphe de l'icône Localiser. Aucun des
   deux ne change de fonction.

2) Le bandeau "PRÉ-PRODUCTION" ne dépend plus d'un fichier .env par
   branche (source d'erreur lors des merges/CI), mais détecte
   simplement si l'URL de déploiement contient "/preprod/", ce que le
   workflow de déploiement pré-production est seul à produire. Plus
   robuste et sans configuration à synchroniser entre branches.
…raphe

Les paramètres des algorithmes de layout (et de métriques) vivaient
uniquement dans l'atom "session", persisté dans le sessionStorage du
navigateur (propre à l'onglet, vidé à sa fermeture) et absent du format
de fichier gephi-lite. Ils étaient donc perdus au rechargement, à la
sauvegarde/réouverture ou au partage du fichier.

La session est désormais incluse dans GephiLiteFileFormat : sérialisée à
l'export et restaurée à l'ouverture d'un fichier gephi-lite. Aucun
obstacle technique : le sérialiseur maison (gephiLiteStringify) gère déjà
les fonctions (paramètres de type script), Sets et graphes — c'est le
même que celui utilisé pour le sessionStorage.

- Le champ session est optionnel dans le format : les fichiers exportés
  avant cette évolution n'en ont pas, et sont ouverts sans erreur (la
  session de l'onglet courant est alors conservée).
- Ajout d'un producer setFullState à sessionActions, sur le modèle de
  appearanceActions.setFullState.
…les valeurs »

1) Le formulaire de création/édition d'un attribut scripté permet
   désormais de saisir un Label (en plus de l'ID), pour renommer
   l'en-tête de colonne. Au-dessus du champ, une ligne informative
   (lecture seule) rappelle quel attribut sert actuellement de label
   d'affichage dans Appearance (« Set label from… »). Le Label saisi
   apparaît automatiquement dans l'en-tête de colonne ET dans le
   sélecteur « Set label from… » (via field.label || field.id).

2) Le menu d'une colonne de type script propose une action « Figer les
   valeurs » : une pop-up de confirmation prévient que le script sera
   supprimé et les valeurs figées (non recalculables). Si confirmé, la
   colonne devient un attribut normal, éditable, dont les valeurs
   courantes (recalculées sur tout le graphe) sont stockées en statique.
…les attributs scriptés

- graph.model.field.id : "Identifier"/"Identifiant" -> "ID" (formulaires
  de création d'attribut, normal et scripté).
- Formulaire d'attribut scripté : au lieu d'une ligne informative séparée
  ("Current display label (Appearance): ...") suivie du caption "Label",
  le caption du champ Label est directement le nom du label d'affichage
  actuel (ex : "label", ou "No label" si aucun n'est configuré) — pour
  Nodes comme pour Edges.
…un simple "Label" fixe (comme pour un attribut standard), au lieu de le calculer d'après le label d'affichage courant (Appearance).
…rche fuzzy

Le texte actuellement saisi dans le champ de recherche fuzzy ("Search nodes, edges") est maintenant réutilisé pour initialiser :
- le champ Label (ou l'ID en l'absence de champ Label configuré) lors de la création d'un nouveau Node,
- le champ Source lors de la création d'un nouvel Edge (texte de recherche pré-rempli, sans présélectionner de nœud).

Ce comportement s'applique aussi bien aux boutons + du panneau de gauche qu'au menu "Create new node"/"Create new edge", via un nouvel atome partagé (searchQueryAtom) lu directement par les formulaires, sans duplication de logique entre les deux points d'entrée.
…Node ou Edge

Deux causes cumulées :
- useKeyboardShortcuts ignorait tout raccourci (y compris Escape) dès que le focus était dans un champ texte, alors que ce garde-fou ne devrait viser que les raccourcis lettre, pas Escape qui est la touche universelle d'annulation.
- Les modales Node/Edge n'avaient pas le flag doNotPreserveData, ce qui bloquait volontairement la fermeture par Escape/clic extérieur alors que les boutons Annuler/X ferment déjà sans confirmation : Escape est maintenant aligné sur ce même comportement.
Lors de l'ouverture d'un graphe depuis GitHub, la date du fichier distant et son origine "zone réseau" sont déjà mémorisées dans le fichier courant (type "cloud" + updatedAt).

À la 1ère modification après ouverture/sauvegarde (transition propre→modifié, quand l'étoile isDirty s'allume), on interroge GitHub : si la version distante est plus récente que celle mémorisée (donc modifiée entre-temps par un autre utilisateur ou une autre session), une popup de warning propose de recharger la version à jour (les modifs locales sont alors perdues) ou de conserver ses modifications.

Le check ne se fait qu'à cette transition (pas à chaque édition) pour limiter les appels réseau et ne pas harceler l'utilisateur ; après une sauvegarde, le fichier courant est mis à jour avec la nouvelle date distante afin que la prochaine modification ne déclenche pas de faux positif sur notre propre sauvegarde.

- useRemoteFileGuard : hook branché dans Initialize, détecte la transition et gère le check + la popup.
- useCloudProvider.saveFile : met à jour le fichier courant (donc la date de référence) après sauvegarde.
- ConfirmModal : n'émet plus de toast de succès vide quand aucun successMsg n'est fourni (le guard gère sa propre notification de rechargement).
…e création/édition

Jusqu'ici la vérification ne se déclenchait qu'à la validation (transition propre→modifié) : l'utilisateur remplissait la popup puis apprenait au moment de valider que le graphe n'était pas à jour, et perdait toute sa saisie s'il rechargeait.

Désormais la vérification est aussi déclenchée à l'ouverture de la popup de création/édition d'un node ou d'un edge (EditNodeModal / EditEdgeModal), de sorte que l'avertissement apparaît AVANT que l'utilisateur ne remplisse le formulaire.

- La logique de check est extraite dans un hook réutilisable useRemoteFileFreshnessCheck, partagé entre le guard (transition propre→modifié, pour les modifs hors popup : layout, métriques, apparence, filtres, édition directe dans la table...) et les popups (à leur ouverture).
- Un verrou partagé garantit un seul appel réseau par « base propre » (jusqu'à la prochaine ouverture/sauvegarde/rechargement) : pas de double check popup+validation, pas de harcèlement. Le verrou est ré-armé à chaque changement de fichier courant.
- Le check est non bloquant (fire-and-forget) : si GitHub est injoignable (mode avion, réseau indisponible), la popup s'ouvre normalement, aucun avertissement n'est affiché et l'utilisateur peut modifier le graphe sans être gêné (le verrou est relâché pour permettre une nouvelle tentative ultérieure).
…ifier avant chaque sauvegarde

Ré-armement périodique :
- Le verrou "déjà vérifié" devient une fenêtre temporelle (~5 min) au lieu d'un simple booléen : passé ce délai, la prochaine sollicitation (ouverture de popup, 1ère modification) re-vérifie.
- Un timer relance en plus la vérification toutes les ~5 min, de sorte qu'une longue session d'édition continue de détecter une mise à jour distante même sans action de l'utilisateur.

Re-vérification avant sauvegarde :
- Au moment du Save, AVANT d'écrire sur GitHub, on re-interroge le distant (checkBeforeSave, sans tenir compte de la fenêtre). Si la version distante est plus récente, la sauvegarde est annulée et l'avertissement (recharger / conserver) est affiché — on n'écrase jamais un fichier plus récent.
- Si la vérification échoue (hors-ligne...), la sauvegarde est laissée passer (elle échouera d'elle-même si le réseau est coupé) : jamais bloquée par un pré-check en erreur.

La logique est factorisée dans useRemoteFileFreshnessCheck qui expose check() (passif, non bloquant) et checkBeforeSave() (bloquant, à la sauvegarde).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants