Commit graph

517 commits

Author SHA1 Message Date
Yohan Boniface
953b37a181 fixup: fix tests 2025-03-27 13:14:20 +01:00
Yohan Boniface
003b25d5e0 fix: import iconUrl as absolute when possible
This will only cover the cases where the icon is set at the map or
at the layer level, not the one of the marker itself.

cf #2552
2025-03-11 16:20:58 +01:00
Yohan Boniface
8599199afa feat: add more users counts in /stats/
Co-authored-by: David Larlet <david@larlet.fr>
2025-03-10 16:38:53 +01:00
Yohan Boniface
1981f73212 feat: expose active sessions in stats endpoint 2025-03-05 10:02:42 +01:00
Yohan Boniface
e919c5f168
fix(sync): make datalayer upsert idempotent (#2528)
That fix does not really fix the original issue, but it makes it
impactless, and I think it's safer anyway to have upsert idempotent.

The pattern to reproduce is:
- peer A create a synced map, add a datalayer, save it
- peer B loads the map, click on edit
- at this time, peer B have twice the datalayer data, once from the
server AND once from the sync

So a better fix would be to make that peer B send a meaningfull HLC to
peer A I guess.
For this we may save the last HLC is the map properties, or maybe try to
merge the "reference_version" and the HLC.
2025-02-27 15:32:09 +01:00
Yohan Boniface
b1076dcb7b
fix: make sure we sync a line when hitting esc while drawing (#2526)
I first tried to handle this on Leaflet.Editable side, to make it fire
the "editable:edited" event we use to trigger the sync, but deciding
what to do with a feature on escape needs some decisions that seems hard
to implement in a generic way in Leaflet.Editable.
We call stopDrawing, which then calls cancelDrawing, so here one need to
decide if cancelDrawing should keep the already drawn line (but cancel
the point being drawn) or cancel everything.
This is why I end up making this change in uMap itself.
2025-02-27 15:26:54 +01:00
Yohan Boniface
b400ade44b fix(sync): make datalayer upsert idempotent
That fix does not really fix the original issue, but it make it impactless.

The pattern is:
- peer A create a synced map, add a datalayer, save it
- peer B loads the map, click on edit
- at this time, peer B have twice the datalayer data, once from the server
  AND once from the sync

So a better fix would be to make that peer B send a meaningfull HLC to
peer A I guess.
For this we may save the last HLC is the map properties, or maybe try
to merge the "reference_version" and the HLC.
2025-02-26 11:55:21 +01:00
Yohan Boniface
9858fc2190 fix: make sure we sync a line when hitting esc while drawing
I first tried to handle this on Leaflet.Editable side, to make
it fire the "editable:edited" event we use to trigger the sync,
but deciding what to do with a feature on escape needs some
decisions that seems hard to implement in a generic way in
Leaflet.Editable.
We call stopDrawing, which then calls cancelDrawing, so here
one need to decide if cancelDrawing should keep the already
drawn line (but cancel the point being drawn) or cancel
everything.
This is why I end up making this change in uMap itself.
2025-02-25 17:17:49 +01:00
Yohan Boniface
5ddd973eae fix: prevent client to open two websocket connections
To reproduce:
- create a map
- saved it
- change the "syncEnabled" setting to on
- save again
- open another tab with this map
- switch on edit mode

In this case, the second client will try to authenticate:
- once switch on edit mode
- and once receiving the operation message from peer A about the
  syncEnabled (which calls render, which calls initSyncEngine in
  in this case)

I think we want to keep render to call initSyncEngine, so if a map
owner switch off the syncEnabled setting, this will (should) disconnect
the other peers.
2025-02-25 08:33:14 +01:00
Yohan Boniface
fcac4df30b
chore: use our contexmenu class for inplace toolbar (#2510)
Some checks failed
Test & Docs / tests (postgresql, 3.10) (push) Has been cancelled
Test & Docs / tests (postgresql, 3.12) (push) Has been cancelled
Test & Docs / lint (push) Has been cancelled
And remove Leaflet.Toolbar dependency.
This also teach ContextMenu how to display icons instead of text and how
to render in horizontal orientation instead of vertical.

Before:

![image](https://github.com/user-attachments/assets/196b17c4-ec6c-4023-b5bf-32033caf4408)

After:


![image](https://github.com/user-attachments/assets/29ad8628-01a6-4028-a99a-bc679c5db18d)

We've lost the bottom tip in the process, should I add this to the
ContextMenu class ?

Also, the automatic border for the focused button is a bit noisy imho,
not sure how to deal with that.
2025-02-14 17:25:13 +01:00
Yohan Boniface
244e637acc
chore: sync save state (#2487)
When a peer save the map, other peers in dirty state should not need to
save the map anymore.

That implementation uses the lastKnownHLC as a reference, but it changes
all dirty states at once. Another impementation could be to have each
object sync its dirty state, but in this case we do not have a HLC per
object as reference, and it also creates more messages.

ping @almet if you're around and wanna have a fresh look. :)
2025-02-14 17:17:59 +01:00
Yohan Boniface
4adc558560 chore: use our contexmenu class for inplace toolbar
And remove Leaflet.Toolbar dependency.
This also teach ContextMenu how to display icons instead of
text and how to render in horizontal orientation instead of
vertical.
2025-02-12 14:59:43 +01:00
Yohan Boniface
c5417178c4 fix: "null" value was not honoured in showLabel field 2025-02-11 11:48:01 +01:00
Yohan Boniface
175e27a535 chore: remove DataLayer._dataloaded in favor of isLoaded()
At the end, we only need two states: has this datalayer loaded the
data it should load ? yes / no.
Whether it local or remote data should not be a matter.
2025-02-10 15:44:41 +01:00
Yohan Boniface
64068af393 fix: do not save "null" instead of null for showLabel 2025-02-07 21:56:02 +01:00
Yohan Boniface
eca7ad4772 fixup: prevent to reload a datalayer after other peer has saved it
The scenario to reproduce is:
- peer A creates a datalayer
- peer B add a marker on that datalayer
- peer B saves the datalayer

Before this fix, after the save, peer A would get a new _referenceVersion
for this datalayer, and the render method would make a hide/show,
which would refetch the data from the server, duplicating it.
So forcing the _loaded to be true in this situation prevent this.

We may want to rework the "_loaded" pattern, maybe with the server
returning in a datalayer metadata the length of the data it get for
this given datalayer, so the client knows if it is worth getting
data for a layer when itself (the client) does not have any.

Co-authored-by: David Larlet <david@larlet.fr>
2025-02-07 17:58:27 +01:00
Yohan Boniface
b8db07a4ce chore: sync save state
When a peer save the map, other peers in dirty state should not need
to save the map anymore.

That implementation uses the lastKnownHLC as a reference, but it changes
all dirty states at once. Another impementation could be to have each
object sync its dirty state, but in this case we do not have a HLC per
object as reference, and it also creates more messages.

Co-authored-by: David Larlet <david@larlet.fr>
2025-02-07 16:47:45 +01:00
Yohan Boniface
ad51f674ef
fix: do not import empty features (#2485) 2025-02-07 15:26:42 +01:00
Yohan Boniface
c5ee9fc283
chore: use editable-edited event to sync changes (#2478)
Some checks are pending
Test & Docs / tests (postgresql, 3.10) (push) Waiting to run
Test & Docs / tests (postgresql, 3.12) (push) Waiting to run
Test & Docs / lint (push) Waiting to run
Test & Docs / docs (push) Waiting to run
This is more unified between markers and paths, and it allows paths to
be synced as soon as they have been drawn (instead of when closing the
edit panel, which created a race condition when changing its properties
that were then synced to other while the feature itself was not).
2025-02-07 09:12:45 +01:00
Yohan Boniface
9af74b0a4e fix: do not import empty features 2025-02-07 09:11:16 +01:00
David Larlet
b214f4109c
fixup: restore help contents and fix button icon
Co-authored-by: Yohan Boniface <yohanboniface@free.fr>
2025-02-06 10:28:05 -05:00
David Larlet
0451b4a882
chore: highlight bar buttons according to open panel
Co-authored-by: Yohan Boniface <yohanboniface@free.fr>
2025-02-06 10:02:32 -05:00
Yohan Boniface
99db1c82f4 chore: move DrawToolbar and SettingsToolbar to bar.js module
This also:
- change the "set center and zoom" to be a panel instead of
  a direct action (including the "defaultView" setting
- refactor the "get started dialog"

This is a first step to remove our dependency to the unmaintained
Leaflet.Toolbar plugin.
2025-02-06 12:26:58 +01:00
Yohan Boniface
79352d8a82 chore: use editable-edited event to sync changes
This is more unified between markers and paths, and it allows paths to
be synced as soon as they have been drawn (instead of when closing the
edit panel, which created a race condition when changing its properties
that were then synced to other while the feature itself was not).
2025-02-04 16:36:14 +01:00
Yohan Boniface
aa25398a62
feat: display a more descriptive alert on invalid geojson error (#2466) 2025-01-31 17:16:44 +01:00
Yohan Boniface
37ecea0799 feat: display a more descriptive alert on invalid geojson error
Co-authored-by: David Larlet <david@larlet.fr>
2025-01-31 17:08:35 +01:00
Yohan Boniface
2162aaf930 fix: only allow to set a map as sync when it is already saved 2025-01-31 15:45:55 +01:00
Yohan Boniface
3e9982c8cb
Sync show usernames (#2444)
Some checks are pending
Test & Docs / tests (postgresql, 3.10) (push) Waiting to run
Test & Docs / tests (postgresql, 3.12) (push) Waiting to run
Test & Docs / lint (push) Waiting to run
Test & Docs / docs (push) Waiting to run
fix #2267
2025-01-31 06:56:46 +01:00
David Larlet
ac607370d0
a11y: include site description within page titles (#2455)
This is not the same as the short `SITE_NAME` which is displayed as the
title of the (home)page for instance.

The plan is to set `SITE_DESCRIPTION` as `uMap OpenStreetMap` for the
OSM instance and `uMap agents publics` for the ANCT one.
2025-01-30 10:45:22 -05:00
David Larlet
44aa914658
a11y: include site description within page titles
This is not the same as the short SITE_NAME which is displayed as the title of the (home)page for instance.
2025-01-30 10:36:31 -05:00
Yohan Boniface
fd8a1971f8 feat: soft delete datalayers
When deleting a datalayer, it will now be moved to a state "deleted", and
it will only be deleted for real when running the command `umap empty_trash`.

This is what we already do for the map itself, but until now if a user
deleted a only a datalayer by mistake (not the map itself) it could not retrieve
it.
2025-01-29 19:08:59 +01:00
Yohan Boniface
70f87d8636 feat: add "accent" mode for tooltip, and use it for peers list
Co-authored-by: David Larlet <david@larlet.fr>
2025-01-27 18:43:36 +01:00
Yohan Boniface
bcd21d3697
feat(forms): add a debounce for Input and Textarea fields (#2445)
fix #2415

I'm a bit afraid this will add more hiccup to the playwright tests,
tough :(
2025-01-27 18:40:11 +01:00
Yohan Boniface
49ea7ed4a5 feat(forms): add a debounce for Input and Textarea fields
fix #2415
2025-01-27 17:25:56 +01:00
Yohan Boniface
d20943a487
feat: move star button to caption (#2442)
fix #2282


![image](https://github.com/user-attachments/assets/45fda270-035b-4ec2-9ac1-3e2f2798663b)
![Screenshot From 2025-01-23
10-42-23](https://github.com/user-attachments/assets/ef323c82-bb12-41ef-97e6-b21dfeef01ba)
2025-01-27 17:18:28 +01:00
Yohan Boniface
250579eaa2 chore: better styling for star button in caption panel
Co-authored-by: David Larlet <david@larlet.fr>
2025-01-27 16:50:27 +01:00
Yohan Boniface
7e42331533 wip(sync): add Redis to CI and configure tests settings 2025-01-23 17:20:21 +01:00
Yohan Boniface
a07ee482ce wip(sync): use our async_live_server for websocket related PW tests
As now both http and ws are on the same domain, let's use one test server
able to serve both.

Co-authored-by: David Larlet <david@larlet.fr>
2025-01-23 17:20:20 +01:00
Yohan Boniface
ab7119e0a4 wip(sync): use Daphne as live_server for tests
Also clean dependencies.

We still use the channels live server for our tests, but do not use it
anymore for the actual websocket handling.
2025-01-23 17:17:13 +01:00
Yohan Boniface
31546d6ff4 wip(sync): use django-channels to serve websockets
Co-authored-by: David Larlet <david@larlet.fr>
2025-01-23 17:16:44 +01:00
Yohan Boniface
48f9afdedd feat: move star button to caption
fix #2282
2025-01-23 11:25:09 +01:00
Yohan Boniface
dc5a3a6b62 fix: test failing due to unstable FS ordering between OS 2025-01-20 21:12:06 +01:00
Yohan Boniface
f53d435dfd
chore: internalize FormBuilder (#2420)
Some checks failed
Test & Docs / lint (push) Has been cancelled
Test & Docs / docs (push) Has been cancelled
Test & Docs / tests (postgresql, 3.10) (push) Has been cancelled
Test & Docs / tests (postgresql, 3.12) (push) Has been cancelled
fix #2280 

That's a first step, which:
- internalize Formbuilder as a bunch of modules
- use Javascript classes instead of Leaflet ones
- remove dependencies to Leaflet (L.DomUtil…)
- replaces `L.FormBuilder` by `Form` (in theory generic, but not quite)
and `U.FormBuilder` by `MutatingForm` (knows about isDirty,
`inheritable` and such)

There is much more room for refactor, but let's do it step by step!
2025-01-11 14:29:55 +01:00
Yohan Boniface
86a8e17aec
fix(sync): handle sync of datalayer delete (#2416)
Some checks are pending
Test & Docs / lint (push) Waiting to run
Test & Docs / docs (push) Waiting to run
Test & Docs / tests (postgresql, 3.10) (push) Waiting to run
Test & Docs / tests (postgresql, 3.12) (push) Waiting to run
fix #2268

There is a tricky choice to do: the delete actually occurs in two
times, first the datalayer is hidden from the UI and set as "deleted"
(this can then be undone) then at next "save" it will totally removed.

When syncing, given we removed the "reset/undo" feature for now, and
because it was simpler, I decide to do both step in once.

When working on a proper "undo/redo", we may challenge this choice
again.
2025-01-10 16:34:47 +01:00
Yohan Boniface
75af1a4855 fix(sync): handle sync of datalayer delete
fix #2268

There is a tricky choice to do: the delete actually occurs in two
times, first the datalayer is hidden from the UI and set as "deleted"
(this can then be undone) then at next "save" it will totally removed.

When syncing, given we removed the "reset/undo" feature for now, and
because it was simpler, I decide to do both step in once.

When working on a proper "undo/redo", we may challenge this choice
again.
2025-01-10 16:33:46 +01:00
Yohan Boniface
0c52c35ae3 chore(tests): use name from data when defined in DataLayerFactory 2025-01-10 16:33:06 +01:00
Yohan Boniface
49cde00361
feat: display map's "created at" and "modified at" in the caption (#2424)
fix #2110 


![image](https://github.com/user-attachments/assets/a7db6197-4cc6-417e-b480-8e1434d73687)
2025-01-10 16:23:42 +01:00
Yohan Boniface
e7fe92c070 feat: display map's "created at" and "modified at" in the caption 2025-01-10 15:49:05 +01:00
Yohan Boniface
92b7be3ad9 fix: update map.modified_at when saving a datalayer
fix #2421
2025-01-10 12:01:13 +01:00
Yohan Boniface
fb4fecd337 chore(tests): fix sync tests 2025-01-09 13:00:59 +01:00