@alreadyso/annotate 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -9
- package/dist/AlreadyAnnotate.d.ts +1 -2
- package/dist/AlreadyAnnotate.js +23 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,9 +13,7 @@ export function App() {
|
|
|
13
13
|
<YourApp />
|
|
14
14
|
<AlreadyAnnotate
|
|
15
15
|
teamId="YOUR_TEAM_ID"
|
|
16
|
-
|
|
17
|
-
webAppUrl="http://localhost:3000"
|
|
18
|
-
authToken="SUPABASE_ACCESS_TOKEN"
|
|
16
|
+
useCookies
|
|
19
17
|
openOnSave
|
|
20
18
|
/>
|
|
21
19
|
</>
|
|
@@ -25,7 +23,7 @@ export function App() {
|
|
|
25
23
|
|
|
26
24
|
## Overlay Helper
|
|
27
25
|
|
|
28
|
-
If you want the component to fetch an auth token on mount, use `AlreadyAnnotateOverlay
|
|
26
|
+
If you want the component to fetch an auth token on mount, use `AlreadyAnnotateOverlay`. For same-origin apps you can also rely on cookies by passing `useCookies`.
|
|
29
27
|
|
|
30
28
|
```tsx
|
|
31
29
|
import { AlreadyAnnotateOverlay } from "@alreadyso/annotate";
|
|
@@ -41,7 +39,6 @@ export function App() {
|
|
|
41
39
|
<YourApp />
|
|
42
40
|
<AlreadyAnnotateOverlay
|
|
43
41
|
teamId="YOUR_TEAM_ID"
|
|
44
|
-
teamSlug="your-team-slug"
|
|
45
42
|
getAuthToken={getAuthToken}
|
|
46
43
|
/>
|
|
47
44
|
</>
|
|
@@ -52,13 +49,12 @@ export function App() {
|
|
|
52
49
|
## Props
|
|
53
50
|
|
|
54
51
|
- `teamId` (required): Team UUID for the session.
|
|
55
|
-
- `
|
|
56
|
-
- `
|
|
57
|
-
- `authToken` (optional): Supabase access token for user auth.
|
|
52
|
+
- `webAppUrl` (optional): Base URL for the Already web app. Defaults to the current origin in the browser. Use this when embedding the annotator on a different domain.
|
|
53
|
+
- `authToken` (optional): Bearer token for user auth.
|
|
58
54
|
- `apiKey` (optional): Agent API key (alternative to `authToken`).
|
|
59
55
|
- `useCookies` (optional): Send cookies with requests (for same-origin use).
|
|
60
56
|
- `defaultStatus` (optional): Session status to set after saving. Defaults to `todo`.
|
|
61
|
-
- `openOnSave` (optional): Open the session after save
|
|
57
|
+
- `openOnSave` (optional): Open the session after save (redirects via `/t/by-id`). Defaults to `true`.
|
|
62
58
|
- `blockInteractions` (optional): Prevent underlying clicks while annotating. Defaults to `true`.
|
|
63
59
|
- `accentColor` (optional): Accent color for the overlay UI.
|
|
64
60
|
- `sessionTitle` (optional): Override the session title.
|
|
@@ -18,7 +18,6 @@ export type Annotation = {
|
|
|
18
18
|
};
|
|
19
19
|
export type AlreadyAnnotateProps = {
|
|
20
20
|
teamId: string;
|
|
21
|
-
teamSlug?: string;
|
|
22
21
|
webAppUrl?: string;
|
|
23
22
|
authToken?: string;
|
|
24
23
|
apiKey?: string;
|
|
@@ -30,4 +29,4 @@ export type AlreadyAnnotateProps = {
|
|
|
30
29
|
sessionTitle?: string;
|
|
31
30
|
onSaveComplete?: (sessionId: string) => void;
|
|
32
31
|
};
|
|
33
|
-
export declare function AlreadyAnnotate({ teamId,
|
|
32
|
+
export declare function AlreadyAnnotate({ teamId, webAppUrl, authToken, apiKey, useCookies, defaultStatus, openOnSave, blockInteractions, accentColor, sessionTitle, onSaveComplete, }: AlreadyAnnotateProps): React.ReactPortal | null;
|
package/dist/AlreadyAnnotate.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
|
-
const DEFAULT_WEB_URL = "http://localhost:3000";
|
|
5
4
|
const DEFAULT_ACCENT = "#2563eb";
|
|
6
5
|
function nowIso() {
|
|
7
6
|
return new Date().toISOString();
|
|
@@ -136,7 +135,7 @@ function isIgnoredTarget(target) {
|
|
|
136
135
|
return true;
|
|
137
136
|
return false;
|
|
138
137
|
}
|
|
139
|
-
export function AlreadyAnnotate({ teamId,
|
|
138
|
+
export function AlreadyAnnotate({ teamId, webAppUrl, authToken, apiKey, useCookies = false, defaultStatus = "todo", openOnSave = true, blockInteractions = true, accentColor = DEFAULT_ACCENT, sessionTitle, onSaveComplete, }) {
|
|
140
139
|
const [portalRoot, setPortalRoot] = useState(null);
|
|
141
140
|
const [isActive, setIsActive] = useState(false);
|
|
142
141
|
const [hoverRect, setHoverRect] = useState(null);
|
|
@@ -284,6 +283,18 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
284
283
|
const handleDeleteAnnotation = useCallback((id) => {
|
|
285
284
|
setAnnotations((prev) => prev.filter((item) => item.id !== id));
|
|
286
285
|
}, []);
|
|
286
|
+
const resolvedWebAppUrl = useMemo(() => {
|
|
287
|
+
if (webAppUrl)
|
|
288
|
+
return webAppUrl.replace(/\/$/, "");
|
|
289
|
+
if (typeof window !== "undefined")
|
|
290
|
+
return window.location.origin;
|
|
291
|
+
return "";
|
|
292
|
+
}, [webAppUrl]);
|
|
293
|
+
const buildUrl = useCallback((path) => {
|
|
294
|
+
if (!resolvedWebAppUrl)
|
|
295
|
+
return path;
|
|
296
|
+
return `${resolvedWebAppUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
297
|
+
}, [resolvedWebAppUrl]);
|
|
287
298
|
const buildHeaders = useCallback(() => {
|
|
288
299
|
const headers = {
|
|
289
300
|
"Content-Type": "application/json",
|
|
@@ -298,7 +309,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
298
309
|
return headers;
|
|
299
310
|
}, [apiKey, authToken, teamId]);
|
|
300
311
|
const createSession = useCallback(async () => {
|
|
301
|
-
const response = await fetch(
|
|
312
|
+
const response = await fetch(buildUrl("/api/sessions/start"), {
|
|
302
313
|
method: "POST",
|
|
303
314
|
headers: buildHeaders(),
|
|
304
315
|
body: JSON.stringify({ title: pageTitle, source: "web" }),
|
|
@@ -312,11 +323,11 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
312
323
|
throw new Error("Session creation succeeded but no session_id returned");
|
|
313
324
|
}
|
|
314
325
|
return payload.session_id;
|
|
315
|
-
}, [buildHeaders, pageTitle, useCookies
|
|
326
|
+
}, [buildHeaders, buildUrl, pageTitle, useCookies]);
|
|
316
327
|
const updateSessionData = useCallback(async (sessionId) => {
|
|
317
328
|
const notes = buildNotesDocument(annotations, pageTitle, pageUrl);
|
|
318
329
|
const timeline = buildTimeline(annotations);
|
|
319
|
-
const response = await fetch(
|
|
330
|
+
const response = await fetch(buildUrl(`/api/sessions/${sessionId}/data`), {
|
|
320
331
|
method: "PATCH",
|
|
321
332
|
headers: buildHeaders(),
|
|
322
333
|
body: JSON.stringify({
|
|
@@ -331,12 +342,12 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
331
342
|
if (!response.ok) {
|
|
332
343
|
throw new Error(payload.error || payload.message || `Failed to save session data (${response.status})`);
|
|
333
344
|
}
|
|
334
|
-
}, [annotations, buildHeaders, pageTitle, pageUrl, useCookies
|
|
345
|
+
}, [annotations, buildHeaders, buildUrl, pageTitle, pageUrl, useCookies]);
|
|
335
346
|
const updateSessionStatus = useCallback(async (sessionId) => {
|
|
336
347
|
if (!defaultStatus || defaultStatus === "in_session" || defaultStatus === "uploading") {
|
|
337
348
|
return;
|
|
338
349
|
}
|
|
339
|
-
const response = await fetch(
|
|
350
|
+
const response = await fetch(buildUrl(`/api/sessions/${sessionId}`), {
|
|
340
351
|
method: "PATCH",
|
|
341
352
|
headers: buildHeaders(),
|
|
342
353
|
body: JSON.stringify({ status: defaultStatus }),
|
|
@@ -346,7 +357,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
346
357
|
if (!response.ok) {
|
|
347
358
|
throw new Error(payload.error || payload.message || `Failed to update session status (${response.status})`);
|
|
348
359
|
}
|
|
349
|
-
}, [buildHeaders, defaultStatus, useCookies
|
|
360
|
+
}, [buildHeaders, buildUrl, defaultStatus, useCookies]);
|
|
350
361
|
const handleSaveToAlready = useCallback(async () => {
|
|
351
362
|
if (annotations.length === 0) {
|
|
352
363
|
setError("Add at least one annotation before saving.");
|
|
@@ -360,8 +371,9 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
360
371
|
await updateSessionStatus(sessionId);
|
|
361
372
|
setLastSessionId(sessionId);
|
|
362
373
|
onSaveComplete?.(sessionId);
|
|
363
|
-
if (openOnSave
|
|
364
|
-
const
|
|
374
|
+
if (openOnSave) {
|
|
375
|
+
const target = `/t/by-id?teamId=${encodeURIComponent(teamId)}&sessionId=${encodeURIComponent(sessionId)}`;
|
|
376
|
+
const url = buildUrl(target);
|
|
365
377
|
window.open(url, "_blank", "noopener,noreferrer");
|
|
366
378
|
}
|
|
367
379
|
}
|
|
@@ -372,7 +384,7 @@ export function AlreadyAnnotate({ teamId, teamSlug, webAppUrl = DEFAULT_WEB_URL,
|
|
|
372
384
|
finally {
|
|
373
385
|
setSaving(false);
|
|
374
386
|
}
|
|
375
|
-
}, [annotations.length, createSession, onSaveComplete, openOnSave,
|
|
387
|
+
}, [annotations.length, buildUrl, createSession, onSaveComplete, openOnSave, updateSessionData, updateSessionStatus]);
|
|
376
388
|
const panel = (_jsxs("div", { "data-already-annotate-ui": true, style: {
|
|
377
389
|
position: "fixed",
|
|
378
390
|
right: 16,
|