From d9ca5e3102560c6dc1fe79e9ba2a52b3d0b01737 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 1 Mar 2025 12:29:53 +0100 Subject: [PATCH] sync form --- src/stores/admin/operation/missionDetail.ts | 61 +++++++++++++------ .../admin/operation/mission/MissionDetail.vue | 8 ++- .../operation/mission/MissionOverview.vue | 7 ++- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/stores/admin/operation/missionDetail.ts b/src/stores/admin/operation/missionDetail.ts index 2bf1d7a..39f6186 100644 --- a/src/stores/admin/operation/missionDetail.ts +++ b/src/stores/admin/operation/missionDetail.ts @@ -1,13 +1,13 @@ import { defineStore } from "pinia"; import { useConnectionStore } from "./connection"; import * as Y from "yjs"; -import { Awareness } from "y-protocols/awareness.js"; -import { computed, ref } from "vue"; +import * as AwarenessProtocol from "y-protocols/awareness.js"; export const useMissionDetailStore = defineStore("missionDetail", { state: () => { return { yDoc: new Y.Doc(), + awareness: undefined as undefined | AwarenessProtocol.Awareness, docId: null as null | string, lastUpdateTimestamp: 0 as number, connectionStatus: "disconnected", // 'disconnected', 'connecting', 'connected', 'syncing', 'synced' @@ -18,16 +18,18 @@ export const useMissionDetailStore = defineStore("missionDetail", { this.docId = docId; this.lastUpdateTimestamp = this.loadLastUpdateFromLocalStorage(); + this.awareness = new AwarenessProtocol.Awareness(this.yDoc); + this.awareness.setLocalStateField("user", { name: "hi", color: "#123456" }); this.setupSocketHandlers(); this.setupYjsObservers(); + this.setupAwarenessObservers(); }, setupSocketHandlers() { const connectionStore = useConnectionStore(); - if (!connectionStore.connection) return; - connectionStore.connection.on("package-sync", (data) => { + connectionStore.connection?.on("package-sync", (data) => { try { this.connectionStatus = "syncing"; @@ -44,7 +46,7 @@ export const useMissionDetailStore = defineStore("missionDetail", { this.requestFullSync(); } }); - connectionStore.connection.on("sync-get-missing-updates", (data) => { + connectionStore.connection?.on("sync-get-missing-updates", (data) => { const clientUpdates = Y.encodeStateAsUpdate(this.yDoc, new Uint8Array(data.stateVector)); connectionStore.connection?.emit("mission:sync-client-updates", { @@ -53,12 +55,16 @@ export const useMissionDetailStore = defineStore("missionDetail", { }); }); + connectionStore.connection?.on("package-sync-awareness", (data) => { + // if (this.awareness != undefined) { + // AwarenessProtocol.applyAwarenessUpdate(this.awareness, new Uint8Array(data.update), this); + // } + }); + this.joinDocument(); }, setupYjsObservers() { - if (!this.yDoc) return; - this.yDoc.on("update", (update) => { const connectionStore = useConnectionStore(); if (connectionStore.connected) { @@ -73,20 +79,35 @@ export const useMissionDetailStore = defineStore("missionDetail", { }); }, - joinDocument() { - const connectionStore = useConnectionStore(); - if (!connectionStore.connection || !this.docId) return; + setupAwarenessObservers() { + if (!this.awareness) return; - connectionStore.connection.emit("mission:join", this.docId, { + this.awareness.on("update", (update: { added: number[]; updated: number[]; removed: number[] }) => { + if (this.awareness != undefined) { + const changedClients = update.added.concat(update.updated).concat(update.removed); + const connectionStore = useConnectionStore(); + connectionStore.connection?.emit( + "mission:sync-client-awareness", + Array.from(AwarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients)) + ); + } + }); + }, + + joinDocument() { + if (!this.docId) return; + + const connectionStore = useConnectionStore(); + connectionStore.connection?.emit("mission:join", this.docId, { timestamp: this.lastUpdateTimestamp, }); }, requestFullSync() { - const connectionStore = useConnectionStore(); - if (!connectionStore.connection || !this.docId) return; + if (!this.docId) return; - connectionStore.connection.emit("mission:join", this.docId, null); + const connectionStore = useConnectionStore(); + connectionStore.connection?.emit("mission:join", this.docId, null); }, loadLastUpdateFromLocalStorage() { @@ -97,16 +118,18 @@ export const useMissionDetailStore = defineStore("missionDetail", { }, saveLastUpdateToLocalStorage() { - if (!this.docId) return; - localStorage.setItem(`yjsDoc_timestamp`, this.lastUpdateTimestamp.toString()); }, cleanup() { - if (this.yDoc) { - this.yDoc.destroy(); - this.yDoc = new Y.Doc(); + if (this.awareness) { + AwarenessProtocol.removeAwarenessStates(this.awareness, [this.yDoc.clientID], "window unload"); + this.awareness.destroy(); } + + this.yDoc.destroy(); + this.yDoc = new Y.Doc(); + this.lastUpdateTimestamp = 0; localStorage.removeItem("yjsDoc_timestamp"); diff --git a/src/views/admin/operation/mission/MissionDetail.vue b/src/views/admin/operation/mission/MissionDetail.vue index 1c52624..950d8c8 100644 --- a/src/views/admin/operation/mission/MissionDetail.vue +++ b/src/views/admin/operation/mission/MissionDetail.vue @@ -60,7 +60,6 @@ :style="!can('create', 'operation', 'mission') ? 'opacity: 75%; background: rgb(243 244 246)' : ''" @ready="initEditor" /> -

Eingesetzte Fahrzeuge

@@ -86,6 +85,7 @@ import { moduleOptions } from "@/helpers/quillConfig"; import ForceSelect from "@/components/admin/ForceSelect.vue"; import { useForceStore } from "@/stores/admin/configuration/force"; import * as Y from "yjs"; +import type { Awareness } from "y-protocols/awareness.js";