Skip to content

Many enhancements: node/edge editing, formula columns, selection panel, Github check before save, mobile UX & pre-production CI... - #332

Open
JeanGarf wants to merge 320 commits into
gephi:mainfrom
JeanGarf:main_jg
Open

Many enhancements: node/edge editing, formula columns, selection panel, Github check before save, mobile UX & pre-production CI...#332
JeanGarf wants to merge 320 commits into
gephi:mainfrom
JeanGarf:main_jg

Conversation

@JeanGarf

@JeanGarf JeanGarf commented Aug 4, 2026

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 (d906a95627860e)

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

  • Warn before editing a GitHub file that has become stale, checked as soon as the create/edit popup opens

  • Re-arm the freshness check every ~1 minute (down from 5) and re-check before every save

  • Fix a save deadlock and add an "Overwrite" button to the conflict popup

  • Save-conflict popup: all 3 buttons visible on mobile, "Keep" selected by default

  • Fix a reload loop (the internal reference date wasn't refreshed after Reload)

  • Disable the HTTP cache on gist reads (getFile / getFileContent)

  • Fix a freshness false positive: memorize the open date from the same detail endpoint used by the periodic checks, instead of the list endpoint; add a 1s tolerance to absorb transient GitHub timestamp inconsistencies

  • Stop flagging a remote change that isn't one (real content comparison, not date alone)

  • Fix the two remaining root causes of false "modified on GitHub" alerts: fingerprint mismatch between sent and remote-returned bytes, and an un-persisted "keep my changes" acknowledgment causing repeated re-warnings

  • Open from GitHub: the last opened file is now really preselected (not just visually), so "Open" works immediately

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

  • Fix Escape not closing the node/edge create/edit popups

  • Confirm before losing unsaved input when closing the editor (Back button, Escape, click-outside, and both close crosses all go through the same confirmation)

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"

  • Fix the Label caption for scripted attributes: back to a plain fixed "Label" instead of computing it from the current display label (Appearance)

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
  • Visualize the shortest path between two selected nodes
  • Long-press to add a node or edge to the selection (touch equivalent of Ctrl-click)
  • Mobile: fold the selection panel without losing the selection
  • Selection panel: toggle between alphabetical and size sort, persisted per item type

Search

  • Made the main fuzzy search robust to involuntary focus loss on Android
  • Fixed the clear cross not closing the results list on Windows, and made it reappear automatically on Android
  • Touch-friendly fuzzy search, persistent results, browser autocomplete hidden
  • Clear cross: focus returned to the field, and the cross always visible
  • Persistent fuzzy search text and clearable fields in the editor
  • Pre-fill node/edge creation with the text typed in the fuzzy search
  • Close the results dropdown when another panel or popup takes its place (it used to keep floating on top)

Data tables

  • Locate a node/edge by clicking from the data tables
  • Add Source/Target label columns [In data view, edge mode, Create column Source Label and Target Label #320 ] and move ID columns to the end (edge view, then node view)
  • Search edges by source/target labels, not just internal IDs
  • Keyboard navigation between cells, plus a cancel button
  • Align the number field's stepper with the check button, not the cross

Filters

  • Reorder the filters panel and support scripted attributes as filterable
  • Fix the displayed From/To range-filter placeholder values
  • Add a "Based on filtered values" checkbox for size min/max interpolation
  • Left panel: clarify when filters are active
  • Make filtered items readable and consistent everywhere (funnel icon, selection, dimmed rendering)
  • A filtered edge also dims both its endpoints

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
  • Add a "+" button to create a node directly from the bottom bar, between the panel-close button and "Graph"

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)
  • Show the build commit hash and date below the version number in the About popup, so the running version can be checked at a glance

claude and others added 30 commits July 15, 2026 17:36
Les attributs scriptés deviennent des colonnes "formule" dont le script est
stocké dans le FieldModel (donc persisté avec le dataset) et dont les valeurs
sont recalculées à la volée par le pipeline des attributs dynamiques.

- SDK : ajout de FieldModel.script (FieldScriptFunction), sérialisé
  automatiquement grâce au support des fonctions dans gephiLiteStringify.
- dynamicItemDataAtom évalue aussi les champs script du modèle : recalcul au
  chargement, à l'édition d'un nœud/arête, au changement de topologie ou de
  script. Une erreur de script laisse la cellule vide sans tout interrompre.
- Le menu "scripted attribute" stocke désormais le script au lieu de figer les
  valeurs, avec un mode édition pour re-modifier le script.
- Table de données : colonnes formule en lecture seule, le menu de colonne
  "modifier" rouvre l'éditeur de script.
- Les champs script sont exclus des formulaires de création/édition de
  nœud/arête et d'édition multiple (ils sont calculés).
# Conflicts:
#	packages/gephi-lite/src/components/data/EditEdge.tsx
#	packages/gephi-lite/src/components/data/EditMultipleItems.tsx
#	packages/gephi-lite/src/components/data/EditNode.tsx
#	packages/gephi-lite/src/core/graph/index.ts
#	packages/gephi-lite/src/views/dataPage/dataTable/useDataTableColumns.tsx
#	packages/sdk/src/graph/types.ts
À l'export GEXF, les valeurs calculées des champs "formule" (script) sont
désormais écrites comme attributs statiques sur le graphe exporté, afin
d'apparaître dans le fichier GEXF.

Cette matérialisation ne modifie que le graphe d'export construit à la volée
par dataGraphToFullGraph : le dataset, les définitions de formule et la
sauvegarde native .gephi-lite restent inchangés.
Sur mobile (< 576px), sélectionner un item déploie un panneau qui prend 50% de
la hauteur ; la zone graphe (.filler) rétrécit via une transition CSS. Comme le
bouton "Localiser" fait select() puis focus() de façon synchrone, le cadrage
était calculé sur la bande pleine hauteur (avant déploiement du panneau), puis
le panneau recouvrait la moitié basse.

focusCameraOnEdges attend désormais que la zone graphe se stabilise avant de
cadrer, pour tenir compte du panneau. Sur desktop rien ne change (la bande est
déjà stable, le cadrage est immédiat).

Correctif candidat à valider sur un vrai appareil Android.
Les navigateurs mobiles (Android, iOS) n'affichent pas les spin buttons natifs
de <input type="number">, laissant les champs numériques sans moyen visible
d'incrémenter/décrémenter.

Ajout d'un composant NumberInput ([−] champ [+]) utilisé par l'éditeur numérique
(table de données, formulaires de création/édition, valeur par défaut…). Les
spin buttons natifs sont masqués en CSS pour éviter les doublons sur desktop :
le stepper est ainsi identique sur toutes les plateformes.
Nouvelle chaîne d'intégration continue (deploy-app-preprod.yml) déclenchée à
chaque push sur develop : build de l'app puis déploiement dans la branche
gh-pages sous le sous-chemin /preprod/, à côté de la production (déployée depuis
main_jg à la racine). La prod n'est jamais touchée (clean: false, écriture sous
preprod/ uniquement) ; analytics Matomo désactivé sur la préprod.

