mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 03:42:37 +02:00
feat(sync): Add a enableSync
option.
This changes how the syncEngine works. At the moment, it's always instanciated, even if no syncing is configured. It just does nothing. This is to avoid doing `if (engine) engine.update()` calls everywhere we use it. You now need to `start()` and `stop()` it.
This commit is contained in:
parent
9a74cc370c
commit
5e692d2280
8 changed files with 60 additions and 28 deletions
|
@ -1,8 +1,9 @@
|
|||
import { translate } from './i18n.js'
|
||||
|
||||
// Possible impacts
|
||||
// ['ui', 'data', 'limit-bounds', 'datalayer-index', 'remote-data', 'background']
|
||||
// ['ui', 'data', 'limit-bounds', 'datalayer-index', 'remote-data', 'background' 'sync']
|
||||
|
||||
// This is sorted alphabetically
|
||||
export const SCHEMA = {
|
||||
browsable: {
|
||||
impacts: ['ui'],
|
||||
|
@ -14,6 +15,12 @@ export const SCHEMA = {
|
|||
label: translate('Do you want to display a caption bar?'),
|
||||
default: false,
|
||||
},
|
||||
captionControl: {
|
||||
type: Boolean,
|
||||
nullable: true,
|
||||
label: translate('Display the caption control'),
|
||||
default: true,
|
||||
},
|
||||
captionMenus: {
|
||||
type: Boolean,
|
||||
impacts: ['ui'],
|
||||
|
@ -184,7 +191,6 @@ export const SCHEMA = {
|
|||
type: Boolean,
|
||||
impacts: ['ui'],
|
||||
},
|
||||
|
||||
interactive: {
|
||||
type: Boolean,
|
||||
impacts: ['data'],
|
||||
|
@ -373,12 +379,6 @@ export const SCHEMA = {
|
|||
impacts: ['ui'],
|
||||
label: translate('Allow scroll wheel zoom?'),
|
||||
},
|
||||
captionControl: {
|
||||
type: Boolean,
|
||||
nullable: true,
|
||||
label: translate('Display the caption control'),
|
||||
default: true,
|
||||
},
|
||||
searchControl: {
|
||||
type: Boolean,
|
||||
impacts: ['ui'],
|
||||
|
@ -437,6 +437,13 @@ export const SCHEMA = {
|
|||
inheritable: true,
|
||||
default: true,
|
||||
},
|
||||
syncEnabled: {
|
||||
type: Boolean,
|
||||
impacts: ['sync', 'ui'],
|
||||
label: translate('Enable real-time collaboration'),
|
||||
helpEntries: 'sync',
|
||||
default: false,
|
||||
},
|
||||
tilelayer: {
|
||||
type: Object,
|
||||
impacts: ['background'],
|
||||
|
|
|
@ -8,16 +8,31 @@ import {
|
|||
} from './updaters.js'
|
||||
|
||||
export class SyncEngine {
|
||||
constructor(map, webSocketURI, authToken) {
|
||||
constructor(map) {
|
||||
this.map = map
|
||||
this.receiver = new MessagesDispatcher(this.map)
|
||||
|
||||
this._initialize()
|
||||
}
|
||||
_initialize() {
|
||||
this.transport = undefined
|
||||
const noop = () => undefined
|
||||
// by default, all operations do nothing, until the engine is started.
|
||||
this.upsert = this.update = this.delete = noop
|
||||
}
|
||||
|
||||
start(webSocketURI, authToken) {
|
||||
this.transport = new WebSocketTransport(webSocketURI, authToken, this.receiver)
|
||||
this.sender = new MessagesSender(this.transport)
|
||||
|
||||
this.upsert = this.sender.upsert.bind(this.sender)
|
||||
this.update = this.sender.update.bind(this.sender)
|
||||
this.delete = this.sender.delete.bind(this.sender)
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.transport) this.transport.close()
|
||||
this._initialize()
|
||||
}
|
||||
}
|
||||
|
||||
export class MessagesDispatcher {
|
||||
|
|
|
@ -19,4 +19,8 @@ export class WebSocketTransport {
|
|||
let encoded = JSON.stringify(message)
|
||||
this.websocket.send(encoded)
|
||||
}
|
||||
|
||||
close() {
|
||||
this.websocket.close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1186,10 +1186,8 @@ U.FormBuilder = L.FormBuilder.extend({
|
|||
L.FormBuilder.prototype.setter.call(this, field, value)
|
||||
this.obj.isDirty = true
|
||||
if ('render' in this.obj) this.obj.render([field], this)
|
||||
console.log('setter', field, value)
|
||||
const { subject, metadata, engine } = this.obj.getSyncMetadata()
|
||||
console.log('metadata', metadata)
|
||||
engine.update(subject, metadata, field, value)
|
||||
if (engine) engine.update(subject, metadata, field, value)
|
||||
},
|
||||
|
||||
finish: function () {
|
||||
|
|
|
@ -248,11 +248,16 @@ U.Map = L.Map.extend({
|
|||
this.backup()
|
||||
this.initContextMenu()
|
||||
this.on('click contextmenu.show', this.closeInplaceToolbar)
|
||||
this.sync = new U.SyncEngine(this)
|
||||
|
||||
Promise.resolve(this.initSyncEngine())
|
||||
},
|
||||
|
||||
initSyncEngine: async function () {
|
||||
console.log('this.options.syncEnabled', this.options.syncEnabled)
|
||||
if (this.options.syncEnabled != true) {
|
||||
this.sync.stop()
|
||||
} else {
|
||||
// Get the authentication token from the server
|
||||
// And pass it to the sync engine.
|
||||
// FIXME: use `this.urls`
|
||||
|
@ -260,7 +265,8 @@ U.Map = L.Map.extend({
|
|||
`/map/${this.options.umap_id}/ws-token/`
|
||||
)
|
||||
if (!error) {
|
||||
this.sync = new U.SyncEngine(this, 'ws://localhost:8001', response.token)
|
||||
this.sync.start('ws://localhost:8001', response.token)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -294,6 +300,8 @@ U.Map = L.Map.extend({
|
|||
case 'bounds':
|
||||
this.handleLimitBounds()
|
||||
break
|
||||
case 'sync':
|
||||
this.initSyncEngine()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1036,7 +1044,7 @@ U.Map = L.Map.extend({
|
|||
formData.append('center', JSON.stringify(this.geometry()))
|
||||
formData.append('settings', JSON.stringify(geojson))
|
||||
const uri = this.urls.get('map_save', { map_id: this.options.umap_id })
|
||||
const [data, response, error] = await this.server.post(uri, {}, formData)
|
||||
const [data, _, error] = await this.server.post(uri, {}, formData)
|
||||
// FIXME: login_required response will not be an error, so it will not
|
||||
// stop code while it should
|
||||
if (!error) {
|
||||
|
@ -1538,7 +1546,7 @@ U.Map = L.Map.extend({
|
|||
if (!this.editEnabled) return
|
||||
if (this.options.editMode !== 'advanced') return
|
||||
const container = L.DomUtil.create('div', 'umap-edit-container'),
|
||||
metadataFields = ['options.name', 'options.description'],
|
||||
metadataFields = ['options.name', 'options.description', 'options.syncEnabled'],
|
||||
title = L.DomUtil.create('h3', '', container)
|
||||
title.textContent = L._('Edit map details')
|
||||
const builder = new U.FormBuilder(this, metadataFields, {
|
||||
|
|
|
@ -60,6 +60,9 @@ U.Layer.Cluster = L.MarkerClusterGroup.extend({
|
|||
|
||||
initialize: function (datalayer) {
|
||||
this.datalayer = datalayer
|
||||
if (!U.Utils.isObject(this.datalayer.options.cluster)) {
|
||||
this.datalayer.options.cluster = {}
|
||||
}
|
||||
const options = {
|
||||
polygonOptions: {
|
||||
color: this.datalayer.getColor(),
|
||||
|
@ -74,10 +77,6 @@ U.Layer.Cluster = L.MarkerClusterGroup.extend({
|
|||
L.MarkerClusterGroup.prototype.initialize.call(this, options)
|
||||
this._markerCluster = U.MarkerCluster
|
||||
this._layers = []
|
||||
|
||||
if (!U.Utils.isObject(this.datalayer.options.cluster)) {
|
||||
this.datalayer.options.cluster = {}
|
||||
}
|
||||
},
|
||||
|
||||
onRemove: function (map) {
|
||||
|
|
|
@ -109,6 +109,7 @@ U.MapPermissions = L.Class.extend({
|
|||
{ handler: 'ManageEditors', label: L._("Map's editors") },
|
||||
])
|
||||
}
|
||||
|
||||
const builder = new U.FormBuilder(this, fields)
|
||||
const form = builder.build()
|
||||
container.appendChild(form)
|
||||
|
|
|
@ -51,7 +51,7 @@ class OperationMessage(BaseModel):
|
|||
subject: str = Literal["map", "layer", "feature"]
|
||||
metadata: Optional[dict] = None
|
||||
key: Optional[str] = None
|
||||
value: Optional[str | bool | int | GeometryValue] = None
|
||||
value: Optional[str | bool | int | GeometryValue | Geometry] = None
|
||||
|
||||
|
||||
async def join_and_listen(
|
||||
|
|
Loading…
Reference in a new issue