Skip to content

Commit c0a1dc1

Browse files
committed
fix(web): keep readonly comment creation available
1 parent 188b573 commit c0a1dc1

2 files changed

Lines changed: 60 additions & 0 deletions

File tree

apps/web/src/components/FileViewer.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12553,6 +12553,10 @@ function HtmlViewer({
1255312553
const myMemberId = collab.member?.memberId ?? null;
1255412554
const iAmProjectOwner = collab.isOwner;
1255512555
const commentAuthoredByMe = (comment: PreviewComment | null | undefined): boolean => {
12556+
// No persisted comment means this is the create flow: the draft belongs
12557+
// to the current viewer, including a read-only member/admin annotating
12558+
// someone else's shared project.
12559+
if (!comment) return true;
1255612560
const authorId = comment?.authorMemberId ?? null;
1255712561
// A legacy shared comment without an author is deliberately owner-only.
1255812562
// Treating it as "mine" for every member made the client advertise a

apps/web/tests/components/FileViewer.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import { emptyManualEditStyles } from '../../src/edit-mode/types';
8484
import { __resetPreviewIsolationCache } from '../../src/runtime/powered-preview';
8585
import { readExpandedIndexCss } from '../helpers/read-expanded-css';
8686
import { resetWorkspaceContextCache } from '../../src/collab/useWorkspaceContext';
87+
import { CollabProvider, type CollabContextValue } from '../../src/collab/collab-context';
8788
import {
8889
buildWorkspacePermissions,
8990
buildWorkspaceSeatSummary,
@@ -5984,6 +5985,61 @@ describe('FileViewer tweaks toolbar', () => {
59845985
});
59855986
});
59865987

5988+
it('keeps the Comment CTA for a new element annotation in a viewer-only team project', async () => {
5989+
const collab: CollabContextValue = {
5990+
enabled: true,
5991+
member: { memberId: 'wm-1', name: 'Member', role: 'member' },
5992+
present: [],
5993+
publishedVersion: 1,
5994+
syncState: 'synced',
5995+
viewerOnly: true,
5996+
isOwner: false,
5997+
ownerDisplayName: 'Owner',
5998+
ownerRole: 'owner',
5999+
downloadPending: false,
6000+
reportChange: () => {},
6001+
requestPublish: () => {},
6002+
refreshPresence: () => {},
6003+
checkStatusNow: () => {},
6004+
};
6005+
6006+
render(
6007+
<CollabProvider value={collab}>
6008+
<FileViewer
6009+
projectId="project-1"
6010+
projectKind="prototype"
6011+
file={htmlPreviewFile()}
6012+
liveHtml='<html><body><main data-od-id="hero">Hero</main></body></html>'
6013+
viewerOnly
6014+
onSavePreviewComment={vi.fn()}
6015+
/>
6016+
</CollabProvider>,
6017+
);
6018+
6019+
clickAgentTool('board-mode-toggle');
6020+
const frame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
6021+
window.dispatchEvent(new MessageEvent('message', {
6022+
source: frame.contentWindow,
6023+
data: {
6024+
type: 'od:comment-target',
6025+
elementId: 'hero',
6026+
selector: '[data-od-id="hero"]',
6027+
label: 'Hero',
6028+
text: 'Hero',
6029+
position: { x: 8, y: 12, width: 120, height: 48 },
6030+
hoverPoint: { x: 12, y: 16 },
6031+
htmlHint: '<main data-od-id="hero">Hero</main>',
6032+
},
6033+
}));
6034+
6035+
const input = await screen.findByTestId('comment-popover-input');
6036+
fireEvent.change(input, { target: { value: 'Please tighten this heading.' } });
6037+
6038+
expect(input).not.toHaveAttribute('readonly');
6039+
expect(screen.getByTestId('comment-popover-save')).toHaveTextContent('Comment');
6040+
expect(screen.queryByTestId('comment-add-send')).toBeNull();
6041+
});
6042+
59876043
it('docks the comment side panel outside the clickable preview canvas', () => {
59886044
vi.spyOn(HTMLElement.prototype, 'getBoundingClientRect')
59896045
.mockImplementation(function getBoundingClientRectMock(this: HTMLElement) {

0 commit comments

Comments
 (0)