URLs :
- prod    : https://jeangarf.github.io/gephi-lite/          (main_jg)
- préprod : https://jeangarf.github.io/gephi-lite/preprod/  (develop)

Ajout d'un bandeau "PRÉ-PRODUCTION" (PreproductionBanner) affiché uniquement
quand l'app est buildée avec VITE_PREPRODUCTION (défini par ce workflow), pour
distinguer visuellement l'instance de préprod de la prod.
Dans le tableau des nœuds, un clic sur l'aperçu d'un nœud le localise
(bascule vers le graphe, sélectionne ce seul nœud et recentre la caméra
dessus). Dans le tableau des edges, un clic sur le nœud source ou cible
localise ce nœud, et un clic sur le trait/la flèche au milieu localise
l'edge.

- Nouveau hook partagé useLocateInGraph (locateNode/locateEdge, option
  navigateToGraph) ; le volet de sélection est refactoré pour le
  réutiliser au lieu de dupliquer la logique.
- NodeComponentById/EdgeComponentById acceptent une prop locatable ;
  EdgeComponent gère un clic sur le milieu (onEdgeClick). Style de bouton
  « localiser » mutualisé (.gl-locate-button).
- Recentrage différé après navigation (requestFocusOnReady /
  consumePendingFocus) : on attend que sigma ait dimensionné le conteneur
  et cadré le graphe, sinon la caméra visait une zone vide.
…urs existantes a l'ajout d'une nouvelle categorie
Sinon leur ordre dans le volet de sélection suit celui, arbitraire, du Set
de sélection, ce qui rend une sélection multiple difficile à parcourir.
…bile)

Le bouton « Show in Graph » du tableau des edges passait par fitViewportToNodes
(cadrage sur tout le canvas), alors que le bouton « Zoom on all selected edges »
du volet passait par notre cadrage conscient de la bande visible (.filler). D'où,
sur mobile, des edges cadrés derrière le volet de sélection, et un niveau de zoom
différent entre les deux entrées.

Les deux chemins passent désormais par focusCameraOnNodes (cadrage band-aware +
surbrillance), réutilisé par focusCameraOnEdges. L'attente runWhenReadyToFrame
combine bande stabilisée et graphe rendu (relit le sigma vivant à chaque frame),
donc le cadrage est correct aussi bien depuis le volet (déjà monté) que depuis le
tableau (navigation puis montage).
Deux corrections dans getCameraStateToFrameNodes :
- La largeur du label (fixe, non scalée) n'est désormais réservée que pour les
  nœuds situés à droite du centre (le label s'affiche à droite du nœud). La
  réserver pour tous, y compris les nœuds à gauche dont le label s'étend vers
  l'intérieur, sur-contraignait le zoom et dézoomait énormément sur une bande
  étroite (mobile) — d'où « on ne voit presque plus le graphe » sur une sélection
  d'edges étalée (un edge seul, 2 nœuds proches, n'était pas affecté). La réserve
  est aussi plafonnée pour qu'un label très long ne puisse pas écraser le zoom.
