fix(comment): fix comments-related issues (#6712)

This commit is contained in:
wpxp123456
2026-03-20 11:40:24 +08:00
committed by GitHub
parent 6d84a00d7d
commit f1fbcfea2a
37 changed files with 216 additions and 95 deletions
+1 -1
View File
@@ -39,5 +39,5 @@ export function isInternalEditorID(id: string) {
}
export function isCommentEditorID(id: string) {
return id === DOCS_COMMENT_EDITOR_UNIT_ID_KEY;
return id.startsWith(DOCS_COMMENT_EDITOR_UNIT_ID_KEY);
}
@@ -15,8 +15,7 @@
*/
import { describe, expect, it, vi } from 'vitest';
import { DocThreadCommentPanel } from '../../../views/doc-thread-comment-panel';
import { DOCS_THREAD_COMMENT_PANEL } from '../../../common/const';
import { ShowCommentPanelOperation, ToggleCommentPanelOperation } from '../show-comment-panel.operation';
describe('ShowCommentPanelOperation', () => {
@@ -48,7 +47,7 @@ describe('ShowCommentPanelOperation', () => {
expect(ok).toBe(true);
expect(open).toHaveBeenCalledWith(expect.objectContaining({
children: { label: DocThreadCommentPanel.componentKey },
children: { label: DOCS_THREAD_COMMENT_PANEL },
width: 320,
}));
expect(setPanelVisible).toHaveBeenCalledWith(true);
@@ -68,7 +67,7 @@ describe('ToggleCommentPanelOperation', () => {
const close = vi.fn();
const sidebarService = {
options: { children: { label: DocThreadCommentPanel.componentKey } },
options: { children: { label: DOCS_THREAD_COMMENT_PANEL } },
open: vi.fn(),
close,
};
@@ -23,9 +23,8 @@ import { IRenderManagerService } from '@univerjs/engine-render';
import { getDT } from '@univerjs/thread-comment';
import { ThreadCommentPanelService } from '@univerjs/thread-comment-ui';
import { ISidebarService } from '@univerjs/ui';
import { DEFAULT_DOC_SUBUNIT_ID } from '../../common/const';
import { DEFAULT_DOC_SUBUNIT_ID, DOCS_THREAD_COMMENT_PANEL } from '../../common/const';
import { DocThreadCommentService } from '../../services/doc-thread-comment.service';
import { DocThreadCommentPanel } from '../../views/doc-thread-comment-panel';
export interface IShowCommentPanelOperationParams {
activeComment: ActiveCommentInfo;
@@ -38,10 +37,10 @@ export const ShowCommentPanelOperation: ICommand<IShowCommentPanelOperationParam
const panelService = accessor.get(ThreadCommentPanelService);
const sidebarService = accessor.get(ISidebarService);
if (!panelService.panelVisible || sidebarService.options.children?.label !== DocThreadCommentPanel.componentKey) {
if (!panelService.panelVisible || sidebarService.options.children?.label !== DOCS_THREAD_COMMENT_PANEL) {
sidebarService.open({
header: { title: 'threadCommentUI.panel.title' },
children: { label: DocThreadCommentPanel.componentKey },
children: { label: DOCS_THREAD_COMMENT_PANEL },
width: 320,
onClose: () => panelService.setPanelVisible(false),
});
@@ -63,10 +62,10 @@ export const ToggleCommentPanelOperation: ICommand = {
const panelService = accessor.get(ThreadCommentPanelService);
const sidebarService = accessor.get(ISidebarService);
if (!panelService.panelVisible || sidebarService.options.children?.label !== DocThreadCommentPanel.componentKey) {
if (!panelService.panelVisible || sidebarService.options.children?.label !== DOCS_THREAD_COMMENT_PANEL) {
sidebarService.open({
header: { title: 'threadCommentUI.panel.title' },
children: { label: DocThreadCommentPanel.componentKey },
children: { label: DOCS_THREAD_COMMENT_PANEL },
width: 320,
onClose: () => panelService.setPanelVisible(false),
});
@@ -14,6 +14,8 @@
* limitations under the License.
*/
export const DOCS_THREAD_COMMENT_PANEL = 'univer.doc.thread-comment-panel';
export const PLUGIN_NAME = 'DOC_THREAD_COMMENT_UI_PLUGIN';
export const DEFAULT_DOC_SUBUNIT_ID = 'default_doc';
@@ -15,7 +15,7 @@
*/
import { describe, expect, it, vi } from 'vitest';
import { DOCS_THREAD_COMMENT_PANEL } from '../../common/const';
import { DocThreadCommentPanel } from '../../views/doc-thread-comment-panel';
import { DocThreadCommentUIController } from '../doc-thread-comment-ui.controller';
@@ -33,7 +33,7 @@ describe('DocThreadCommentUIController', () => {
expect(registerCommand).toHaveBeenCalled();
expect(mergeMenu).toHaveBeenCalled();
expect(registerComponent).toHaveBeenCalledWith(DocThreadCommentPanel.componentKey, DocThreadCommentPanel);
expect(registerComponent).toHaveBeenCalledWith(DOCS_THREAD_COMMENT_PANEL, DocThreadCommentPanel);
controller.dispose();
});
@@ -20,6 +20,7 @@ import { ComponentManager, IMenuManagerService } from '@univerjs/ui';
import { AddDocCommentComment } from '../commands/commands/add-doc-comment.command';
import { DeleteDocCommentComment } from '../commands/commands/delete-doc-comment.command';
import { ShowCommentPanelOperation, StartAddCommentOperation, ToggleCommentPanelOperation } from '../commands/operations/show-comment-panel.operation';
import { DOCS_THREAD_COMMENT_PANEL } from '../common/const';
import { menuSchema } from '../menu/schema';
import { DocThreadCommentPanel } from '../views/doc-thread-comment-panel';
@@ -53,7 +54,7 @@ export class DocThreadCommentUIController extends Disposable {
private _initComponents() {
([
[DocThreadCommentPanel.componentKey, DocThreadCommentPanel],
[DOCS_THREAD_COMMENT_PANEL, DocThreadCommentPanel],
['CommentIcon', CommentIcon],
] as const).forEach(([id, comp]) => {
this.disposeWithMe(
@@ -121,5 +121,3 @@ export const DocThreadCommentPanel = () => {
/>
);
};
DocThreadCommentPanel.componentKey = 'univer.doc.thread-comment-panel';
@@ -35,7 +35,7 @@ export const useLeftAndRightArrow = (isNeed: boolean, selectingMode: boolean, ed
return;
}
const editorId = editor.getEditorId();
const operationId = `sheet.formula-embedding-editor.${editorId}`;
const operationId = `doc.rich-text-editor.${editorId}`;
const d = new DisposableCollection();
const handleMoveInEditor = (keycode: KeyCode, metaKey?: MetaKeys) => {
if (onMoveInEditorRef.current) {
@@ -14,15 +14,17 @@
* limitations under the License.
*/
import type { ICommand } from '@univerjs/core';
import type { IOperation } from '@univerjs/core';
import type { ISheetLocation } from '@univerjs/sheets';
import { CommandType, IUniverInstanceService } from '@univerjs/core';
import { getSheetCommandTarget, SheetsSelectionsService } from '@univerjs/sheets';
import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';
import { ThreadCommentPanelService } from '@univerjs/thread-comment-ui';
import { ISidebarService } from '@univerjs/ui';
import { SheetsThreadCommentPopupService } from '../../services/sheets-thread-comment-popup.service';
import { SHEETS_THREAD_COMMENT_PANEL } from '../../types/const';
export const ShowAddSheetCommentModalOperation: ICommand = {
export const ShowAddSheetCommentModalOperation: IOperation = {
type: CommandType.OPERATION,
id: 'sheets.operation.show-comment-modal',
handler(accessor) {
@@ -66,3 +68,26 @@ export const ShowAddSheetCommentModalOperation: ICommand = {
return true;
},
};
export const ToggleSheetCommentPanelOperation: IOperation = {
id: 'sheets.operation.toggle-comment-panel',
type: CommandType.OPERATION,
handler(accessor) {
const sidebarService = accessor.get(ISidebarService);
const panelService = accessor.get(ThreadCommentPanelService);
if (panelService.panelVisible) {
sidebarService.close();
panelService.setPanelVisible(false);
} else {
sidebarService.open({
header: { title: 'threadCommentUI.panel.title' },
children: { label: SHEETS_THREAD_COMMENT_PANEL },
width: 360,
});
panelService.setPanelVisible(true);
}
return true;
},
};
@@ -21,7 +21,7 @@ import { serializeRange, singleReferenceToGrid } from '@univerjs/engine-formula'
import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';
import { COPY_TYPE, ISheetClipboardService } from '@univerjs/sheets-ui';
import { AddCommentMutation, DeleteCommentMutation, IThreadCommentDataSourceService } from '@univerjs/thread-comment';
import { SHEETS_THREAD_COMMENT } from '../types/const';
import { PLUGIN_NAME } from '../types/const';
const transformRef = (ref: string, source: { row: number; column: number }, target: { row: number; column: number }) => {
const refObj = singleReferenceToGrid(ref);
@@ -56,7 +56,7 @@ export class SheetsThreadCommentCopyPasteController extends Disposable {
private _initClipboardHook() {
this.disposeWithMe(
this._sheetClipboardService.addClipboardHook({
id: SHEETS_THREAD_COMMENT,
id: PLUGIN_NAME,
onBeforeCopy: (unitId, subUnitId, range) => {
this._copyInfo = {
unitId,
@@ -0,0 +1,106 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { ICommandInfo } from '@univerjs/core';
import type { IAddCommentCommandParams, IDeleteCommentCommandParams, IDeleteCommentTreeCommandParams, IResolveCommentCommandParams, IUpdateCommentCommandParams } from '@univerjs/thread-comment';
import { Disposable, ICommandService, Inject, LocaleService } from '@univerjs/core';
import { singleReferenceToGrid } from '@univerjs/engine-formula';
import { RangeProtectionPermissionViewPoint, SheetPermissionCheckController, WorkbookCommentPermission, WorksheetViewPermission } from '@univerjs/sheets';
import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';
import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ResolveCommentCommand, UpdateCommentCommand } from '@univerjs/thread-comment';
import { ShowAddSheetCommentModalOperation, ToggleSheetCommentPanelOperation } from '../commands/operations/comment.operation';
export class SheetsThreadCommentPermissionController extends Disposable {
constructor(
@Inject(LocaleService) private _localeService: LocaleService,
@ICommandService private readonly _commandService: ICommandService,
@Inject(SheetPermissionCheckController) private readonly _sheetPermissionCheckController: SheetPermissionCheckController,
@Inject(SheetsThreadCommentModel) private readonly _sheetsThreadCommentModel: SheetsThreadCommentModel
) {
super();
this._commandExecutedListener();
}
private _commandExecutedListener() {
this.disposeWithMe(
this._commandService.beforeCommandExecuted((command: ICommandInfo) => {
const { id } = command;
if (id === ShowAddSheetCommentModalOperation.id || id === ToggleSheetCommentPanelOperation.id) {
const permission = this._sheetPermissionCheckController.permissionCheckWithoutRange({
workbookTypes: [WorkbookCommentPermission],
worksheetTypes: [WorksheetViewPermission],
});
if (!permission) {
this._sheetPermissionCheckController.blockExecuteWithoutPermission(this._localeService.t('permission.dialog.commentErr'));
}
} else if (id === AddCommentCommand.id) {
const params = command.params as IAddCommentCommandParams;
const { unitId, subUnitId, comment } = params;
const location = singleReferenceToGrid(comment.ref);
const { row, column } = location;
const permission = this._sheetPermissionCheckController.permissionCheckWithRanges({
workbookTypes: [WorkbookCommentPermission],
worksheetTypes: [WorksheetViewPermission],
rangeTypes: [RangeProtectionPermissionViewPoint],
}, [{ startRow: row, startColumn: column, endRow: row, endColumn: column }], unitId, subUnitId);
if (!permission) {
this._sheetPermissionCheckController.blockExecuteWithoutPermission(this._localeService.t('permission.dialog.commentErr'));
}
} else if (id === UpdateCommentCommand.id) {
const params = command.params as IUpdateCommentCommandParams;
const { unitId, subUnitId, payload } = params;
const { commentId } = payload;
const comment = this._sheetsThreadCommentModel.getComment(unitId, subUnitId, commentId);
if (comment) {
const location = singleReferenceToGrid(comment.ref);
const { row, column } = location;
const permission = this._sheetPermissionCheckController.permissionCheckWithRanges({
workbookTypes: [WorkbookCommentPermission],
worksheetTypes: [WorksheetViewPermission],
rangeTypes: [RangeProtectionPermissionViewPoint],
}, [{ startRow: row, startColumn: column, endRow: row, endColumn: column }], unitId, subUnitId);
if (!permission) {
this._sheetPermissionCheckController.blockExecuteWithoutPermission(this._localeService.t('permission.dialog.commentErr'));
}
}
} else if (id === ResolveCommentCommand.id || id === DeleteCommentCommand.id || id === DeleteCommentTreeCommand.id) {
const params = command.params as IResolveCommentCommandParams | IDeleteCommentCommandParams | IDeleteCommentTreeCommandParams;
const { unitId, subUnitId, commentId } = params;
const comment = this._sheetsThreadCommentModel.getComment(unitId, subUnitId, commentId);
if (comment) {
const location = singleReferenceToGrid(comment.ref);
const { row, column } = location;
const permission = this._sheetPermissionCheckController.permissionCheckWithRanges({
workbookTypes: [WorkbookCommentPermission],
worksheetTypes: [WorksheetViewPermission],
rangeTypes: [RangeProtectionPermissionViewPoint],
}, [{ startRow: row, startColumn: column, endRow: row, endColumn: column }], unitId, subUnitId);
if (!permission) {
this._sheetPermissionCheckController.blockExecuteWithoutPermission(this._localeService.t('permission.dialog.commentErr'));
}
}
}
})
);
}
}
@@ -16,11 +16,10 @@
import { Disposable, Inject } from '@univerjs/core';
import { CommentIcon } from '@univerjs/icons';
import { THREAD_COMMENT_PANEL } from '@univerjs/thread-comment-ui';
import { ComponentManager, IMenuManagerService, IShortcutService } from '@univerjs/ui';
import { AddCommentShortcut } from '../menu/menu';
import { menuSchema } from '../menu/schema';
import { SHEETS_THREAD_COMMENT_MODAL } from '../types/const';
import { SHEETS_THREAD_COMMENT_MODAL, SHEETS_THREAD_COMMENT_PANEL } from '../types/const';
import { SheetsThreadCommentCell } from '../views/sheets-thread-comment-cell';
import { SheetsThreadCommentPanel } from '../views/sheets-thread-comment-panel';
@@ -47,7 +46,7 @@ export class SheetsThreadCommentController extends Disposable {
private _initComponent() {
([
[SHEETS_THREAD_COMMENT_MODAL, SheetsThreadCommentCell],
[THREAD_COMMENT_PANEL, SheetsThreadCommentPanel],
[SHEETS_THREAD_COMMENT_PANEL, SheetsThreadCommentPanel],
['CommentIcon', CommentIcon],
] as const).forEach(([key, comp]) => {
this.disposeWithMe(
@@ -16,11 +16,10 @@
import './global.css';
export { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation';
export { ShowAddSheetCommentModalOperation, ToggleSheetCommentPanelOperation } from './commands/operations/comment.operation';
export type { IUniverSheetsThreadCommentUIConfig } from './config/config';
export { UniverSheetsThreadCommentUIPlugin } from './plugin';
export { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service';
export { SHEETS_THREAD_COMMENT } from './types/const';
export { IThreadCommentDataSourceService } from '@univerjs/thread-comment';
export {
AddCommentCommand,
@@ -19,9 +19,8 @@ import type { IShortcutItem } from '@univerjs/ui';
import { UniverInstanceType } from '@univerjs/core';
import { RangeProtectionPermissionViewPoint, WorkbookCommentPermission, WorksheetViewPermission } from '@univerjs/sheets';
import { getCurrentRangeDisable$, whenSheetEditorFocused } from '@univerjs/sheets-ui';
import { ToggleSheetCommentPanelOperation } from '@univerjs/thread-comment-ui';
import { getMenuHiddenObservable, KeyCode, MenuItemType, MetaKeys } from '@univerjs/ui';
import { ShowAddSheetCommentModalOperation } from '../commands/operations/comment.operation';
import { ShowAddSheetCommentModalOperation, ToggleSheetCommentPanelOperation } from '../commands/operations/comment.operation';
export const threadCommentMenuFactory = (accessor: IAccessor) => {
return {
@@ -15,9 +15,8 @@
*/
import type { MenuSchemaType } from '@univerjs/ui';
import { ToggleSheetCommentPanelOperation } from '@univerjs/thread-comment-ui';
import { ContextMenuGroup, ContextMenuPosition, RibbonInsertGroup } from '@univerjs/ui';
import { ShowAddSheetCommentModalOperation } from '../commands/operations/comment.operation';
import { ShowAddSheetCommentModalOperation, ToggleSheetCommentPanelOperation } from '../commands/operations/comment.operation';
import { threadCommentMenuFactory, threadPanelMenuFactory } from './menu';
export const menuSchema: MenuSchemaType = {
@@ -20,19 +20,20 @@ import { DependentOn, ICommandService, IConfigService, Inject, Injector, merge,
import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment';
import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui';
import pkg from '../package.json';
import { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation';
import { ShowAddSheetCommentModalOperation, ToggleSheetCommentPanelOperation } from './commands/operations/comment.operation';
import { defaultPluginConfig, SHEETS_THREAD_COMMENT_UI_PLUGIN_CONFIG_KEY } from './config/config';
import { SheetsThreadCommentRenderController } from './controllers/render-controllers/render.controller';
import { SheetsThreadCommentCopyPasteController } from './controllers/sheets-thread-comment-copy-paste.controller';
import { SheetsThreadCommentHoverController } from './controllers/sheets-thread-comment-hover.controller';
import { SheetsThreadCommentPermissionController } from './controllers/sheets-thread-comment-permission.controller';
import { SheetsThreadCommentPopupController } from './controllers/sheets-thread-comment-popup.controller';
import { SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller';
import { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service';
import { SHEETS_THREAD_COMMENT } from './types/const';
import { PLUGIN_NAME } from './types/const';
@DependentOn(UniverThreadCommentUIPlugin, UniverSheetsThreadCommentPlugin)
export class UniverSheetsThreadCommentUIPlugin extends Plugin {
static override pluginName = SHEETS_THREAD_COMMENT;
static override pluginName = PLUGIN_NAME;
static override packageName = pkg.name;
static override version = pkg.version;
static override type = UniverInstanceType.UNIVER_SHEET;
@@ -65,11 +66,15 @@ export class UniverSheetsThreadCommentUIPlugin extends Plugin {
[SheetsThreadCommentHoverController],
[SheetsThreadCommentPopupController],
[SheetsThreadCommentPopupService],
[SheetsThreadCommentPermissionController],
] as Dependency[]).forEach((dep) => {
this._injector.add(dep);
});
[ShowAddSheetCommentModalOperation].forEach((command) => {
[
ShowAddSheetCommentModalOperation,
ToggleSheetCommentPanelOperation,
].forEach((command) => {
this._commandService.registerCommand(command);
});
@@ -84,5 +89,6 @@ export class UniverSheetsThreadCommentUIPlugin extends Plugin {
this._injector.get(SheetsThreadCommentCopyPasteController);
this._injector.get(SheetsThreadCommentHoverController);
this._injector.get(SheetsThreadCommentPopupController);
this._injector.get(SheetsThreadCommentPermissionController);
}
}
@@ -15,4 +15,6 @@
*/
export const SHEETS_THREAD_COMMENT_MODAL = 'univer.sheet.thread-comment-modal';
export const SHEETS_THREAD_COMMENT = 'SHEET_THREAD_COMMENT';
export const SHEETS_THREAD_COMMENT_PANEL = 'univer.sheet.thread-comment-panel';
export const PLUGIN_NAME = 'SHEET_THREAD_COMMENT_UI_PLUGIN';
@@ -17,7 +17,7 @@
import type { Workbook } from '@univerjs/core';
import { IUniverInstanceService, Tools, UniverInstanceType } from '@univerjs/core';
import { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment';
import { ThreadCommentTree } from '@univerjs/thread-comment-ui';
import { ThreadCommentTree, ThreadCommentTreeLocation } from '@univerjs/thread-comment-ui';
import { useDependency, useObservable } from '@univerjs/ui';
import { SheetsThreadCommentPopupService } from '../../services/sheets-thread-comment-popup.service';
@@ -46,7 +46,7 @@ export const SheetsThreadCommentCell = () => {
onClick={() => {
sheetsThreadCommentPopupService.persistPopup();
}}
prefix="cell"
location={ThreadCommentTreeLocation.CELL}
id={rootId}
unitId={unitId}
subUnitId={subUnitId}
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'El full de càlcul està protegit i no teniu permís per imprimir. Per imprimir, contacteu amb el creador.',
formulaErr: 'L\'interval o l\'interval referenciat està protegit, i no teniu permís d\'edició. Per editar, contacteu amb el creador.',
hyperLinkErr: 'L\'interval està protegit i no teniu permís per establir hipervincles. Per establir hipervincles, contacteu amb el creador.',
commentErr: 'L\'interval está protegido y no tienes permiso para comentar. Para comentar, contacta con el creador.',
},
button: {
confirm: 'Confirmar',
+1
View File
@@ -477,6 +477,7 @@ const locale = {
printErr: 'The worksheet is protected, and you do not have permission to print. To print, please contact the creator.',
formulaErr: 'The range or the referenced range is protected, and you do not have edit permission. To edit, please contact the creator.',
hyperLinkErr: 'The range is protected, and you do not have permission to set hyperlinks. To set hyperlinks, please contact the creator.',
commentErr: 'The range is protected, and you do not have permission to comment. To comment, please contact the creator.',
},
button: {
confirm: 'Confirm',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'La hoja de cálculo está protegida y no tienes permiso para imprimir. Para imprimir, contacta al creador.',
formulaErr: 'El rango o el rango referenciado está protegido, y no tienes permiso de edición. Para editar, contacta al creador.',
hyperLinkErr: 'El rango está protegido y no tienes permiso para establecer hipervínculos. Para establecer hipervínculos, contacta al creador.',
commentErr: 'El rango está protegido y no tienes permiso para comentar. Para comentar, contacta al creador.',
},
button: {
confirm: 'Confirmar',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'کاربرگ محافظت شده است و شما مجوز چاپ را ندارید. برای چاپ، لطفا با سازنده تماس بگیرید.',
formulaErr: 'محدوده یا محدوده مرجع محافظت شده است و شما مجوز ویرایش را ندارید. برای ویرایش، لطفا با سازنده تماس بگیرید.',
hyperLinkErr: 'محدوده محافظت شده است و شما مجوز تنظیم هایپرلینک را ندارید. برای تنظیم هایپرلینک، لطفا با سازنده تماس بگیرید.',
commentErr: 'محدوده محافظت شده است و شما مجوز نظر دادن را ندارید. برای نظر دادن، لطفا با سازنده تماس بگیرید.',
},
button: {
confirm: 'تایید',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'La feuille de calcul est protégée, et vous n\'avez pas la permission d\'imprimer. Pour imprimer, veuillez contacter le créateur.',
formulaErr: 'La plage ou la plage référencée est protégée, et vous n\'avez pas la permission de modifier. Pour modifier, veuillez contacter le créateur.',
hyperLinkErr: 'La plage est protégée, et vous n\'avez pas la permission de définir des liens hypertextes. Pour définir des liens hypertextes, veuillez contacter le créateur.',
commentErr: 'La plage est protégée, et vous n\'avez pas la permission de commenter. Pour commenter, veuillez contacter le créateur.',
},
button: {
confirm: 'Confirmer',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'このワークシートは保護されており、印刷できません。印刷するには作成者に連絡してください。',
formulaErr: 'この範囲または参照された範囲は保護されており、数式を編集できません。編集するには作成者に連絡してください。',
hyperLinkErr: 'この範囲は保護されており、ハイパーリンクを設定する権限がありません。設定するには作成者に連絡してください。',
commentErr: 'この範囲は保護されており、コメントする権限がありません。コメントするには作成者に連絡してください。',
},
button: {
confirm: '確認',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: '이 워크시트는 보호되어 있어 인쇄할 수 없습니다. 인쇄하려면 작성자에게 문의하세요.',
formulaErr: '이 범위 또는 참조된 범위는 보호되어 있어 수식을 편집할 수 없습니다. 편집하려면 작성자에게 문의하세요.',
hyperLinkErr: '해당 범위는 보호되어 있어 하이퍼링크 설정 권한이 없습니다. 설정하려면 작성자에게 문의하세요.',
commentErr: '해당 범위는 보호되어 있어 댓글 권한이 없습니다. 댓글을 달려면 작성자에게 문의하세요.',
},
button: {
confirm: '확인',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'Лист защищен, и у вас нет разрешения на печать. Для печати свяжитесь с создателем.',
formulaErr: 'Диапазон или ссылочный диапазон защищен, и у вас нет разрешения на редактирование. Для редактирования свяжитесь с создателем.',
hyperLinkErr: 'Диапазон защищен, и у вас нет разрешения на установку гиперссылок. Для установки гиперссылок свяжитесь с создателем.',
commentErr: 'Диапазон защищен, и у вас нет разрешения на комментирование. Для комментирования свяжитесь с создателем.',
},
button: {
confirm: 'Подтвердить',
+1
View File
@@ -479,6 +479,7 @@ const locale: typeof enUS = {
printErr: 'Hárok je chránený a nemáte oprávnenie na tlač. Ak chcete tlačiť, kontaktujte autora.',
formulaErr: 'Rozsah alebo referenčný rozsah je chránený a nemáte oprávnenie na úpravu. Ak chcete upravovať, kontaktujte autora.',
hyperLinkErr: 'Rozsah je chránený a nemáte oprávnenie nastavovať hypertextové odkazy. Ak chcete nastavovať hypertextové odkazy, kontaktujte autora.',
commentErr: 'Rozsah je chránený a nemáte oprávnění pro komentování. Pokud chcete komentovat, kontaktujte autora.',
},
button: {
confirm: 'Potvrdiť',
+1
View File
@@ -476,6 +476,7 @@ const locale: typeof enUS = {
printErr: 'Trang bảng này đã được bảo vệ, hiện không có quyền in. Nếu cần in, vui lòng liên hệ với người tạo.',
formulaErr: 'Phạm vi hoặc phạm vi tham chiếu này đã được bảo vệ, hiện không có quyền chỉnh sửa. Nếu cần chỉnh sửa, vui lòng liên hệ với người tạo.',
hyperLinkErr: 'Phạm vi này đã được bảo vệ, hiện không có quyền thiết lập liên kết. Nếu cần thiết lập liên kết, vui lòng liên hệ với người tạo.',
commentErr: 'Phạm vi này đã được bảo vệ, hiện không có quyền bình luận. Nếu cần bình luận, vui lòng liên hệ với người tạo.',
},
button: {
confirm: 'Xác nhận',
+1
View File
@@ -477,6 +477,7 @@ const locale: typeof enUS = {
printErr: '该工作表已被保护,目前无打印权限。如需打印,请联系创建者。',
formulaErr: '该范围或者引用范围已被保护,目前无编辑权限。如需编辑,请联系创建者。',
hyperLinkErr: '该范围已被保护,目前无设置超链接权限。如需设置超链接,请联系创建者。',
commentErr: '该范围已被保护,目前无评论权限。如需评论,请联系创建者。',
},
button: {
confirm: '确认',
+1
View File
@@ -477,6 +477,7 @@ const locale: typeof enUS = {
printErr: '該工作表已被保護,目前無列印權限。如需列印,請聯絡創作者。 ',
formulaErr: '該範圍或引用範圍已被保護,目前無編輯權限。如需編輯,請聯絡創建者。 ',
hyperLinkErr: '範圍已被保護,目前無設定超連結權限。如需設定超鏈接,請聯絡建立者。 ',
commentErr: '該範圍已被保護,目前無評論權限。如需評論,請聯絡創建者。 ',
},
button: {
confirm: '確認',
@@ -14,34 +14,9 @@
* limitations under the License.
*/
import type { IAccessor, ICommand } from '@univerjs/core';
import type { ICommand } from '@univerjs/core';
import { CommandType } from '@univerjs/core';
import { ISidebarService } from '@univerjs/ui';
import { ThreadCommentPanelService } from '../../services/thread-comment-panel.service';
import { THREAD_COMMENT_PANEL } from '../../types/const';
export const ToggleSheetCommentPanelOperation: ICommand = {
id: 'thread-comment-ui.operation.toggle-panel',
type: CommandType.OPERATION,
handler(accessor: IAccessor) {
const sidebarService = accessor.get(ISidebarService);
const panelService = accessor.get(ThreadCommentPanelService);
if (panelService.panelVisible) {
sidebarService.close();
panelService.setPanelVisible(false);
} else {
sidebarService.open({
header: { title: 'threadCommentUI.panel.title' },
children: { label: THREAD_COMMENT_PANEL },
width: 360,
});
panelService.setPanelVisible(true);
}
return true;
},
};
export interface ISetActiveCommentOperationParams {
unitId: string;
+2 -7
View File
@@ -16,16 +16,11 @@
import './global.css';
export {
type ISetActiveCommentOperationParams,
SetActiveCommentOperation,
ToggleSheetCommentPanelOperation,
} from './commands/operations/comment.operations';
export { type ISetActiveCommentOperationParams, SetActiveCommentOperation } from './commands/operations/comment.operations';
export type { IUniverThreadCommentUIConfig } from './config/config';
export { UniverThreadCommentUIPlugin } from './plugin';
export { type ActiveCommentInfo, ThreadCommentPanelService } from './services/thread-comment-panel.service';
export { THREAD_COMMENT_PANEL } from './types/const';
export { ThreadCommentPanel } from './views/thread-comment-panel';
export type { IThreadCommentPanelProps } from './views/thread-comment-panel';
export { ThreadCommentTree } from './views/thread-comment-tree';
export { ThreadCommentTree, ThreadCommentTreeLocation } from './views/thread-comment-tree';
export type { IThreadCommentTreeProps } from './views/thread-comment-tree';
+4 -2
View File
@@ -19,7 +19,7 @@ import type { IUniverThreadCommentUIConfig } from './config/config';
import { DependentOn, ICommandService, IConfigService, Inject, Injector, merge, mergeOverrideWithDependencies, Plugin, UniverInstanceType } from '@univerjs/core';
import { UniverThreadCommentPlugin } from '@univerjs/thread-comment';
import pkg from '../package.json';
import { SetActiveCommentOperation, ToggleSheetCommentPanelOperation } from './commands/operations/comment.operations';
import { SetActiveCommentOperation } from './commands/operations/comment.operations';
import { defaultPluginConfig, THREAD_COMMENT_UI_PLUGIN_CONFIG_KEY } from './config/config';
import { ThreadCommentPanelService } from './services/thread-comment-panel.service';
import { PLUGIN_NAME } from './types/const';
@@ -58,7 +58,9 @@ export class UniverThreadCommentUIPlugin extends Plugin {
this._injector.add(dep);
});
[ToggleSheetCommentPanelOperation, SetActiveCommentOperation].forEach((command) => {
[
SetActiveCommentOperation,
].forEach((command) => {
this._commandService.registerCommand(command);
});
}
@@ -14,8 +14,4 @@
* limitations under the License.
*/
export const THREAD_COMMENT_POPUP = 'thread-comment-popup';
export const THREAD_COMMENT_PANEL = 'thread-comment-panel';
export const PLUGIN_NAME = 'UNIVER_THREAD_COMMENT_UI_PLUGIN';
@@ -17,7 +17,7 @@
import type { IDocumentBody, IDocumentData, IUser } from '@univerjs/core';
import type { Editor, IKeyboardEventConfig } from '@univerjs/docs-ui';
import type { IThreadComment } from '@univerjs/thread-comment';
import { BuildTextUtils, DOCS_COMMENT_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, ICommandService, LocaleService, Tools, UniverInstanceType } from '@univerjs/core';
import { BuildTextUtils, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, ICommandService, LocaleService, Tools, UniverInstanceType } from '@univerjs/core';
import { Button, clsx } from '@univerjs/design';
import { BreakLineCommand, IEditorService, RichTextEditor } from '@univerjs/docs-ui';
import { KeyCode, useDependency } from '@univerjs/ui';
@@ -33,6 +33,7 @@ export interface IThreadCommentEditorProps {
unitId: string;
subUnitId: string;
type: UniverInstanceType;
editorId: string;
}
export interface IThreadCommentEditorInstance {
@@ -48,7 +49,7 @@ function getSnapshot(body: IDocumentBody): IDocumentData {
}
export const ThreadCommentEditor = forwardRef<IThreadCommentEditorInstance, IThreadCommentEditorProps>((props, ref) => {
const { comment, onSave, id, onCancel, autoFocus, unitId, type } = props;
const { comment, onSave, id, onCancel, autoFocus, unitId, type, editorId } = props;
const commandService = useDependency(ICommandService);
const localeService = useDependency(LocaleService);
const [editing, setEditing] = useState(false);
@@ -115,7 +116,7 @@ export const ThreadCommentEditor = forwardRef<IThreadCommentEditorInstance, IThr
<RichTextEditor
className="univer-w-full"
editorRef={editor}
editorId={DOCS_COMMENT_EDITOR_UNIT_ID_KEY}
editorId={editorId}
autoFocus={autoFocus}
keyboardEventConfig={keyboardEventConfig}
placeholder={localeService.t('threadCommentUI.editor.placeholder')}
@@ -26,7 +26,7 @@ import { useDependency, useObservable } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
import { SetActiveCommentOperation } from '../../commands/operations/comment.operations';
import { ThreadCommentPanelService } from '../../services/thread-comment-panel.service';
import { ThreadCommentTree } from '../thread-comment-tree';
import { ThreadCommentTree, ThreadCommentTreeLocation } from '../thread-comment-tree';
export interface IThreadCommentPanelProps {
unitId: string;
@@ -78,7 +78,7 @@ export const ThreadCommentPanel = (props: IThreadCommentPanelProps) => {
const commandService = useDependency(ICommandService);
const subUnitId = useObservable(subUnitId$);
const shouldScroll = useRef(true);
const prefix = 'panel';
const location = ThreadCommentTreeLocation.PANEL;
const currentUser = useObservable(userService.currentUser$);
const comments = useMemo(() => {
const allComments =
@@ -154,13 +154,13 @@ export const ThreadCommentPanel = (props: IThreadCommentPanelProps) => {
return;
}
const { unitId, subUnitId, commentId } = activeCommentId;
const id = `${prefix}-${unitId}-${subUnitId}-${commentId}`;
const id = `${location}-${unitId}-${subUnitId}-${commentId}`;
document.getElementById(id)?.scrollIntoView({ block: 'center' });
}, [activeCommentId]);
const renderComment = (comment: IThreadComment) => (
<ThreadCommentTree
prefix={prefix}
location={location}
getSubUnitName={getSubUnitName}
key={comment.id}
id={comment.id}
@@ -18,7 +18,7 @@ import type { IUser, UniverInstanceType } from '@univerjs/core';
import type { IAddCommentCommandParams, IThreadComment, IUpdateCommentCommandParams } from '@univerjs/thread-comment';
import type { IUniverUIConfig } from '@univerjs/ui';
import type { IThreadCommentEditorInstance } from '../thread-comment-editor';
import { generateRandomId, ICommandService, LocaleService, UserManagerService } from '@univerjs/core';
import { DOCS_COMMENT_EDITOR_UNIT_ID_KEY, generateRandomId, ICommandService, LocaleService, UserManagerService } from '@univerjs/core';
import { borderClassName, clsx, Dropdown, scrollbarClassName, Tooltip } from '@univerjs/design';
import { DeleteIcon, MoreHorizontalIcon, ReplyToCommentIcon, ResolvedIcon, SolveIcon } from '@univerjs/icons';
import {
@@ -37,6 +37,11 @@ import { SetActiveCommentOperation } from '../../commands/operations/comment.ope
import { ThreadCommentEditor } from '../thread-comment-editor';
import { transformDocument2TextNodes, transformTextNodes2Document } from '../thread-comment-editor/util';
export enum ThreadCommentTreeLocation {
CELL = 'CELL',
PANEL = 'PANEL',
};
export interface IThreadCommentTreeProps {
full?: boolean;
id?: string;
@@ -49,7 +54,7 @@ export interface IThreadCommentTreeProps {
showHighlight?: boolean;
onClose?: () => void;
getSubUnitName: (subUnitId: string) => string;
prefix?: string;
location: ThreadCommentTreeLocation;
autoFocus?: boolean;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
@@ -73,12 +78,13 @@ export interface IThreadCommentItemProps {
onAddComment?: (comment: IThreadComment) => boolean;
onDeleteComment?: (comment: IThreadComment) => boolean;
type: UniverInstanceType;
threadCommentEditorId: string;
}
const MOCK_ID = '__mock__';
const ThreadCommentItem = (props: IThreadCommentItemProps) => {
const { item, unitId, subUnitId, editing, onEditingChange, onReply, resolved, isRoot, onClose, onDeleteComment, type } = props;
const { item, unitId, subUnitId, editing, onEditingChange, onReply, resolved, isRoot, onClose, onDeleteComment, type, threadCommentEditorId } = props;
const commandService = useDependency(ICommandService);
const localeService = useDependency(LocaleService);
const userManagerService = useDependency(UserManagerService);
@@ -214,6 +220,7 @@ const ThreadCommentItem = (props: IThreadCommentItemProps) => {
autoFocus
unitId={unitId}
subUnitId={subUnitId}
editorId={threadCommentEditorId}
onSave={({ text, attachments }) => {
onEditingChange?.(false);
commandService.executeCommand(
@@ -272,7 +279,7 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
showHighlight,
onClose,
getSubUnitName,
prefix,
location,
autoFocus,
onMouseEnter,
onMouseLeave,
@@ -360,17 +367,18 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
const subUnitName = getSubUnitName(comments?.root.subUnitId ?? subUnitId);
const editorVisible = showEdit && !editingId && !resolved;
const title = `${refStr || comments?.root.ref || ''}${subUnitName ? ' · ' : ''}${subUnitName}`;
const threadCommentEditorId = `${DOCS_COMMENT_EDITOR_UNIT_ID_KEY}_${location}`;
return (
<div
id={`${prefix}-${unitId}-${subUnitId}-${id}`}
id={`${location}-${unitId}-${subUnitId}-${id}`}
className={clsx(`
univer-relative univer-box-border univer-rounded-md univer-bg-white univer-p-4
dark:!univer-bg-gray-900 dark:!univer-text-white
`, borderClassName, {
'univer-w-[278px]': !full,
'univer-w-full': full,
'univer-shadow': !resolved && (showHighlight || isHover || prefix === 'cell'),
'univer-shadow': !resolved && (showHighlight || isHover || location === ThreadCommentTreeLocation.CELL),
})}
style={style}
onClick={onClick}
@@ -460,6 +468,7 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
editing={editingId === item.id}
resolved={comments?.root.resolved}
type={type}
threadCommentEditorId={threadCommentEditorId}
onClose={onClose}
onEditingChange={(editing) => {
if (editing) {
@@ -502,22 +511,19 @@ export const ThreadCommentTree = (props: IThreadCommentTreeProps) => {
type={type}
unitId={unitId}
subUnitId={subUnitId}
editorId={threadCommentEditorId}
onSave={async ({ text, attachments }) => {
if (!currentUser?.userID || !comments?.root) {
throw new Error('[ThreadCommentTree] No current user or root comment found');
}
const comment: IThreadComment = {
text,
attachments,
dT: getDT(),
id: generateRandomId(),
ref: refStr!,
personId: currentUser?.userID,
personId: currentUser?.userID ?? '',
parentId: comments?.root.id,
unitId,
subUnitId,
threadId: comments?.root.threadId,
threadId: comments?.root.threadId ?? '',
};
if (onAddComment?.(comment) === false) {