diff --git a/src/annotator/guest.ts b/src/annotator/guest.ts
index 7b6eff876c5..f11fde3590a 100644
--- a/src/annotator/guest.ts
+++ b/src/annotator/guest.ts
@@ -643,6 +643,13 @@ export class Guest
this._sidebarRPC.on('deleteAnnotation', (tag: string) => this.detach(tag));
+ // Expose document info to the sidebar on demand, so that annotation
+ // creation can be triggered from there (e.g. via the experimental new note
+ // button)
+ this._sidebarRPC.on('getDocumentInfo', async callback =>
+ callback(await this.getDocumentInfo()),
+ );
+
this._sidebarRPC.on(
'loadAnnotations',
async (annotations: AnnotationData[]) => {
diff --git a/src/annotator/test/guest-test.js b/src/annotator/test/guest-test.js
index 22502fdce73..09f09b419a4 100644
--- a/src/annotator/test/guest-test.js
+++ b/src/annotator/test/guest-test.js
@@ -1,4 +1,5 @@
-import { delay } from '@hypothesis/frontend-testing';
+import { delay, waitFor } from '@hypothesis/frontend-testing';
+import sinon from 'sinon';
import { EventEmitter } from '../../shared/event-emitter';
import { DrawError } from '../draw-tool';
@@ -736,6 +737,30 @@ describe('Guest', () => {
});
});
+ describe('on "getDocumentInfo" event', () => {
+ it('gets guest document info', async () => {
+ const callback = sinon.stub();
+
+ createGuest();
+ emitSidebarEvent('getDocumentInfo', callback);
+
+ await waitFor(() => callback.called);
+
+ assert.calledWith(
+ callback,
+ sinon.match({
+ uri: 'https://example.com/test.pdf',
+ metadata: {
+ title: 'Test title',
+ documentFingerprint: 'test-fingerprint',
+ },
+ }),
+ );
+ assert.called(fakeIntegration.uri);
+ assert.called(fakeIntegration.getMetadata);
+ });
+ });
+
describe('on "featureFlagsUpdated" event', () => {
it('updates active feature flags', () => {
const flagsUpdated = sinon.stub();
diff --git a/src/sidebar/components/SidebarTabs.tsx b/src/sidebar/components/SidebarTabs.tsx
index 2283c466c3d..8423b7eac6a 100644
--- a/src/sidebar/components/SidebarTabs.tsx
+++ b/src/sidebar/components/SidebarTabs.tsx
@@ -8,6 +8,7 @@ import {
} from '@hypothesis/frontend-shared';
import classnames from 'classnames';
import type { ComponentChildren } from 'preact';
+import { useCallback } from 'preact/hooks';
import { pluralize } from '../../shared/pluralize';
import type { SidebarSettings } from '../../types/config';
@@ -15,6 +16,7 @@ import type { TabName } from '../../types/sidebar';
import { applyTheme } from '../helpers/theme';
import { withServices } from '../service-context';
import type { AnnotationsService } from '../services/annotations';
+import type { FrameSyncService } from '../services/frame-sync';
import { useSidebarStore } from '../store';
import ThreadList from './ThreadList';
import { useRootThread } from './hooks/use-root-thread';
@@ -99,6 +101,7 @@ export type SidebarTabsProps = {
// injected
settings: SidebarSettings;
annotationsService: AnnotationsService;
+ frameSync: FrameSyncService;
};
/**
@@ -108,6 +111,7 @@ function SidebarTabs({
annotationsService,
isLoading,
settings,
+ frameSync,
}: SidebarTabsProps) {
const { rootThread, tabCounts } = useRootThread();
const store = useSidebarStore();
@@ -143,6 +147,11 @@ function SidebarTabs({
}
const tabCountsSummary = tabCountsSummaryPieces.join(', ');
+ const createPageNoteWithDocumentMeta = useCallback(async () => {
+ const { metadata } = await frameSync.getDocumentInfo();
+ annotationsService.createPageNote(metadata);
+ }, [annotationsService, frameSync]);
+
return (
<>
@@ -201,7 +210,7 @@ function SidebarTabs({