From 82ba16870d99e74a781ae097fa63df2d88c09319 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 16 Jul 2025 12:28:00 +0200 Subject: [PATCH 1/5] chore(move): useDelayedFlag to composables Signed-off-by: Max --- src/components/Editor.vue | 2 +- src/{components/Editor => composables}/useDelayedFlag.spec.ts | 0 src/{components/Editor => composables}/useDelayedFlag.ts | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/{components/Editor => composables}/useDelayedFlag.spec.ts (100%) rename src/{components/Editor => composables}/useDelayedFlag.ts (100%) diff --git a/src/components/Editor.vue b/src/components/Editor.vue index 099141f2597..0c9f903d8a3 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -100,6 +100,7 @@ import { t } from '@nextcloud/l10n' import { generateRemoteUrl } from '@nextcloud/router' import { Awareness } from 'y-protocols/awareness.js' import { provideConnection } from '../composables/useConnection.ts' +import { useDelayedFlag } from '../composables/useDelayedFlag.ts' import { useEditorMethods } from '../composables/useEditorMethods.ts' import { provideSaveService } from '../composables/useSaveService.ts' import { provideSyncService } from '../composables/useSyncService.ts' @@ -126,7 +127,6 @@ import ContentContainer from './Editor/ContentContainer.vue' import DocumentStatus from './Editor/DocumentStatus.vue' import MainContainer from './Editor/MainContainer.vue' import Status from './Editor/Status.vue' -import { useDelayedFlag } from './Editor/useDelayedFlag.ts' import Wrapper from './Editor/Wrapper.vue' import MenuBar from './Menu/MenuBar.vue' import Translate from './Modal/Translate.vue' diff --git a/src/components/Editor/useDelayedFlag.spec.ts b/src/composables/useDelayedFlag.spec.ts similarity index 100% rename from src/components/Editor/useDelayedFlag.spec.ts rename to src/composables/useDelayedFlag.spec.ts diff --git a/src/components/Editor/useDelayedFlag.ts b/src/composables/useDelayedFlag.ts similarity index 100% rename from src/components/Editor/useDelayedFlag.ts rename to src/composables/useDelayedFlag.ts From 427d798beb82d36488510529aa6dcb73708b7d72 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 17 Jul 2025 20:22:44 +0200 Subject: [PATCH 2/5] enh(status): use awareness state instead of sessions Signed-off-by: Max --- src/components/Editor.vue | 92 +++++------------------ src/components/Editor/AvatarWrapper.vue | 27 +++---- src/components/Editor/GuestNameDialog.vue | 40 +++------- src/components/Editor/SessionList.vue | 82 +++++++++----------- src/components/Editor/Status.vue | 26 +++---- src/composables/useClients.ts | 71 +++++++++++++++++ src/extensions/CollaborationCursor.ts | 9 ++- src/services/PollingBackend.ts | 3 +- 8 files changed, 169 insertions(+), 181 deletions(-) create mode 100644 src/composables/useClients.ts diff --git a/src/components/Editor.vue b/src/components/Editor.vue index 0c9f903d8a3..6befb7b8c26 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -31,7 +31,7 @@ @@ -48,7 +48,7 @@ @@ -87,7 +87,7 @@ import { File } from '@nextcloud/files' import { loadState } from '@nextcloud/initial-state' import { Collaboration } from '@tiptap/extension-collaboration' import { useElementSize } from '@vueuse/core' -import Vue, { defineComponent, ref, set, shallowRef, watch } from 'vue' +import { defineComponent, ref, shallowRef, watch } from 'vue' import { Doc } from 'yjs' import Autofocus from '../extensions/Autofocus.js' @@ -96,7 +96,6 @@ import { provideEditorFlags } from '../composables/useEditorFlags.ts' import { ATTACHMENT_RESOLVER, FILE, IS_MOBILE } from './Editor.provider.ts' import ReadonlyBar from './Menu/ReadonlyBar.vue' -import { t } from '@nextcloud/l10n' import { generateRemoteUrl } from '@nextcloud/router' import { Awareness } from 'y-protocols/awareness.js' import { provideConnection } from '../composables/useConnection.ts' @@ -245,7 +244,10 @@ export default defineComponent({ const extensions = [ Autofocus.configure({ fileId: props.fileId }), Collaboration.configure({ document: ydoc }), - CollaborationCursor.configure({ provider: { awareness } }), + CollaborationCursor.configure({ + provider: { awareness }, + user: { clientId: ydoc.clientID, name: '' }, + }), ] const editor = isRichEditor ? createRichEditor({ @@ -303,12 +305,8 @@ export default defineComponent({ IDLE_TIMEOUT, document: null, - sessions: [], - currentSession: null, fileNode: null, - filteredSessions: {}, - idle: false, lock: null, dirty: false, @@ -343,7 +341,7 @@ export default defineComponent({ : '/' }, displayed() { - return (this.currentSession && this.active) || this.syncError + return (this.connection && this.active) || this.syncError }, showLoadingSkeleton() { return (!this.contentLoaded || !this.displayed) && !this.syncError @@ -503,54 +501,7 @@ export default defineComponent({ this.idle = false }, - updateSessions(sessions) { - this.sessions = sessions.sort((a, b) => b.lastContact - a.lastContact) - - // Make sure we get our own session updated - // This should ideally be part of a global store where we can have that updated on the actual name change for guests - const currentUpdatedSession = this.sessions.find( - (session) => session.id === this.currentSession.id, - ) - set(this, 'currentSession', currentUpdatedSession) - - const currentSessionIds = this.sessions.map((session) => session.userId) - const currentGuestIds = this.sessions.map((session) => session.guestId) - - const removedSessions = Object.keys(this.filteredSessions).filter( - (sessionId) => - !currentSessionIds.includes(sessionId) - && !currentGuestIds.includes(sessionId), - ) - - for (const index in removedSessions) { - Vue.delete(this.filteredSessions, removedSessions[index]) - } - for (const index in this.sessions) { - const session = this.sessions[index] - const sessionKey = session.displayName ? session.userId : session.id - if (this.filteredSessions[sessionKey]) { - // update timestamp if relevant - if ( - this.filteredSessions[sessionKey].lastContact - < session.lastContact - ) { - set( - this.filteredSessions[sessionKey], - 'lastContact', - session.lastContact, - ) - } - } else { - set(this.filteredSessions, sessionKey, session) - } - if (session.id === this.currentSession.id) { - set(this.filteredSessions[sessionKey], 'isCurrent', true) - } - } - }, - onOpened({ document, session, documentSource, documentState }) { - this.currentSession = session this.document = document this.readOnly = document.readOnly this.baseVersionEtag = document.baseVersionEtag @@ -559,18 +510,17 @@ export default defineComponent({ this.setEditable(this.editMode) this.lock = this.syncService.lock - localStorage.setItem('nick', this.currentSession.guestName) this.$attachmentResolver = new AttachmentResolver({ - session: this.currentSession, + session, user: getCurrentUser(), shareToken: this.shareToken, currentDirectory: this.currentDirectory, }) - if (this.currentSession?.userId && this.relativePath?.length) { + if (session?.userId && this.relativePath?.length) { const node = new File({ id: this.fileId, source: generateRemoteUrl( - `dav/files/${this.currentSession.userId}${this.relativePath}`, + `dav/files/${session.userId}${this.relativePath}`, ), mime: this.mime, }) @@ -589,20 +539,18 @@ export default defineComponent({ }) } }) - const user = { - name: session?.userId - ? session.displayName - : session?.guestName || t('text', 'Guest'), - color: session?.color, - clientId: this.ydoc.clientID, - } - this.editor.commands.updateUser(user) + const { userId, displayName, guestName, color } = session + localStorage.setItem('nick', guestName) + this.editor.commands.updateUser({ + ...this.awareness.getLocalState().user, + userId, + name: userId ? displayName : guestName, + color, + }) }, - onChange({ document, sessions }) { - this.updateSessions.bind(this)(sessions) + onChange({ document }) { this.document = document - this.syncError = null this.setEditable(this.editMode && !this.requireReconnect) }, diff --git a/src/components/Editor/AvatarWrapper.vue b/src/components/Editor/AvatarWrapper.vue index 93c405b532e..8ff49cff14d 100644 --- a/src/components/Editor/AvatarWrapper.vue +++ b/src/components/Editor/AvatarWrapper.vue @@ -4,16 +4,15 @@ -->