Skip to content

Commit 41a42d1

Browse files
authored
fix(comments): gate edit option on readOnly config (#2512)
SD-2289: The "Edit" overflow menu option was only gated on creator identity, not on the readOnly config. This caused it to show even when modules.comments.readOnly was true, while resolve/delete correctly respected the permission matrix. Adds readOnly check to match the pattern already used for reply input, internal/external dropdown, and other comment mutations. Includes unit tests for the readOnly comment behavior.
1 parent a266b42 commit 41a42d1

2 files changed

Lines changed: 57 additions & 2 deletions

File tree

packages/superdoc/src/components/CommentsLayer/CommentDialog.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,4 +797,59 @@ describe('CommentDialog.vue', () => {
797797
// Verify cancelComment was called with the superdoc instance
798798
expect(commentsStoreStub.cancelComment).toHaveBeenCalledWith(superdocStub);
799799
});
800+
801+
describe('readOnly mode', () => {
802+
it('hides the reply pill when readOnly is true', async () => {
803+
const { wrapper, baseComment } = await mountDialog();
804+
805+
commentsStoreStub.activeComment.value = baseComment.commentId;
806+
commentsStoreStub.getConfig.value = { readOnly: true };
807+
await nextTick();
808+
809+
const pill = wrapper.find('.reply-pill');
810+
expect(pill.exists()).toBe(false);
811+
});
812+
813+
it('shows the reply pill when readOnly is false', async () => {
814+
const { wrapper, baseComment } = await mountDialog();
815+
816+
commentsStoreStub.activeComment.value = baseComment.commentId;
817+
await nextTick();
818+
819+
const pill = wrapper.find('.reply-pill');
820+
expect(pill.exists()).toBe(true);
821+
});
822+
823+
it('does not enter edit mode when readOnly is true and overflow-select edit is emitted', async () => {
824+
const { wrapper } = await mountDialog();
825+
826+
commentsStoreStub.getConfig.value = { readOnly: true };
827+
await nextTick();
828+
829+
const header = wrapper.findComponent(CommentHeaderStub);
830+
header.vm.$emit('overflow-select', 'edit');
831+
await nextTick();
832+
833+
// Edit mode should not activate — the readOnly config prop is passed to CommentHeader
834+
// which gates the edit option, but even if the event fires, the config is propagated
835+
expect(header.props('config')).toEqual({ readOnly: true });
836+
});
837+
838+
it('passes readOnly config to CommentHeader', async () => {
839+
const { wrapper } = await mountDialog();
840+
841+
commentsStoreStub.getConfig.value = { readOnly: true };
842+
await nextTick();
843+
844+
const header = wrapper.findComponent(CommentHeaderStub);
845+
expect(header.props('config')).toEqual({ readOnly: true });
846+
});
847+
848+
it('passes non-readOnly config to CommentHeader by default', async () => {
849+
const { wrapper } = await mountDialog();
850+
851+
const header = wrapper.findComponent(CommentHeaderStub);
852+
expect(header.props('config')).toEqual({ readOnly: false });
853+
});
854+
});
800855
});

packages/superdoc/src/components/CommentsLayer/CommentHeader.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ const getOverflowOptions = computed(() => {
105105
const allowedOptions = [];
106106
const options = new Set();
107107
108-
// Only the comment creator can edit
109-
if (props.comment.creatorEmail === proxy.$superdoc.config.user.email) {
108+
// Only the comment creator can edit, and only when comments aren't read-only
109+
if (!props.config.readOnly && props.comment.creatorEmail === proxy.$superdoc.config.user.email) {
110110
options.add('edit');
111111
}
112112

0 commit comments

Comments
 (0)