Skip to content

refactor(docflow): extract doc permission/collab/template logic into …#326

Merged
xun082 merged 1 commit intomainfrom
refactor/docflow-editor-collab-hooks
Mar 25, 2026
Merged

refactor(docflow): extract doc permission/collab/template logic into …#326
xun082 merged 1 commit intomainfrom
refactor/docflow-editor-collab-hooks

Conversation

@xun082
Copy link
Owner

@xun082 xun082 commented Mar 25, 2026

…hooks

  • split docs/[room]/page.tsx into useDocumentPermission, useCollaboration and useTemplateInsertion
  • centralize readonly resolution with precedence: query readonly > server permission > HTTP fallback
  • gate collaboration bootstrap by IndexedDB restore + server sync before editor init
  • keep editable state synced via editor.setEditable without recreating editor instance

PR 描述

PR 类型

  • 🐛 Bug 修复
  • ✨ 新功能
  • 💄 UI/UX 改进
  • ♻️ 重构
  • 🚀 性能优化
  • 📝 文档更新
  • 🔄 其他

Issue 关联

Closes #

其他信息

…hooks

- split docs/[room]/page.tsx into useDocumentPermission, useCollaboration and useTemplateInsertion
- centralize readonly resolution with precedence: query readonly > server permission > HTTP fallback
- gate collaboration bootstrap by IndexedDB restore + server sync before editor init
- keep editable state synced via editor.setEditable without recreating editor instance
@netlify
Copy link

netlify bot commented Mar 25, 2026

Deploy Preview for ornate-blancmange-89db6b failed. Why did it fail? →

Name Link
🔨 Latest commit 90a6b9d
🔍 Latest deploy log https://app.netlify.com/projects/ornate-blancmange-89db6b/deploys/69c3a9be78585000085045d4

@xun082 xun082 merged commit 91d9d84 into main Mar 25, 2026
0 of 6 checks passed
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the DocumentPage component by extracting key functionalities into dedicated React hooks. This improves modularity, maintainability, and readability by separating concerns related to document permissions, real-time collaboration, and template insertion. The changes also introduce a more robust and centralized mechanism for determining the document's read-only status and optimize the editor's lifecycle management.

Highlights

  • Extracted Logic into Hooks: Document permission, real-time collaboration, and template insertion logic were moved from the main page.tsx component into dedicated React hooks (useDocumentPermission, useCollaboration, useTemplateInsertion).
  • Centralized Read-Only Resolution: A new authoritative read-only flag was implemented, consolidating precedence from URL query parameters, server-confirmed permissions, and HTTP fallback.
  • Gated Collaboration Bootstrap: Collaboration initialization now waits for IndexedDB restoration and server synchronization to ensure data consistency before the editor is fully active.
  • Optimized Editor Editable State: The editor's editable state is dynamically synced using editor.setEditable() to avoid recreating the editor instance, improving performance and user experience during permission changes.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the DocumentPage component by extracting collaboration, permission, and template insertion logic into dedicated custom hooks (useCollaboration, useDocumentPermission, useTemplateInsertion). This significantly improves modularity and readability. The DocumentPage now primarily orchestrates these hooks and renders the UI. Feedback includes removing a redundant useEffect for editor cleanup, ensuring immediate synchronization of user awareness state in useCollaboration to prevent UI delays, and refining the template insertion logic in useTemplateInsertion to consistently clear templates from local storage after an attempt to use them.

const updatedContents = { ...templateContents };
delete updatedContents[docIdString];
storage.set(STORAGE_KEYS.TEMPLATE_CONTENT, updatedContents);
useEffect(() => () => clearEditor(), [clearEditor]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这个用于在组件卸载时调用 clearEditoruseEffect 是多余的。useEditor hook 已经在 onDestroy 回调(第 151 行)中配置了此功能。Tiptap 的 useEditor hook 会在组件卸载时自动销毁编辑器并调用 onDestroy。删除这个 useEffect 可以使代码更简洁,且不影响功能。

Comment on lines +137 to +139
provider.awareness.on('update', sync);

return () => provider.awareness?.off('update', sync);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

awareness 的 'update' 事件在状态改变时触发,但最佳实践是在附加监听器后立即同步一次状态。这可以确保 awareness 状态中已存在的任何用户都能立即显示,而不是等待下一次更新。这样可以防止加载文档时 UI 出现延迟或闪烁。

    provider.awareness.on('update', sync);
    sync(); // 立即同步以捕获初始状态

    return () => provider.awareness?.off('update', sync);

Comment on lines +28 to +50
try {
if (!editor || editor.isDestroyed) return;

const updatedContents = { ...templateContents };
delete updatedContents[docIdString];

if (editor.getText().trim().length > 0) {
storage.set(STORAGE_KEYS.TEMPLATE_CONTENT, updatedContents);

return;
}

if (!editor.commands.pasteMarkdown) return;

editor.commands.clearContent();

if (editor.commands.pasteMarkdown(templateContent)) {
storage.set(STORAGE_KEYS.TEMPLATE_CONTENT, updatedContents);
setTimeout(() => editor.commands.focus('start'), 100);
}
} catch {
// silently ignore
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这个 hook 顶部的注释说:“无论结果如何,都清除存储的模板”。然而,目前的实现只在文档不为空或 pasteMarkdown 成功时才从存储中删除模板。如果粘贴失败,模板将保留在存储中,并在下次加载时再次尝试插入,这可能不是预期的行为。

为了使行为更健壮并与注释的意图保持一致,应该在读取模板后立即从存储中删除它。

      try {
        if (!editor || editor.isDestroyed) return;

        // 一旦我们尝试使用模板,就认为它已被“消费”。
        // 立即从存储中删除它,以防止将来加载时重新插入。
        const updatedContents = { ...templateContents };
        delete updatedContents[docIdString];
        storage.set(STORAGE_KEYS.TEMPLATE_CONTENT, updatedContents);

        if (editor.getText().trim().length > 0) {
          // 文档已有内容,不插入模板。
          return;
        }

        if (editor.commands.pasteMarkdown) {
          editor.commands.clearContent();
          if (editor.commands.pasteMarkdown(templateContent)) {
            setTimeout(() => editor.commands.focus('start'), 100);
          }
        }
      } catch {
        // 静默忽略
      }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant