# Collaboration

- Human documentation: [https://docs.univer.ai/fr-FR/guides/bases/features/collaboration](https://docs.univer.ai/fr-FR/guides/bases/features/collaboration)

- Agent Markdown: [https://docs.univer.ai/fr-FR/guides/bases/features/collaboration.md](https://docs.univer.ai/fr-FR/guides/bases/features/collaboration.md)

- Requested language: `fr-FR`

- Content language: `fr-FR`

- Documentation version: `1.2.0`

- Source: [bases/features/collaboration.fr-FR.mdx](https://github.com/dream-num/documentation/blob/dev/content/guides/bases/features/collaboration.fr-FR.mdx)

---

#### Package metadata

```json
{
  "preset": [],
  "plugins": [
    {
      "client": "@univerjs-pro/collaboration"
    },
    {
      "client": "@univerjs-pro/collaboration-client",
      "facade": "@univerjs-pro/collaboration-client/facade",
      "locale": "@univerjs-pro/collaboration-client/locale/fr-FR"
    },
    {
      "client": "@univerjs-pro/collaboration-client-ui",
      "facade": "@univerjs-pro/collaboration-client-ui/facade",
      "locale": "@univerjs-pro/collaboration-client-ui/locale/fr-FR",
      "style": "@univerjs-pro/collaboration-client-ui/lib/index.css"
    }
  ],
  "license": true,
  "server": true
}
```

Permettez aux utilisateurs d’ouvrir la même Base et de modifier ensemble tables, champs, enregistrements et vues. Ils peuvent travailler dans des vues différentes tout en modifiant le même document.

## Étapes d’intégration

1. Suivez l’[intégration collaborative](https://docs.univer.ai/fr-FR/server/collaboration/browser-integration.md) pour exécuter l’exemple et connecter la connexion utilisateur, les autorisations et le stockage en base de données.
2. Ajoutez la configuration du client Collaboration à votre éditeur Bases existant. Suivez le [Démarrage rapide de la collaboration](https://docs.univer.ai/fr-FR/server/collaboration/quick-start.md) pour le navigateur, mais créez et stockez des documents Bases au lieu de copier les données Sheets de l’exemple.
3. Créez la Base via le backend de votre application et renvoyez son ID au navigateur.

## Ouvrir une Base du serveur

Définissez l’utilisateur courant avant de charger le document. Voir [Intégration collaborative](https://docs.univer.ai/fr-FR/server/collaboration/browser-integration.md).

```ts
import '@univerjs-pro/bases/facade'
import { UserManagerService } from '@univerjs/core'
import '@univerjs-pro/collaboration-client/facade'

univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })

const base = await univerAPI.getCollaboration().loadBaseAsync('your-base-id')
if (!base) throw new Error('Base could not be loaded')
```

Réutilisez cet ID pour rouvrir ou partager le document. Ne remplacez pas le chargement serveur par `createBase()` et un nouveau document local vierge.

Utilisez [états, renvois et récupération des conflits](https://docs.univer.ai/fr-FR/server/collaboration/browser-integration.md#sync-status) pour afficher l’enregistrement et préserver les modifications non confirmées avant rechargement.

## Suppression du chargement intégré par URL des documents collaboratifs

> [!WARNING: À noter]
> À partir de la version **1.2.0**, Univer a supprimé le chargement intégré par URL des documents collaboratifs. Les paramètres `unit` et `type` de l’URL ne sont plus lus automatiquement pour charger un document collaboratif.

Si votre application dépend de ce comportement, vous pouvez le rétablir avec un plugin personnalisé.

### Intégrer le plugin personnalisé

Copiez les quatre fichiers ci-dessous dans votre projet en respectant cette arborescence :

```text
custom-url-load/
├── plugin.ts
├── controllers/
│   └── data-loader.controller.ts
└── services/
    ├── url.service.ts
    └── web-url.service.ts
```

Après avoir initialisé l’éditeur et les plugins de collaboration, définissez l’utilisateur courant avant d’enregistrer `CustomUrlLoadPlugin`.

```ts
import { UserManagerService } from '@univerjs/core'
import { CustomUrlLoadPlugin } from './custom-url-load/plugin'

univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })

univer.registerPlugin(CustomUrlLoadPlugin)
```

Une fois enregistré, le plugin charge le document ; il n’est donc pas nécessaire d’appeler `loadBaseAsync()` pour le même document. Si votre application charge déjà les documents via la Facade, vous pouvez conserver l’approche de la section précédente et gérer les URL selon les besoins de votre application.

### Code complet du plugin

#### plugin.ts

```ts
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'
import { DependentOn, Inject, Injector, Plugin } from '@univerjs/core'
import { CollaborationDataLoaderController } from './controllers/data-loader.controller'
import { IURLService } from './services/url.service'
import { WebURLService } from './services/web-url.service'

@DependentOn(UniverCollaborationClientPlugin)
export class CustomUrlLoadPlugin extends Plugin {
  static override pluginName = 'CUSTOM_URL_LOAD_PLUGIN'

  constructor(
    _config: undefined,
    @Inject(Injector) protected override readonly _injector: Injector
  ) {
    super()
  }

  override onStarting(): void {
    this._injector.add([IURLService, { useClass: WebURLService }])
    this._injector.add([CollaborationDataLoaderController])

    this.disposeWithMe(this._injector.get(IURLService))
    this.disposeWithMe(this._injector.get(CollaborationDataLoaderController))
  }
}
```

#### controllers/data-loader.controller.ts

```ts
import { DataLoaderService } from '@univerjs-pro/collaboration-client'
import { ILogService, Inject, RxDisposable } from '@univerjs/core'
import { IURLService } from '../services/url.service'

/**
 * Charge un document collaboratif à partir des paramètres de l’URL.
 */
export class CollaborationDataLoaderController extends RxDisposable {
  constructor(
    @IURLService private readonly _urlService: IURLService,
    @ILogService private readonly _logService: ILogService,
    @Inject(DataLoaderService) private readonly _dataLoaderService: DataLoaderService
  ) {
    super()

    const unitId = this._urlService.getParam('unit')
    const type = this._urlService.getParam('type')
    if (!unitId || !type) {
      return
    }

    this._dataLoaderService.loadUnit(unitId, Number(type))
      .catch((error: unknown) => {
        this._logService.error('[CollaborationDataLoaderController]', error)
      })
  }
}
```

#### services/url.service.ts

```ts
import type { IDisposable } from '@univerjs/core'
import type { Observable } from 'rxjs'
import { createIdentifier } from '@univerjs/core'

export interface IURLService extends IDisposable {
  getParam: (key: string) => string | undefined
  setParam: (key: string, value: string, useReplace?: boolean) => void
  removeParam: (key: string, useReplace?: boolean) => void
  readonly urlChange$: Observable<void>
}

export const IURLService = createIdentifier<IURLService>('demo.custom-url-load.url-service')
```

#### services/web-url.service.ts

```ts
import type { IURLService } from './url.service'
import { RxDisposable } from '@univerjs/core'
import { fromEvent, map, shareReplay, takeUntil } from 'rxjs'

export class WebURLService extends RxDisposable implements IURLService {
  readonly urlChange$ = fromEvent(window, 'popstate').pipe(
    map(() => undefined),
    takeUntil(this.dispose$),
    shareReplay({ bufferSize: 1, refCount: true })
  )

  getParam(key: string): string | undefined {
    return new URL(window.location.href).searchParams.get(key) ?? undefined
  }

  setParam(key: string, value: string, useReplace = false): void {
    const url = new URL(window.location.href)
    url.searchParams.set(key, value)
    this._updateUrl(url, useReplace)
  }

  removeParam(key: string, useReplace = false): void {
    const url = new URL(window.location.href)
    url.searchParams.delete(key)
    this._updateUrl(url, useReplace)
  }

  private _updateUrl(url: URL, useReplace: boolean): void {
    if (useReplace) {
      window.history.replaceState(window.history.state, '', url.toString())
    } else {
      window.history.pushState(window.history.state, '', url.toString())
    }
  }
}
```

## Vérifier la synchronisation et l’enregistrement

Ouvrez le même ID dans deux sessions de navigateur indépendantes. Ajoutez un enregistrement ou modifiez un champ dans l’une, puis vérifiez que l’autre reçoit le changement. Vérifiez que les modifications persistent après actualisation et redémarrage du serveur.

Contrôlez côté serveur l’accès des lecteurs et des utilisateurs non autorisés. Les [réglages locaux de lecture seule](https://docs.univer.ai/fr-FR/guides/bases/features/core/permissions.md) ne contrôlent que le comportement de l’éditeur. La conversion de fichiers, les commentaires et l’historique nécessitent leurs fonctionnalités backend respectives ; consultez [Import-export](https://docs.univer.ai/fr-FR/guides/bases/features/import-export.md), [Commentaires](https://docs.univer.ai/fr-FR/guides/bases/features/thread-comment.md) et [Historique](https://docs.univer.ai/fr-FR/guides/bases/features/edit-history.md).
