Intégration collaborative
Connecter l’éditeur Univer à un service collaboratif pour modifier un même document à plusieurs.
La collaboration connecte les éditeurs du navigateur à un service de documents partagés. Par exemple, deux utilisateurs ouvrent le même classeur et une modification dans un navigateur apparaît dans l’autre.
Préparez le backend avec l’intégration serveur, puis configurez l’éditeur et le chargement ci-dessous. Suivez ensemble les codes Server et Web du Démarrage rapide de la collaboration.
Connecter votre éditeur existant
Conservez votre éditeur Web SDK. Suivez la configuration navigateur du démarrage rapide pour ajouter les plugins collaboratifs et configurer le chargement, l’envoi de modifications et les adresses WebSocket. Gardez les versions des paquets navigateur et serveur compatibles.
Les utilisateurs fixes et les autorisations par défaut des exemples servent à la démonstration. Dans votre application, joignez les identifiants de connexion aux requêtes pour que le backend vérifie l’identité et l’accès au document. Consultez la configuration de la licence pour la licence.
Créer et ouvrir le même document
La création et l’ouverture sont deux actions distinctes :
- Lorsqu’un utilisateur crée un document, votre backend l’enregistre et renvoie son ID.
- Le navigateur charge cet ID. Réutilisez-le pour rouvrir le document ou le partager.
Le unitId de l’API est cet ID de document. Ne créez pas un nouveau document local vierge à chaque visite.
Définissez l’utilisateur courant avant de charger un document. Il identifie le collaborateur et possède le cache hors ligne local ; voir Identité et autorisations.
Par exemple, après avoir enregistré les plugins Sheets et collaboratifs, chargez un classeur du serveur :
import { UserManagerService } from '@univerjs/core'import '@univerjs-pro/collaboration-client/facade'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })const workbook = await univerAPI.getCollaboration().loadSheetAsync('your-document-id')if (!workbook) throw new Error('Document could not be loaded')Consultez les guides Sheets, Docs, Slides, Boards, Bases et PDFs pour le chargement propre à chaque produit. Vérifiez la prise en charge par le produit et la version backend ciblée.
Vérifier synchronisation, enregistrement et autorisations
Ouvrez le même document dans deux sessions indépendantes, par exemple une fenêtre normale et une privée. Modifiez dans l’une et vérifiez l’autre. Vérifiez ensuite le contenu après actualisation, reconnexion et redémarrage serveur.
Testez avec un éditeur, un lecteur et un utilisateur non autorisé. Les réglages UI de lecture seule contrôlent les interactions ; le serveur doit toujours refuser les lectures et changements non autorisés.
Si les documents se chargent mais que les modifications ne se synchronisent pas, vérifiez WebSocket. Si le contenu disparaît au redémarrage, vérifiez le stockage backend. Ces réglages sont décrits dans l’intégration serveur.
Ajouter échange de fichiers, commentaires ou historique
Pour modifier ensemble un fichier importé, créez un document collaboratif à partir des données converties ; consultez l’intégration de l’échange de fichiers. Commentaires et historique nécessitent leurs propres plugins, services et autorisations. Suivez les modules d’extension Office.
Pour les panneaux d’historique, consultez Sheets, Docs, Slides, Boards et Bases. La portée actuelle pour PDFs est décrite dans Historique PDFs.
État de synchronisation et renvois
Après import du Facade, CollaborationStatusChanged signale l’état courant des documents déjà collaboratifs lors de l’abonnement, puis les changements sans doublons consécutifs. hasWritePending(unitId) inclut les modifications en attente d’envoi, d’accusé de réception et hors ligne. Sans ID, il vérifie le document ciblé. Une connexion ouverte ne signifie pas que tout est enregistré.
import '@univerjs-pro/collaboration-client/facade'const collaboration = univerAPI.getCollaboration()const statusSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationStatusChanged, (event) => { console.info(event.unitId, event.status, collaboration.hasWritePending(event.unitId))})const resendSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationChangesetResend, (event) => { console.info(event.unitId, event.reason, event.attempt, event.unsyncedMutationCount, event.nextDelayMs)})CollaborationChangesetResend intervient uniquement lors des renvois. Les raisons sont ack_timeout, should_retry et reconnect. attempt, elapsedMs, unsyncedMutationCount et nextDelayMs permettent d’afficher l’enregistrement et les tentatives. Libérez les abonnements à la suppression de l’éditeur.
Le délai de regroupement diffère du délai d’accusé de réception. Valeurs du plugin en millisecondes : sendChangesetTimeout: 2000, changesetAckTimeout: 20000, maxChangesetAckTimeout: 120000. La requête d’envoi utilise aussi le délai d’accusé. Sans confirmation, les renvois suivent un recul exponentiel jusqu’au maximum. Deux délais d’accusé identiques donnent un intervalle constant.
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import { BrowserCollaborationSocketService } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientPlugin, { socketService: BrowserCollaborationSocketService, sendChangesetTimeout: 200, changesetAckTimeout: 20_000, maxChangesetAckTimeout: 120_000,})Ajoutez ces options à l’enregistrement existant en conservant socket et endpoints. Les presets collaboratifs Sheets et Docs utilisent un regroupement de 200 ms et n’exposent pas les délais d’accusé ; utilisez le mode plugin pour les personnaliser.
Gérer les conflits dans l’application
CollaborationConflict intervient une fois à l’entrée en conflit, après la tentative de nettoyage du cache hors ligne. Abonnez-vous avant le chargement. reason vaut transform_failed, apply_failed, changeset_rejected, permission_rejected ou remote_revert ; message et revert apportent des détails si disponibles.
import type { IEventParamConfig } from '@univerjs/core/facade'import '@univerjs-pro/collaboration-client/facade'const conflicts = new Map<string, IEventParamConfig['CollaborationConflict']>()const conflictSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationConflict, (event) => { conflicts.set(event.unitId, event)})L’exemple conserve l’événement pour un écran de récupération. La Map reste en mémoire : avant de recharger, enregistrez ou exportez localChanges dans l’application. C’est lors de cet événement qu’il faut les retenir ; le cache effacé n’est plus récupérable ensuite. awaitingChangeset a peut-être déjà été appliqué sur le serveur : ne le rejouez pas aveuglément.
Avec cacheCleared: false, recharger rejouerait les anciennes modifications du cache. Résolvez le nettoyage avant de recharger. Effacer le cache ne confirme pas la sauvegarde des modifications. permission_rejected exige aussi de résoudre l’accès ; recharger ne donne aucun droit.
Par défaut, l’UI affiche une notification selon la raison et propose de recharger après nettoyage réussi, ou de réessayer si le nettoyage échoue. Pour gérer la récupération vous-même, définissez enableDefaultConflictUI: false dans l’initialisation existante et traitez l’événement :
import { UniverCollaborationClientUIPlugin } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientUIPlugin, { enableDefaultConflictUI: false })import { UniverSheetsCollaborationPreset } from '@univerjs/preset-sheets-collaboration'const collaborationPreset = UniverSheetsCollaborationPreset({ enableDefaultConflictUI: false })import { UniverDocsCollaborationPreset } from '@univerjs/preset-docs-collaboration'const collaborationPreset = UniverDocsCollaborationPreset({ enableDefaultConflictUI: false })Ajoutez le preset collaboratif à createUniver({ presets: [...] }) avec celui de l’éditeur, en conservant les endpoints et l’historique. Voir les paramètres d’événement et la configuration client.
Que pensez-vous de ce guide ?