- Garde-fou : cadrer un sous-ensemble de nœuds ne doit jamais dézoomer au-delà de
  l'affichage du graphe entier. On calcule le zoom qui fait tenir tous les nœuds
  rendus dans la bande et on ne dézoome jamais en deçà.
JeanGarf and others added 30 commits August 11, 2026 19:03
Icône play/stop sous Réseau mixte pour la dernière spatialisation
Déplace l'icône play/stop de la dernière spatialisation à côté du bouton Data
On small viewports (Android), the deployed side panel covers most of
the screen height, but the floating sigma controls (zoom, selection
mode...) are pinned to the viewport bottom-right and end up rendered
above it, overlapping the panel footer buttons (e.g. layout Play/Stop).
…026-822a-f3252d375bbc

Fix: bouton + de zoom masqué par le bouton Play/Stop sur mobile
Déplace l'icône Play/Stop à gauche du bouton de thème
Conserve Graph/Data en anglais en mode français
…n volet est déployé sur mobile, icône Play/Stop à gauche du bouton de thème, termes Graph et Data conservés en anglais en mode français
…églages d'apparence, et met à jour toutes les traductions
…t densité des labels dans les réglages d'apparence
…par écran

Le seuil de taille utilisé jusqu'ici s'annulait au zoom : les nœuds
grossissant en pixels, de plus en plus d'entre eux le franchissaient, et la
grille interne de sigma (construite dans un espace indépendant de la caméra)
autorise `labelDensity / ratio²` libellés par cellule, ce qui encombre
l'écran à fort zoom.

Les libellés de nœuds sont désormais choisis à chaque image parmi les nœuds
visibles : les plus gros d'abord, répartis sur le viewport grâce à une grille
d'environ autant de cellules que de libellés autorisés, dont seul le meilleur
candidat est retenu. Les ex-aequo de taille (cas courant des tailles
uniformes) sont ainsi distribués sur la zone visible, puis départagés par le
libellé déjà affiché (limite le clignotement), le degré, puis l'identifiant.

Le réglage d'apparence devient un nombre de libellés affichés (15 par
défaut), exprimé pour un écran de taille standard et ramené à la surface
réellement disponible, pour qu'un écran de téléphone ne soit pas aussi chargé
qu'un écran de bureau. Il ne concerne que les nœuds, seul cas où il avait un
effet.

Ajoute enfin une taille minimale de rendu des libellés, pour que les petits
nœuds restent lisibles, notamment les voisins minuscules d'un nœud survolé.
…t visible

Sur Android, le budget tombait à 3 libellés pour 15 configurés : il était
proportionnel à la *surface* de l'écran, ce qui divise par cinq sur un
téléphone. Il suit désormais la taille *linéaire* (racine du rapport des
surfaces), soit environ 7 libellés sur un téléphone et 15 sur un écran de
bureau.

Le canvas de sigma s'étend sous l'en-tête et sous les panneaux : les libellés
choisis dans ces zones étaient dessinés derrière eux, invisibles, et
consommaient le budget. Le budget comme la sélection se calent donc sur la
bande réellement dégagée (".filler"), dont le calcul est factorisé avec le
cadrage de la caméra, et un ResizeObserver redemande un rendu quand un
panneau s'ouvre ou se ferme.

Enfin, la marge de 50 px devient intérieure : un nœud trop près du bord n'est
plus éligible, au lieu d'être éligible jusqu'à 50 px en dehors de l'écran, ce
qui affichait des libellés tronqués.
Le nombre configuré était ramené à la taille de l'écran : sur un téléphone,
demander 10 libellés n'en affichait que 5 ou 6, quel que soit le zoom, ce qui
contredit un réglage exprimé en nombre. La mise à l'échelle est supprimée :
un téléphone affiche autant de libellés qu'un écran de bureau, simplement
plus resserrés, et le réglage reste libre de les réduire.
…ros nœuds de la zone visible, répartis), réglage du nombre de libellés affichés et taille minimale de rendu
Le libellé étant écrit à droite de son nœud, les côtés ne sont pas
équivalents : à gauche, un nœud qui entre dans l'écran a d'emblée tout son
libellé visible, d'où une marge nulle ; à droite, la marge passe de 50 à
25 px, ce qui rend éligibles des nœuds jusque-là écartés sans que leur
libellé devienne illisible pour autant.

Documente également le retour sur `develop` après chaque propagation en
production.
…texte

La marge de 50 px, héritée du côté droit, écartait sans raison des nœuds
proches des bords supérieur et inférieur : seule la hauteur du texte compte
là, et non la longueur du libellé. Elle est donc calculée à partir de la
géométrie de rendu de sigma (ligne de base à un tiers de la taille de police
sous le centre du nœud, jambages descendants jusqu'à 0,3 de plus), pour la
plus grande taille de libellé attendue, soit 16 px.

Les ratios de cette géométrie, jusqu'ici codés en dur dans la détection du
clic sur un libellé, sont partagés entre les deux usages.
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.

2 participants