Skip to content

feat(docs): support setting read-only#6115

Open
electroluxcode wants to merge 4 commits intodream-num:devfrom
electroluxcode:feat/docs-support-readonly
Open

feat(docs): support setting read-only#6115
electroluxcode wants to merge 4 commits intodream-num:devfrom
electroluxcode:feat/docs-support-readonly

Conversation

@electroluxcode
Copy link

@electroluxcode electroluxcode commented Nov 9, 2025

close #xxx

Description

This PR implements read-only mode for Univer Docs

Key Changes

  1. Permission System

    • Added DocumentEditablePermission permission point (similar to Sheets' WorkbookEditablePermission)
    • Integrated with IPermissionService for centralized permission management
  2. Facade API

    • Added FDocument.setEditable(value: boolean) method
    • Usage: univerAPI.getActiveDocument().setEditable(false)
  3. Command & UI Protection

    • Added permission checks to all editing commands (insert, delete, paste, list operations, etc.)
    • Added getCurrentDocRangeDisable$() observable for reactive UI updates
    • Updated all menu items and context menus to respect read-only state

Testing

  • step1: replace with the following code examples/src/docs/main.ts pnpm run dev
  • step2: pnpm run dev
  • step3: go to localhost:3000/docs

Then you will find that the docs are set to read-only status after 3 seconds

import { LocaleType, LogLevel, Univer, UniverInstanceType, UserManagerService } from '@univerjs/core';
import { FUniver } from '@univerjs/core/facade';
import { UniverDebuggerPlugin } from '@univerjs/debugger';
import { UniverDocsPlugin } from '@univerjs/docs';
import { UniverDocsDrawingUIPlugin } from '@univerjs/docs-drawing-ui';
import { UniverDocsHyperLinkUIPlugin } from '@univerjs/docs-hyper-link-ui';
import { UniverDocsMentionUIPlugin } from '@univerjs/docs-mention-ui';
import { UniverDocsQuickInsertUIPlugin } from '@univerjs/docs-quick-insert-ui';
import { UniverDocsThreadCommentUIPlugin } from '@univerjs/docs-thread-comment-ui';
import { UniverDocsUIPlugin } from '@univerjs/docs-ui';
import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula';
import { UniverRenderEnginePlugin } from '@univerjs/engine-render';
import { DEFAULT_DOCUMENT_DATA_SIMPLE } from '@univerjs/mockdata';
import zhCN from '@univerjs/mockdata/locales/zh-CN';
import { UniverUIPlugin } from '@univerjs/ui';

import '@univerjs/docs-ui/facade';

import '../global.css';

/* eslint-disable node/prefer-global/process */
const IS_E2E: boolean = !!process.env.IS_E2E;

// univer
const univer = new Univer({
    locale: LocaleType.ZH_CN,
    locales: {
        [LocaleType.ZH_CN]: zhCN,
    },
    logLevel: LogLevel.VERBOSE,
});

// core plugins
univer.registerPlugin(UniverRenderEnginePlugin);
univer.registerPlugin(UniverFormulaEnginePlugin);
univer.registerPlugin(UniverUIPlugin, {
    container: 'app',
});

univer.registerPlugin(UniverDocsPlugin);
univer.registerPlugin(UniverDocsUIPlugin, {
    container: 'univerdoc',
    layout: {
        docContainerConfig: {
            innerLeft: false,
        },
    },
    disableAutoFocus: true, // Disable auto-focus
});

univer.registerPlugin(UniverDocsDrawingUIPlugin);
univer.registerPlugin(UniverDocsThreadCommentUIPlugin);
univer.registerPlugin(UniverDocsHyperLinkUIPlugin);
univer.registerPlugin(UniverDocsMentionUIPlugin);
univer.registerPlugin(UniverDocsQuickInsertUIPlugin);

if (!IS_E2E) {
    univer.createUnit(UniverInstanceType.UNIVER_DOC, DEFAULT_DOCUMENT_DATA_SIMPLE);
    univer.registerPlugin(UniverDebuggerPlugin);
} else {
    univer.registerPlugin(UniverDebuggerPlugin, {
        fab: false,
        performanceMonitor: {
            enabled: false,
        },
    });
}

// use for console test
declare global {
    // eslint-disable-next-line ts/naming-convention
    interface Window {
        univer?: Univer;
    }
}

window.univer = univer;
const injector = univer.__getInjector();
const userManagerService = injector.get(UserManagerService);

const mockUser = {
    userID: 'Owner_qxVnhPbQ',
    name: 'Owner',
    avatar: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAInSURBVHgBtZU9TxtBEIbfWRzFSIdkikhBSqRQkJqkCKTCFkqVInSUSaT0wC8w/gXxD4gU2nRJkXQWhAZowDUUWKIwEgWWbEEB3mVmx3dn4DA2nB/ppNuPeWd29mMIPXDr+RxwtgRHeW6+guNPRxogqnL7Dwz9psJ27S4NShaeZTH3kwXy6I81dlRKcmRui88swdq9AcSFL7Buz1Vmlns64MiLsCjzwnIYHLH57tbfFbs7KRaXyEU8FVZofqccOfA5l7Q8LPIkGrwnb2RPNEXWFVMUF3L+kDCk0btDDAMzOm5YfAHDwp4tG74wnzAsiOYMnJ3GoDybA7IT98/jm5+JNnfiIzAS6LlqHQBN/i6b2t/cV1Hh6BfwYlHnHP4AXi5q/8kmMMpOs8+BixZw/Fd6xUEHEbnkgclvQP2fGp7uShRKnQ3G32rkjV1th8JhIGG7tR/JyjGteSOZELwGMmNqIIigRCLRh2OZIE6BjItdd7pCW6Uhm1zzkUtungSxwEUzNpQ+GQumtH1ej1MqgmNT6vwmhCq5yuwq56EYTbgeQUz3yvrpV1b4ok3nYJ+eYhgYmjRUqErx2EDq0Fr8FhG++iqVGqxlUJI/70Ar0UgJaWHj6hYVHJrfKssAHot1JfqwE9WVWzXZVd5z2Ws/4PnmtEjkXeKJDvxUecLbWOXH/DP6QQ4J72NS0adedp1aseBfXP8odlZFfPvBF7SN/8hky1TYuPOAXAEipMx15u5ToAAAAABJRU5ErkJggg==',
    anonymous: false,
    canBindAnonymous: false,
};
userManagerService.setCurrentUser(mockUser);
window.univerAPI = FUniver.newAPI(univer);

// core: set readonly
setTimeout(() => {
    const univerAPI = window.univerAPI;
    const activeDocument = univerAPI?.getActiveDocument();

    if (activeDocument) {
        // 设置文档为只读模式(类似 Excel 的 setEditable)
        activeDocument.setEditable(false);

        console.log('✅ 文档已设置为只读模式');
        console.log('💡 可以在控制台使用以下命令切换:');
        console.log('   - window.univerAPI.getActiveDocument().setEditable(false)  // 只读');
        console.log('   - window.univerAPI.getActiveDocument().setEditable(true)   // 可编辑');
    }
}, 3000);

Pull Request Checklist

  • Related tickets or issues have been linked in the PR description (or missing issue).
  • Naming convention is followed.
  • Unit tests have been added for the changes (if applicable).
  • Breaking changes have been documented (or no breaking changes introduced in this PR).

@univer-bot
Copy link

univer-bot bot commented Nov 9, 2025

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿

Origin Title: feat(docs): support setting read-only

Title: feat(docs): support setting read-only


close #xxx

Description

This PR implements read-only mode for Univer Docs

Key Changes

  1. Permission System

    • Added DocumentEditablePermission permission point (similar to Sheets' WorkbookEditablePermission)
    • Integrated with IPermissionService for centralized permission management
  2. Facade API

    • Added FDocument.setEditable(value: boolean) method
    • Usage: univerAPI.getActiveDocument().setEditable(false)
  3. Command & UI Protection

    • Added permission checks to all editing commands (insert, delete, paste, list operations, etc.)
    • Added getCurrentDocRangeDisable$() observable for reactive UI updates
    • Updated all menu items and context menus to respect read-only state

Testing

  • step1: replace with the following code examples/src/docs/main.ts pnpm run dev
  • step2: pnpm run dev
  • step3: go to localhost:3000/docs

Then you will find that the docs are set to read-only status after 3 seconds

Pull Request Checklist

  • Related tickets or issues have been linked in the PR description (or missing issue).
  • Naming convention is followed.
  • Unit tests have been added for the changes (if applicable).
  • Breaking changes have been documented (or no breaking changes introduced in this PR).

@github-actions
Copy link

github-actions bot commented Nov 9, 2025

View Deployment

📑 Demo (React@19) Demo (React@16) 📚 Storybook
🔗 Preview link 🔗 Preview link 🔗 Preview link

@electroluxcode
Copy link
Author

electroluxcode commented Nov 12, 2025

May I ask if there is any problem with this PR @jikkai

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