@agent-native/core 0.68.1 → 0.68.3
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 +4 -4
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +16 -0
- package/corpus/core/docs/content/authentication.md +16 -2
- package/corpus/core/docs/content/template-analytics.md +14 -9
- package/corpus/core/docs/content/template-clips.md +35 -2
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +2 -4
- package/corpus/core/src/client/CommandMenu.tsx +98 -3
- package/corpus/core/src/client/ConnectBuilderCard.tsx +11 -2
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/extensions/content-patch.ts +12 -2
- package/corpus/core/src/oauth-tokens/google-refresh.ts +32 -17
- package/corpus/core/src/provider-api/index.ts +37 -17
- package/corpus/core/src/server/auth.ts +6 -8
- package/corpus/core/src/server/better-auth-instance.ts +19 -4
- package/corpus/core/src/server/core-routes-plugin.ts +157 -5
- package/corpus/core/src/server/google-oauth-credentials.ts +51 -0
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/server/onboarding-html.ts +2 -1
- package/corpus/core/src/server/social-og-image.ts +6 -1
- package/corpus/core/src/vite/client.ts +83 -1
- package/corpus/templates/analytics/app/routes/$.tsx +9 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +33 -1
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +11 -3
- package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +25 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +12 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +7 -2
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +37 -78
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +33 -1
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +46 -3
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +203 -2
- package/corpus/templates/calendar/app/lib/event-colors.ts +1 -4
- package/corpus/templates/calendar/app/lib/rsvp-status.tsx +6 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +9 -4
- package/corpus/templates/calendar/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/calendar/app/pages/Settings.tsx +25 -1
- package/corpus/templates/calendar/app/routes/_app.$.tsx +9 -0
- package/corpus/templates/calendar/server/handlers/google-auth.ts +152 -12
- package/corpus/templates/calendar/server/lib/google-calendar.ts +63 -14
- package/corpus/templates/calendar/server/plugins/auth.ts +4 -20
- package/corpus/templates/calendar/shared/api.ts +4 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +17 -0
- package/corpus/templates/clips/actions/sync-calendars.ts +6 -7
- package/corpus/templates/clips/app/components/capture-install-options.tsx +157 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +9 -8
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +4 -6
- package/corpus/templates/clips/app/lib/capture-install-options.ts +14 -0
- package/corpus/templates/clips/app/root.tsx +54 -2
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +9 -13
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +5 -7
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +5 -7
- package/corpus/templates/clips/app/routes/download.tsx +49 -0
- package/corpus/templates/clips/app/routes/record.tsx +4 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +5 -6
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +29 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +6 -7
- package/corpus/templates/clips/server/lib/google-calendar-client.ts +61 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +19 -12
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +6 -6
- package/corpus/templates/content/vite.config.ts +37 -1
- package/corpus/templates/design/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/design/app/routes/$.tsx +9 -0
- package/corpus/templates/mail/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/mail/app/routes/$.tsx +9 -0
- package/corpus/templates/plan/app/global.css +2 -2
- package/corpus/templates/slides/app/pages/NotFound.tsx +1 -1
- package/corpus/templates/slides/app/routes/$.tsx +9 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +81 -25
- package/corpus/templates/videos/app/pages/NotFound.tsx +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +15 -2
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +46 -3
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +11 -2
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/extensions/content-patch.d.ts.map +1 -1
- package/dist/extensions/content-patch.js +10 -2
- package/dist/extensions/content-patch.js.map +1 -1
- package/dist/oauth-tokens/google-refresh.d.ts.map +1 -1
- package/dist/oauth-tokens/google-refresh.js +29 -17
- package/dist/oauth-tokens/google-refresh.js.map +1 -1
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +28 -16
- package/dist/provider-api/index.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -6
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +18 -4
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +5 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +107 -5
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/google-oauth-credentials.d.ts +15 -0
- package/dist/server/google-oauth-credentials.d.ts.map +1 -0
- package/dist/server/google-oauth-credentials.js +34 -0
- package/dist/server/google-oauth-credentials.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +2 -1
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/social-og-image.d.ts.map +1 -1
- package/dist/server/social-og-image.js +5 -1
- package/dist/server/social-og-image.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +83 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/authentication.md +16 -2
- package/docs/content/template-analytics.md +14 -9
- package/docs/content/template-clips.md +35 -2
- package/package.json +1 -1
|
@@ -1320,6 +1320,87 @@ function ssrStubPlugin(packages: string[]): Plugin | null {
|
|
|
1320
1320
|
if (!packages.length) return null;
|
|
1321
1321
|
const stubbed = new Set(packages);
|
|
1322
1322
|
const STUB_ID = "\0agent-native-ssr-stub";
|
|
1323
|
+
const namedExports = [
|
|
1324
|
+
"ActionBarPrimitive",
|
|
1325
|
+
"AllSelection",
|
|
1326
|
+
"Array",
|
|
1327
|
+
"AssistantRuntimeProvider",
|
|
1328
|
+
"Awareness",
|
|
1329
|
+
"BranchPickerPrimitive",
|
|
1330
|
+
"BubbleMenu",
|
|
1331
|
+
"CodeBlockLowlight",
|
|
1332
|
+
"Collaboration",
|
|
1333
|
+
"CollaborationCaret",
|
|
1334
|
+
"ComposerPrimitive",
|
|
1335
|
+
"CompositeAttachmentAdapter",
|
|
1336
|
+
"DOMParser",
|
|
1337
|
+
"Decoration",
|
|
1338
|
+
"DecorationSet",
|
|
1339
|
+
"Editor",
|
|
1340
|
+
"EditorContent",
|
|
1341
|
+
"Extension",
|
|
1342
|
+
"FitAddon",
|
|
1343
|
+
"Fragment",
|
|
1344
|
+
"Image",
|
|
1345
|
+
"Link",
|
|
1346
|
+
"Map",
|
|
1347
|
+
"Markdown",
|
|
1348
|
+
"Mark",
|
|
1349
|
+
"MessagePrimitive",
|
|
1350
|
+
"Node",
|
|
1351
|
+
"NodeSelection",
|
|
1352
|
+
"NodeViewContent",
|
|
1353
|
+
"NodeViewWrapper",
|
|
1354
|
+
"Placeholder",
|
|
1355
|
+
"Plugin",
|
|
1356
|
+
"PluginKey",
|
|
1357
|
+
"ReactNodeViewRenderer",
|
|
1358
|
+
"Selection",
|
|
1359
|
+
"SimpleImageAttachmentAdapter",
|
|
1360
|
+
"SimpleTextAttachmentAdapter",
|
|
1361
|
+
"StarterKit",
|
|
1362
|
+
"Table",
|
|
1363
|
+
"TableCell",
|
|
1364
|
+
"TableHeader",
|
|
1365
|
+
"TableRow",
|
|
1366
|
+
"TaskItem",
|
|
1367
|
+
"TaskList",
|
|
1368
|
+
"Terminal",
|
|
1369
|
+
"TextSelection",
|
|
1370
|
+
"ThreadPrimitive",
|
|
1371
|
+
"WebLinksAddon",
|
|
1372
|
+
"captureException",
|
|
1373
|
+
"common",
|
|
1374
|
+
"createLowlight",
|
|
1375
|
+
"defaultUrlTransform",
|
|
1376
|
+
"extensions",
|
|
1377
|
+
"findTable",
|
|
1378
|
+
"format",
|
|
1379
|
+
"Doc",
|
|
1380
|
+
"getHTMLFromFragment",
|
|
1381
|
+
"getIsolationScope",
|
|
1382
|
+
"init",
|
|
1383
|
+
"isChangeOrigin",
|
|
1384
|
+
"mergeAttributes",
|
|
1385
|
+
"renderToString",
|
|
1386
|
+
"applyUpdate",
|
|
1387
|
+
"encodeStateVector",
|
|
1388
|
+
"encodeStateAsUpdate",
|
|
1389
|
+
"mergeUpdates",
|
|
1390
|
+
"useAui",
|
|
1391
|
+
"useComposer",
|
|
1392
|
+
"useComposerRuntime",
|
|
1393
|
+
"useCurrentEditor",
|
|
1394
|
+
"useEditor",
|
|
1395
|
+
"useLocalRuntime",
|
|
1396
|
+
"useMessagePartText",
|
|
1397
|
+
"useMessageRuntime",
|
|
1398
|
+
"useThread",
|
|
1399
|
+
"useThreadRuntime",
|
|
1400
|
+
"withScope",
|
|
1401
|
+
"XmlFragment",
|
|
1402
|
+
"XmlText",
|
|
1403
|
+
];
|
|
1323
1404
|
return {
|
|
1324
1405
|
name: "agent-native-ssr-stub-heavy-libs",
|
|
1325
1406
|
enforce: "pre",
|
|
@@ -1345,7 +1426,8 @@ function ssrStubPlugin(packages: string[]): Plugin | null {
|
|
|
1345
1426
|
"return new Proxy(() => {}, handler); " +
|
|
1346
1427
|
"} };" +
|
|
1347
1428
|
"const stub = new Proxy(() => {}, handler);" +
|
|
1348
|
-
"export default stub;"
|
|
1429
|
+
"export default stub;" +
|
|
1430
|
+
namedExports.map((name) => `export const ${name} = stub;`).join("")
|
|
1349
1431
|
);
|
|
1350
1432
|
},
|
|
1351
1433
|
};
|
|
@@ -262,7 +262,17 @@ export function DayView({
|
|
|
262
262
|
onDraftDiscard={onDraftDiscard}
|
|
263
263
|
>
|
|
264
264
|
<button
|
|
265
|
-
className=
|
|
265
|
+
className={cn(
|
|
266
|
+
"relative flex w-full items-center gap-1.5 rounded-md px-3 py-1.5 text-left text-sm font-medium text-foreground transition-all hover:brightness-110",
|
|
267
|
+
event.ownerColor && "pr-5",
|
|
268
|
+
)}
|
|
269
|
+
aria-label={
|
|
270
|
+
event.ownerName || event.overlayEmail
|
|
271
|
+
? `${event.title}, ${
|
|
272
|
+
event.ownerName || event.overlayEmail
|
|
273
|
+
}'s calendar`
|
|
274
|
+
: event.title
|
|
275
|
+
}
|
|
266
276
|
style={
|
|
267
277
|
color
|
|
268
278
|
? {
|
|
@@ -283,6 +293,13 @@ export function DayView({
|
|
|
283
293
|
)}
|
|
284
294
|
<EventStatusIcon event={event} className="shrink-0" />
|
|
285
295
|
<span className="truncate">{event.title}</span>
|
|
296
|
+
{event.ownerColor && (
|
|
297
|
+
<span
|
|
298
|
+
aria-hidden="true"
|
|
299
|
+
className="absolute right-2 top-1/2 size-1.5 -translate-y-1/2 rounded-full ring-1 ring-background/70"
|
|
300
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
301
|
+
/>
|
|
302
|
+
)}
|
|
286
303
|
</button>
|
|
287
304
|
</EventDetailPopover>
|
|
288
305
|
);
|
|
@@ -458,7 +475,15 @@ export function DayView({
|
|
|
458
475
|
isBeingDragged && isDragging && "ring-2 ring-primary/40",
|
|
459
476
|
canDrag && isStart && "cursor-grab",
|
|
460
477
|
isBeingDragged && isDragging && "cursor-grabbing",
|
|
478
|
+
event.ownerColor && "pr-4",
|
|
461
479
|
)}
|
|
480
|
+
aria-label={
|
|
481
|
+
event.ownerName || event.overlayEmail
|
|
482
|
+
? `${event.title}, ${
|
|
483
|
+
event.ownerName || event.overlayEmail
|
|
484
|
+
}'s calendar`
|
|
485
|
+
: event.title
|
|
486
|
+
}
|
|
462
487
|
style={{
|
|
463
488
|
...posStyle,
|
|
464
489
|
left: `${li.left}px`,
|
|
@@ -483,6 +508,13 @@ export function DayView({
|
|
|
483
508
|
opacity: isBeingDragged && isDragging ? 0.9 : undefined,
|
|
484
509
|
}}
|
|
485
510
|
>
|
|
511
|
+
{event.ownerColor && (
|
|
512
|
+
<span
|
|
513
|
+
aria-hidden="true"
|
|
514
|
+
className="absolute right-1.5 top-1.5 size-1.5 rounded-full ring-1 ring-background/70"
|
|
515
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
516
|
+
/>
|
|
517
|
+
)}
|
|
486
518
|
{durationMin <= 30 ? (
|
|
487
519
|
<div className="flex items-baseline gap-1.5 truncate">
|
|
488
520
|
{allOthersOut && (
|
|
@@ -16,6 +16,7 @@ import { useAttendeePhotos } from "@/hooks/use-attendee-photos";
|
|
|
16
16
|
import { useRsvpEvent } from "@/hooks/use-events";
|
|
17
17
|
import { cn } from "@/lib/utils";
|
|
18
18
|
import {
|
|
19
|
+
canInlineRsvp,
|
|
19
20
|
getRsvpStatusLabel,
|
|
20
21
|
RsvpStatusIcon,
|
|
21
22
|
type RsvpStatus,
|
|
@@ -406,6 +407,7 @@ export function EventAttendeesSection({
|
|
|
406
407
|
| "id"
|
|
407
408
|
| "accountEmail"
|
|
408
409
|
| "attendees"
|
|
410
|
+
| "overlayEmail"
|
|
409
411
|
| "responseStatus"
|
|
410
412
|
| "source"
|
|
411
413
|
| "recurringEventId"
|
|
@@ -423,8 +425,14 @@ export function EventAttendeesSection({
|
|
|
423
425
|
const { data: photos } = useAttendeePhotos(emails);
|
|
424
426
|
|
|
425
427
|
const sorted = useMemo(() => sortAttendees(attendees), [attendees]);
|
|
426
|
-
const
|
|
427
|
-
const
|
|
428
|
+
const canRsvpInline = canInlineRsvp(event);
|
|
429
|
+
const selfAttendee = canRsvpInline
|
|
430
|
+
? sorted.find((attendee) => attendee.self)
|
|
431
|
+
: undefined;
|
|
432
|
+
const others =
|
|
433
|
+
canRsvpInline && selfAttendee
|
|
434
|
+
? sorted.filter((attendee) => !attendee.self)
|
|
435
|
+
: sorted;
|
|
428
436
|
|
|
429
437
|
useEffect(() => {
|
|
430
438
|
setSelfStatus(event.responseStatus || "needsAction");
|
|
@@ -505,7 +513,7 @@ export function EventAttendeesSection({
|
|
|
505
513
|
attendee={selfAttendee}
|
|
506
514
|
event={event}
|
|
507
515
|
photoUrl={photos?.[selfAttendee.email.toLowerCase()]}
|
|
508
|
-
inlineRsvp={
|
|
516
|
+
inlineRsvp={canRsvpInline}
|
|
509
517
|
currentStatus={selfStatus}
|
|
510
518
|
currentNote={selfNote}
|
|
511
519
|
onResponseChange={handleSelfResponseChange}
|
|
@@ -30,6 +30,7 @@ export function EventCard({
|
|
|
30
30
|
colorPreferences,
|
|
31
31
|
}: EventCardProps) {
|
|
32
32
|
const accentColor = getEventDisplayColor(event, colorPreferences);
|
|
33
|
+
const ownerLabel = event.ownerName || event.overlayEmail;
|
|
33
34
|
|
|
34
35
|
const handleDragStart = (e: React.DragEvent) => {
|
|
35
36
|
e.dataTransfer.setData("text/plain", event.id);
|
|
@@ -47,10 +48,14 @@ export function EventCard({
|
|
|
47
48
|
onDragStart={canDrag ? handleDragStart : undefined}
|
|
48
49
|
onDragEnd={canDrag ? onDragEnd : undefined}
|
|
49
50
|
className={cn(
|
|
50
|
-
"flex w-full items-center gap-1.5 rounded px-1.5 py-0.5 text-left text-xs text-foreground transition-all hover:brightness-110",
|
|
51
|
+
"relative flex w-full items-center gap-1.5 rounded px-1.5 py-0.5 text-left text-xs text-foreground transition-all hover:brightness-110",
|
|
51
52
|
canDrag && "cursor-grab active:cursor-grabbing",
|
|
52
53
|
dimmed && "opacity-40",
|
|
54
|
+
event.ownerColor && "pr-3.5",
|
|
53
55
|
)}
|
|
56
|
+
aria-label={
|
|
57
|
+
ownerLabel ? `${event.title}, ${ownerLabel}'s calendar` : event.title
|
|
58
|
+
}
|
|
54
59
|
style={{
|
|
55
60
|
backgroundColor: `${accentColor}25`,
|
|
56
61
|
}}
|
|
@@ -68,6 +73,13 @@ export function EventCard({
|
|
|
68
73
|
)}
|
|
69
74
|
<EventStatusIcon event={event} />
|
|
70
75
|
<span className="truncate font-medium">{event.title}</span>
|
|
76
|
+
{event.ownerColor && (
|
|
77
|
+
<span
|
|
78
|
+
aria-hidden="true"
|
|
79
|
+
className="absolute right-1 top-1/2 size-1.5 -translate-y-1/2 rounded-full ring-1 ring-background/70"
|
|
80
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
81
|
+
/>
|
|
82
|
+
)}
|
|
71
83
|
</button>
|
|
72
84
|
);
|
|
73
85
|
}
|
|
@@ -79,10 +91,14 @@ export function EventCard({
|
|
|
79
91
|
onDragStart={canDrag ? handleDragStart : undefined}
|
|
80
92
|
onDragEnd={canDrag ? onDragEnd : undefined}
|
|
81
93
|
className={cn(
|
|
82
|
-
"flex w-full flex-col gap-0.5 rounded-md px-2 py-1.5 text-left text-xs text-foreground transition-all hover:brightness-110",
|
|
94
|
+
"relative flex w-full flex-col gap-0.5 rounded-md px-2 py-1.5 text-left text-xs text-foreground transition-all hover:brightness-110",
|
|
83
95
|
canDrag && "cursor-grab active:cursor-grabbing",
|
|
84
96
|
dimmed && "opacity-40",
|
|
97
|
+
event.ownerColor && "pr-4",
|
|
85
98
|
)}
|
|
99
|
+
aria-label={
|
|
100
|
+
ownerLabel ? `${event.title}, ${ownerLabel}'s calendar` : event.title
|
|
101
|
+
}
|
|
86
102
|
style={{
|
|
87
103
|
backgroundColor: `${accentColor}25`,
|
|
88
104
|
borderLeft: `2px solid ${accentColor}`,
|
|
@@ -106,6 +122,13 @@ export function EventCard({
|
|
|
106
122
|
})}
|
|
107
123
|
</span>
|
|
108
124
|
)}
|
|
125
|
+
{event.ownerColor && (
|
|
126
|
+
<span
|
|
127
|
+
aria-hidden="true"
|
|
128
|
+
className="absolute right-1.5 top-1.5 size-1.5 rounded-full ring-1 ring-background/70"
|
|
129
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
109
132
|
</button>
|
|
110
133
|
);
|
|
111
134
|
}
|
|
@@ -101,6 +101,7 @@ export function EventDetailPanel({
|
|
|
101
101
|
const isOverlay = !!event?.overlayEmail;
|
|
102
102
|
const lastSavedDescriptionRef = useRef(event?.description || "");
|
|
103
103
|
const meetingLink = event ? extractMeetingLink(event) : null;
|
|
104
|
+
const ownerLabel = event?.ownerName || event?.overlayEmail;
|
|
104
105
|
|
|
105
106
|
// Reset editing state when event changes
|
|
106
107
|
useEffect(() => {
|
|
@@ -310,6 +311,17 @@ export function EventDetailPanel({
|
|
|
310
311
|
</div>
|
|
311
312
|
)}
|
|
312
313
|
|
|
314
|
+
{event.overlayEmail && ownerLabel && (
|
|
315
|
+
<div className="flex items-center gap-2.5 text-sm text-muted-foreground">
|
|
316
|
+
<span
|
|
317
|
+
aria-hidden="true"
|
|
318
|
+
className="ml-0.5 size-2 shrink-0 rounded-full ring-1 ring-border"
|
|
319
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
320
|
+
/>
|
|
321
|
+
<span>Viewing {ownerLabel}'s calendar</span>
|
|
322
|
+
</div>
|
|
323
|
+
)}
|
|
324
|
+
|
|
313
325
|
{meetingLink ? (
|
|
314
326
|
<a
|
|
315
327
|
href={safeUrl(meetingLink)}
|
|
@@ -395,6 +395,7 @@ export function EventDetailPopover({
|
|
|
395
395
|
"meet" | "zoom" | null
|
|
396
396
|
>(null);
|
|
397
397
|
const isOverlay = !!event.overlayEmail;
|
|
398
|
+
const ownerLabel = event.ownerName || event.overlayEmail;
|
|
398
399
|
|
|
399
400
|
const updateEvent = useUpdateEvent();
|
|
400
401
|
const masterEventId =
|
|
@@ -2086,9 +2087,13 @@ Write a short, useful meeting description. If I ask you to apply it, update this
|
|
|
2086
2087
|
<>
|
|
2087
2088
|
<div className="mx-4 my-2 border-t border-border/50" />
|
|
2088
2089
|
<div className="flex items-center gap-3 px-4 py-1.5">
|
|
2089
|
-
<
|
|
2090
|
+
<span
|
|
2091
|
+
aria-hidden="true"
|
|
2092
|
+
className="ml-1 size-2 shrink-0 rounded-full ring-1 ring-border"
|
|
2093
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
2094
|
+
/>
|
|
2090
2095
|
<span className="text-sm text-muted-foreground">
|
|
2091
|
-
{
|
|
2096
|
+
Viewing {ownerLabel}'s calendar
|
|
2092
2097
|
</span>
|
|
2093
2098
|
</div>
|
|
2094
2099
|
</>
|
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
useGoogleAuthStatus,
|
|
22
22
|
useGoogleAuthUrl,
|
|
23
23
|
useGoogleAddAccountUrl,
|
|
24
|
+
useGoogleDesktopAuth,
|
|
24
25
|
useDisconnectGoogle,
|
|
26
|
+
type DesktopAuthIssue,
|
|
25
27
|
} from "@/hooks/use-google-auth";
|
|
26
28
|
|
|
27
29
|
interface EnvKeyStatus {
|
|
@@ -66,15 +68,6 @@ interface GoogleConnectBannerProps {
|
|
|
66
68
|
variant?: "banner" | "hero";
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
interface DesktopAuthIssue {
|
|
70
|
-
error?: string;
|
|
71
|
-
message?: string;
|
|
72
|
-
code?: string;
|
|
73
|
-
accountId?: string;
|
|
74
|
-
existingOwner?: string;
|
|
75
|
-
attemptedOwner?: string;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
71
|
export function GoogleConnectBanner({
|
|
79
72
|
variant = "banner",
|
|
80
73
|
}: GoogleConnectBannerProps) {
|
|
@@ -93,76 +86,23 @@ export function GoogleConnectBanner({
|
|
|
93
86
|
const hasAccounts = accounts.length > 0;
|
|
94
87
|
|
|
95
88
|
const isBuilderFrame = useMemo(() => isInBuilderFrame(), []);
|
|
96
|
-
const useDesktopAuth = useMemo(
|
|
97
|
-
() => /AgentNativeDesktop/i.test(navigator.userAgent) && !isBuilderFrame,
|
|
98
|
-
[isBuilderFrame],
|
|
99
|
-
);
|
|
100
|
-
const desktopPollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
101
89
|
const authPollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
102
90
|
const addAccountPollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
91
|
+
const {
|
|
92
|
+
isDesktopGoogleAuth,
|
|
93
|
+
isGoogleDesktopAuthPending,
|
|
94
|
+
startDesktopGoogleAuth,
|
|
95
|
+
} = useGoogleDesktopAuth({
|
|
96
|
+
onError: setDesktopAuthIssue,
|
|
97
|
+
onSuccess: () => window.location.reload(),
|
|
98
|
+
});
|
|
103
99
|
useEffect(() => {
|
|
104
100
|
return () => {
|
|
105
|
-
if (desktopPollRef.current) clearInterval(desktopPollRef.current);
|
|
106
101
|
if (authPollRef.current) clearInterval(authPollRef.current);
|
|
107
102
|
if (addAccountPollRef.current) clearInterval(addAccountPollRef.current);
|
|
108
103
|
};
|
|
109
104
|
}, []);
|
|
110
105
|
|
|
111
|
-
function signInViaDesktopBrowser(addAccount = false) {
|
|
112
|
-
setDesktopAuthIssue(null);
|
|
113
|
-
const flowId =
|
|
114
|
-
crypto.randomUUID?.() ||
|
|
115
|
-
Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
116
|
-
const origin = window.location.origin;
|
|
117
|
-
const endpoint = addAccount
|
|
118
|
-
? "/_agent-native/google/add-account/auth-url"
|
|
119
|
-
: "/_agent-native/google/auth-url";
|
|
120
|
-
const redirectUri = encodeURIComponent(
|
|
121
|
-
oauthRedirectUri("/_agent-native/google/callback"),
|
|
122
|
-
);
|
|
123
|
-
window.open(
|
|
124
|
-
`${origin}${agentNativePath(endpoint)}?redirect_uri=${redirectUri}&desktop=1&flow_id=${flowId}&redirect=1`,
|
|
125
|
-
"_blank",
|
|
126
|
-
);
|
|
127
|
-
const start = Date.now();
|
|
128
|
-
if (desktopPollRef.current) clearInterval(desktopPollRef.current);
|
|
129
|
-
desktopPollRef.current = setInterval(async () => {
|
|
130
|
-
try {
|
|
131
|
-
const res = await fetch(
|
|
132
|
-
agentNativePath(
|
|
133
|
-
`/_agent-native/auth/desktop-exchange?flow_id=${flowId}`,
|
|
134
|
-
),
|
|
135
|
-
);
|
|
136
|
-
const data = await res.json();
|
|
137
|
-
if (data?.error) {
|
|
138
|
-
clearInterval(desktopPollRef.current!);
|
|
139
|
-
desktopPollRef.current = null;
|
|
140
|
-
setDesktopAuthIssue(data);
|
|
141
|
-
} else if (data?.token) {
|
|
142
|
-
clearInterval(desktopPollRef.current!);
|
|
143
|
-
desktopPollRef.current = null;
|
|
144
|
-
await fetch(
|
|
145
|
-
agentNativePath(
|
|
146
|
-
`/_agent-native/auth/session?_session=${data.token}`,
|
|
147
|
-
),
|
|
148
|
-
{
|
|
149
|
-
credentials: "include",
|
|
150
|
-
},
|
|
151
|
-
);
|
|
152
|
-
window.location.reload();
|
|
153
|
-
} else if (Date.now() - start > 120_000) {
|
|
154
|
-
clearInterval(desktopPollRef.current!);
|
|
155
|
-
desktopPollRef.current = null;
|
|
156
|
-
}
|
|
157
|
-
} catch {
|
|
158
|
-
if (Date.now() - start > 120_000) {
|
|
159
|
-
clearInterval(desktopPollRef.current!);
|
|
160
|
-
desktopPollRef.current = null;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}, 1500);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
106
|
// Wizard state
|
|
167
107
|
const [currentStep, setCurrentStep] = useState(0);
|
|
168
108
|
const [saving, setSaving] = useState(false);
|
|
@@ -293,16 +233,19 @@ export function GoogleConnectBanner({
|
|
|
293
233
|
|
|
294
234
|
function handleConnect() {
|
|
295
235
|
setDesktopAuthIssue(null);
|
|
296
|
-
if (
|
|
297
|
-
|
|
236
|
+
if (isDesktopGoogleAuth) {
|
|
237
|
+
startDesktopGoogleAuth({ previousAccountCount: accounts.length });
|
|
298
238
|
return;
|
|
299
239
|
}
|
|
300
240
|
setWantAuthUrl(true);
|
|
301
241
|
}
|
|
302
242
|
|
|
303
243
|
function handleAddAccount() {
|
|
304
|
-
if (
|
|
305
|
-
|
|
244
|
+
if (isDesktopGoogleAuth) {
|
|
245
|
+
startDesktopGoogleAuth({
|
|
246
|
+
addAccount: true,
|
|
247
|
+
previousAccountCount: accounts.length,
|
|
248
|
+
});
|
|
306
249
|
return;
|
|
307
250
|
}
|
|
308
251
|
setWantAddAccount(true);
|
|
@@ -377,7 +320,11 @@ export function GoogleConnectBanner({
|
|
|
377
320
|
size="sm"
|
|
378
321
|
className="mt-6 gap-2 px-4 h-8 text-[13px] font-medium"
|
|
379
322
|
onClick={handleConnect}
|
|
380
|
-
disabled={
|
|
323
|
+
disabled={
|
|
324
|
+
authUrl.isLoading ||
|
|
325
|
+
authUrl.isFetching ||
|
|
326
|
+
isGoogleDesktopAuthPending
|
|
327
|
+
}
|
|
381
328
|
>
|
|
382
329
|
<GoogleIcon className="h-3.5 w-3.5" />
|
|
383
330
|
{authUrl.isLoading
|
|
@@ -458,7 +405,11 @@ export function GoogleConnectBanner({
|
|
|
458
405
|
))}
|
|
459
406
|
<button
|
|
460
407
|
onClick={handleAddAccount}
|
|
461
|
-
disabled={
|
|
408
|
+
disabled={
|
|
409
|
+
addAccountUrl.isLoading ||
|
|
410
|
+
addAccountUrl.isFetching ||
|
|
411
|
+
isGoogleDesktopAuthPending
|
|
412
|
+
}
|
|
462
413
|
className="text-xs text-foreground/40 hover:text-foreground/60 transition-colors whitespace-nowrap"
|
|
463
414
|
>
|
|
464
415
|
+ Add account
|
|
@@ -515,7 +466,11 @@ export function GoogleConnectBanner({
|
|
|
515
466
|
size="sm"
|
|
516
467
|
className="gap-1.5 text-xs h-7 font-medium bg-white text-black hover:bg-white/90"
|
|
517
468
|
onClick={handleConnect}
|
|
518
|
-
disabled={
|
|
469
|
+
disabled={
|
|
470
|
+
authUrl.isLoading ||
|
|
471
|
+
authUrl.isFetching ||
|
|
472
|
+
isGoogleDesktopAuthPending
|
|
473
|
+
}
|
|
519
474
|
>
|
|
520
475
|
<GoogleIcon className="h-3 w-3" />
|
|
521
476
|
{authUrl.isLoading ? "Connecting..." : "Sign in with Google"}
|
|
@@ -526,7 +481,11 @@ export function GoogleConnectBanner({
|
|
|
526
481
|
variant="outline"
|
|
527
482
|
className="gap-1.5 text-xs h-7 font-medium"
|
|
528
483
|
onClick={handleConnect}
|
|
529
|
-
disabled={
|
|
484
|
+
disabled={
|
|
485
|
+
authUrl.isLoading ||
|
|
486
|
+
authUrl.isFetching ||
|
|
487
|
+
isGoogleDesktopAuthPending
|
|
488
|
+
}
|
|
530
489
|
>
|
|
531
490
|
{authUrl.isLoading ? "..." : "Connect Google"}
|
|
532
491
|
</Button>
|
|
@@ -592,7 +592,17 @@ export function WeekView({
|
|
|
592
592
|
onDraftDiscard={onDraftDiscard}
|
|
593
593
|
>
|
|
594
594
|
<button
|
|
595
|
-
className=
|
|
595
|
+
className={cn(
|
|
596
|
+
"absolute flex items-center gap-1 truncate rounded px-1.5 text-left text-[11px] font-medium text-foreground transition-opacity hover:opacity-80",
|
|
597
|
+
event.ownerColor && "pr-3.5",
|
|
598
|
+
)}
|
|
599
|
+
aria-label={
|
|
600
|
+
event.ownerName || event.overlayEmail
|
|
601
|
+
? `${event.title}, ${
|
|
602
|
+
event.ownerName || event.overlayEmail
|
|
603
|
+
}'s calendar`
|
|
604
|
+
: event.title
|
|
605
|
+
}
|
|
596
606
|
style={{
|
|
597
607
|
top: `${rowIdx * allDayRowHeight + 4}px`,
|
|
598
608
|
left: `${leftPct}%`,
|
|
@@ -613,6 +623,13 @@ export function WeekView({
|
|
|
613
623
|
)}
|
|
614
624
|
<EventStatusIcon event={event} className="shrink-0" />
|
|
615
625
|
<span className="truncate">{event.title}</span>
|
|
626
|
+
{event.ownerColor && (
|
|
627
|
+
<span
|
|
628
|
+
aria-hidden="true"
|
|
629
|
+
className="absolute right-1 top-1/2 size-1.5 -translate-y-1/2 rounded-full ring-1 ring-background/70"
|
|
630
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
631
|
+
/>
|
|
632
|
+
)}
|
|
616
633
|
</button>
|
|
617
634
|
</EventDetailPopover>
|
|
618
635
|
);
|
|
@@ -864,7 +881,15 @@ export function WeekView({
|
|
|
864
881
|
"ring-2 ring-primary/40",
|
|
865
882
|
canDrag && segmentStartsHere && "cursor-grab",
|
|
866
883
|
isBeingDragged && isDragging && "cursor-grabbing",
|
|
884
|
+
event.ownerColor && "pr-4",
|
|
867
885
|
)}
|
|
886
|
+
aria-label={
|
|
887
|
+
event.ownerName || event.overlayEmail
|
|
888
|
+
? `${event.title}, ${
|
|
889
|
+
event.ownerName || event.overlayEmail
|
|
890
|
+
}'s calendar`
|
|
891
|
+
: event.title
|
|
892
|
+
}
|
|
868
893
|
style={{
|
|
869
894
|
...style,
|
|
870
895
|
left: `${li.left}px`,
|
|
@@ -894,6 +919,13 @@ export function WeekView({
|
|
|
894
919
|
isBeingDragged && isDragging ? 0.9 : undefined,
|
|
895
920
|
}}
|
|
896
921
|
>
|
|
922
|
+
{event.ownerColor && (
|
|
923
|
+
<span
|
|
924
|
+
aria-hidden="true"
|
|
925
|
+
className="absolute right-1.5 top-1.5 size-1.5 rounded-full ring-1 ring-background/70"
|
|
926
|
+
style={{ backgroundColor: event.ownerColor }}
|
|
927
|
+
/>
|
|
928
|
+
)}
|
|
897
929
|
{durationMin <= 30 ? (
|
|
898
930
|
<div className="flex items-baseline gap-1 truncate">
|
|
899
931
|
{allOthersOut && (
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
useGoogleAuthStatus,
|
|
47
47
|
useGoogleAuthUrl,
|
|
48
48
|
useGoogleAddAccountUrl,
|
|
49
|
+
useGoogleDesktopAuth,
|
|
49
50
|
} from "@/hooks/use-google-auth";
|
|
50
51
|
import {
|
|
51
52
|
appPath,
|
|
@@ -305,6 +306,13 @@ function MiniCalendar({
|
|
|
305
306
|
function GoogleConnectSidebarButton() {
|
|
306
307
|
const [wantAuthUrl, setWantAuthUrl] = useState(false);
|
|
307
308
|
const authUrl = useGoogleAuthUrl(wantAuthUrl);
|
|
309
|
+
const {
|
|
310
|
+
isDesktopGoogleAuth,
|
|
311
|
+
isGoogleDesktopAuthPending,
|
|
312
|
+
startDesktopGoogleAuth,
|
|
313
|
+
} = useGoogleDesktopAuth({
|
|
314
|
+
onSuccess: () => window.location.reload(),
|
|
315
|
+
});
|
|
308
316
|
|
|
309
317
|
useEffect(() => {
|
|
310
318
|
if (!wantAuthUrl || !authUrl.data?.url) return;
|
|
@@ -312,6 +320,14 @@ function GoogleConnectSidebarButton() {
|
|
|
312
320
|
window.open(authUrl.data.url, "_blank");
|
|
313
321
|
}, [wantAuthUrl, authUrl.data]);
|
|
314
322
|
|
|
323
|
+
function handleConnect() {
|
|
324
|
+
if (isDesktopGoogleAuth) {
|
|
325
|
+
startDesktopGoogleAuth({ previousAccountCount: 0 });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
setWantAuthUrl(true);
|
|
329
|
+
}
|
|
330
|
+
|
|
315
331
|
return (
|
|
316
332
|
<div className="border-t border-border p-3">
|
|
317
333
|
<div className="rounded-lg bg-primary/10 p-3">
|
|
@@ -324,8 +340,12 @@ function GoogleConnectSidebarButton() {
|
|
|
324
340
|
<Button
|
|
325
341
|
size="sm"
|
|
326
342
|
className="w-full gap-1.5 text-xs font-semibold"
|
|
327
|
-
onClick={
|
|
328
|
-
disabled={
|
|
343
|
+
onClick={handleConnect}
|
|
344
|
+
disabled={
|
|
345
|
+
authUrl.isLoading ||
|
|
346
|
+
authUrl.isFetching ||
|
|
347
|
+
isGoogleDesktopAuthPending
|
|
348
|
+
}
|
|
329
349
|
>
|
|
330
350
|
<IconExternalLink className="h-3 w-3" />
|
|
331
351
|
{authUrl.isLoading ? "Connecting..." : "Connect"}
|
|
@@ -398,6 +418,13 @@ function GoogleAccountsSection({
|
|
|
398
418
|
} = useViewPreferences();
|
|
399
419
|
const [wantAddAccount, setWantAddAccount] = useState(false);
|
|
400
420
|
const addAccountUrl = useGoogleAddAccountUrl(wantAddAccount);
|
|
421
|
+
const {
|
|
422
|
+
isDesktopGoogleAuth,
|
|
423
|
+
isGoogleDesktopAuthPending,
|
|
424
|
+
startDesktopGoogleAuth,
|
|
425
|
+
} = useGoogleDesktopAuth({
|
|
426
|
+
onSuccess: () => window.location.reload(),
|
|
427
|
+
});
|
|
401
428
|
|
|
402
429
|
useEffect(() => {
|
|
403
430
|
if (!wantAddAccount || !addAccountUrl.data?.url) return;
|
|
@@ -405,6 +432,17 @@ function GoogleAccountsSection({
|
|
|
405
432
|
setWantAddAccount(false);
|
|
406
433
|
}, [wantAddAccount, addAccountUrl.data]);
|
|
407
434
|
|
|
435
|
+
function handleAddAccount() {
|
|
436
|
+
if (isDesktopGoogleAuth) {
|
|
437
|
+
startDesktopGoogleAuth({
|
|
438
|
+
addAccount: true,
|
|
439
|
+
previousAccountCount: accounts.length,
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
setWantAddAccount(true);
|
|
444
|
+
}
|
|
445
|
+
|
|
408
446
|
function handlePickColor(color: string) {
|
|
409
447
|
updateViewPreferences({ colorMode: "single", singleColor: color });
|
|
410
448
|
}
|
|
@@ -438,7 +476,12 @@ function GoogleAccountsSection({
|
|
|
438
476
|
<TooltipTrigger asChild>
|
|
439
477
|
<button
|
|
440
478
|
type="button"
|
|
441
|
-
onClick={
|
|
479
|
+
onClick={handleAddAccount}
|
|
480
|
+
disabled={
|
|
481
|
+
addAccountUrl.isLoading ||
|
|
482
|
+
addAccountUrl.isFetching ||
|
|
483
|
+
isGoogleDesktopAuthPending
|
|
484
|
+
}
|
|
442
485
|
className="flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground"
|
|
443
486
|
>
|
|
444
487
|
<IconPlus className="h-3.5 w-3.5" />
|