@agent-native/core-corpus 0.217.0 → 0.219.0
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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +5 -3
- package/corpus/templates/analytics/CHANGELOG.md +2 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +38 -167
- package/corpus/templates/analytics/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/assets/CHANGELOG.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +51 -117
- package/corpus/templates/assets/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +34 -101
- package/corpus/templates/brain/app/routes/sources.tsx +1 -1
- package/corpus/templates/brain/vitest.config.ts +7 -0
- package/corpus/templates/calendar/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-10-16-booking-links-show-localized-visibility-badges.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +62 -101
- package/corpus/templates/clips/CHANGELOG.md +7 -20
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +20 -77
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +63 -90
- package/corpus/templates/clips/app/components/sharing/share-test-support.tsx +180 -0
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -584
- package/corpus/templates/clips/changelog/2026-10-16-share-dialogs-make-it-easier-to-see-who-has-access-and-manag.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-21-share-panels-describe-general-access-in-a-sentence.md +6 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/CHANGELOG.md +7 -0
- package/corpus/templates/content/app/components/editor/CommentStack.tsx +301 -0
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +770 -179
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +75 -27
- package/corpus/templates/content/app/components/editor/SuggestionText.tsx +18 -3
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +89 -22
- package/corpus/templates/content/app/components/editor/block-field-comment-threads.ts +15 -0
- package/corpus/templates/content/app/components/editor/block-field-comments.tsx +5 -9
- package/corpus/templates/content/app/components/editor/comment-stacks.ts +143 -0
- package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +383 -34
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +31 -0
- package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +82 -4
- package/corpus/templates/content/app/global.css +31 -0
- package/corpus/templates/content/app/i18n-data.ts +8 -0
- package/corpus/templates/content/changelog/2026-10-16-accepting-a-suggestion-on-a-page-that-changed-since-it-was-s.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-suggested-edits-that-add-remove-split-or-merge-paragraphs-li.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-blocks-with-several-comment-threads-fold-into-one-stack-in-t.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-opening-a-page-no-longer-saves-an-edit-again-after-another-o.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +8 -1
- package/corpus/templates/content/shared/suggestion-diff.ts +23 -6
- package/corpus/templates/content/shared/suggestion-formatting.ts +44 -14
- package/corpus/templates/content/shared/suggestion-text.ts +20 -5
- package/corpus/templates/design/.generated/bridge/interact-links.generated.ts +8 -8
- package/corpus/templates/design/CHANGELOG.md +8 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +18 -1
- package/corpus/templates/design/app/components/design/bridge/interact-links.bridge.ts +8 -8
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +15 -13
- package/corpus/templates/design/app/i18n/en-US.ts +1 -1
- package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -1
- package/corpus/templates/design/app/pages/Index.tsx +18 -64
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-modes.ts +15 -6
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-screen-rendering.tsx +29 -5
- package/corpus/templates/design/app/pages/design-editor/prototype-navigation-transition.ts +423 -0
- package/corpus/templates/design/app/pages/design-editor/view/single-screen-canvas.tsx +35 -9
- package/corpus/templates/design/changelog/2026-10-16-design-pages-use-localized-visibility-badges-and-a-shared-ow.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-the-design-full-app-toggle-on-the-home-page-no-longer-hides-.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-prototype-links-can-play-code-authored-screen-transitions.md +6 -0
- package/corpus/templates/design/shared/motion-authored-css-import.ts +938 -7
- package/corpus/templates/design/shared/motion-html-source.ts +1689 -135
- package/corpus/templates/design/shared/motion-prototype-transition.ts +329 -0
- package/corpus/templates/design/shared/motion-react-source.ts +2154 -126
- package/corpus/templates/design/shared/motion-text-runtime-v1.fixture.txt +221 -0
- package/corpus/templates/dispatch/CHANGELOG.md +4 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +75 -0
- package/corpus/templates/dispatch/changelog/2026-10-21-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +34 -100
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +1 -1
- package/corpus/templates/plan/CHANGELOG.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +34 -109
- package/corpus/templates/plan/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/slides/CHANGELOG.md +1 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-10-16-deck-lists-use-the-shared-ownership-filter-and-visibility-ba.md +6 -0
- package/package.json +1 -1
- package/corpus/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +0 -83
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { appPath } from "@agent-native/core/client/api-path";
|
|
2
|
-
import {
|
|
3
|
-
useActionQuery,
|
|
4
|
-
useActionMutation,
|
|
5
|
-
} from "@agent-native/core/client/hooks";
|
|
2
|
+
import { useActionMutation } from "@agent-native/core/client/hooks";
|
|
6
3
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
|
+
import {
|
|
5
|
+
useShareButtonController,
|
|
6
|
+
type ShareButtonController,
|
|
7
|
+
} from "@agent-native/core/client/sharing/useShareButtonController";
|
|
8
|
+
import {
|
|
9
|
+
ShareGeneralAccessRow,
|
|
10
|
+
SharePeopleInvite,
|
|
11
|
+
SharePeopleList,
|
|
12
|
+
} from "@agent-native/toolkit/app/sharing";
|
|
7
13
|
import {
|
|
8
14
|
useCallback,
|
|
9
15
|
useEffect,
|
|
@@ -16,15 +22,8 @@ import { toast } from "sonner";
|
|
|
16
22
|
|
|
17
23
|
import {
|
|
18
24
|
CopyButton,
|
|
19
|
-
GeneralAccessSelect,
|
|
20
|
-
InvitePeopleField,
|
|
21
|
-
PeopleAccessSection,
|
|
22
25
|
ShareSectionLabel,
|
|
23
26
|
nestedLayerDismissGuards,
|
|
24
|
-
useResourceVisibilityMutation,
|
|
25
|
-
type SharesQuery,
|
|
26
|
-
type SharesResponse,
|
|
27
|
-
type Visibility,
|
|
28
27
|
} from "@/components/sharing/share-ui";
|
|
29
28
|
import { Button } from "@/components/ui/button";
|
|
30
29
|
import {
|
|
@@ -53,6 +52,7 @@ export function ShareMeetingPopover({
|
|
|
53
52
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
54
53
|
<PopoverContent
|
|
55
54
|
align="end"
|
|
55
|
+
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
56
56
|
{...nestedLayerDismissGuards()}
|
|
57
57
|
className="max-h-[calc(100vh-1rem)] w-[440px] max-w-[calc(100vw-1rem)] overflow-y-auto border-border p-0"
|
|
58
58
|
>
|
|
@@ -80,32 +80,18 @@ function ShareMeetingContent({
|
|
|
80
80
|
[meetingId],
|
|
81
81
|
);
|
|
82
82
|
|
|
83
|
-
const
|
|
83
|
+
const controller = useShareButtonController({
|
|
84
84
|
resourceType: "meeting",
|
|
85
85
|
resourceId: meetingId,
|
|
86
|
+
defaultOpen: true,
|
|
86
87
|
});
|
|
87
88
|
|
|
88
|
-
const data = sharesQuery.data;
|
|
89
|
-
const canManage = data?.role === "owner" || data?.role === "admin";
|
|
90
|
-
const visibility: Visibility =
|
|
91
|
-
(data?.visibility as Visibility | null) ?? "private";
|
|
92
|
-
const { setResourceVisibility, isPending } = useResourceVisibilityMutation(
|
|
93
|
-
"meeting",
|
|
94
|
-
meetingId,
|
|
95
|
-
sharesQuery,
|
|
96
|
-
);
|
|
97
|
-
const visibilityPending = isPending || sharesQuery.isLoading;
|
|
98
|
-
|
|
99
89
|
return (
|
|
100
90
|
<div className="min-w-0 px-4 py-3">
|
|
101
91
|
<LinkTab
|
|
102
92
|
meetingId={meetingId}
|
|
103
93
|
shareUrl={shareUrl}
|
|
104
|
-
|
|
105
|
-
canManage={canManage}
|
|
106
|
-
visibility={visibility}
|
|
107
|
-
visibilityPending={visibilityPending}
|
|
108
|
-
onVisibilityChange={setResourceVisibility}
|
|
94
|
+
controller={controller}
|
|
109
95
|
shareTranscript={shareTranscript}
|
|
110
96
|
transcriptReady={transcriptReady}
|
|
111
97
|
/>
|
|
@@ -116,24 +102,13 @@ function ShareMeetingContent({
|
|
|
116
102
|
function LinkTab({
|
|
117
103
|
meetingId,
|
|
118
104
|
shareUrl,
|
|
119
|
-
|
|
120
|
-
canManage,
|
|
121
|
-
visibility,
|
|
122
|
-
visibilityPending,
|
|
123
|
-
onVisibilityChange,
|
|
105
|
+
controller,
|
|
124
106
|
shareTranscript,
|
|
125
107
|
transcriptReady,
|
|
126
108
|
}: {
|
|
127
109
|
meetingId: string;
|
|
128
110
|
shareUrl: string;
|
|
129
|
-
|
|
130
|
-
canManage: boolean;
|
|
131
|
-
visibility: Visibility;
|
|
132
|
-
visibilityPending: boolean;
|
|
133
|
-
onVisibilityChange: (
|
|
134
|
-
next: Visibility,
|
|
135
|
-
options?: { onSuccess?: () => void },
|
|
136
|
-
) => void;
|
|
111
|
+
controller: ShareButtonController;
|
|
137
112
|
shareTranscript: boolean;
|
|
138
113
|
transcriptReady: boolean;
|
|
139
114
|
}) {
|
|
@@ -143,7 +118,7 @@ function LinkTab({
|
|
|
143
118
|
{ id: string; shareTranscript: boolean }
|
|
144
119
|
>("update-meeting");
|
|
145
120
|
const [includeTranscript, setIncludeTranscript] = useState(shareTranscript);
|
|
146
|
-
const data =
|
|
121
|
+
const { sharesQuery, data, canManage, visibility } = controller;
|
|
147
122
|
const isPublic = visibility === "public";
|
|
148
123
|
const sharesLoaded = data?.visibility != null;
|
|
149
124
|
const createAgentLink = useActionMutation("create-agent-resource-link");
|
|
@@ -216,45 +191,13 @@ function LinkTab({
|
|
|
216
191
|
|
|
217
192
|
return (
|
|
218
193
|
<div className="space-y-3">
|
|
219
|
-
{
|
|
220
|
-
<InvitePeopleField
|
|
221
|
-
resourceType="meeting"
|
|
222
|
-
resourceId={meetingId}
|
|
223
|
-
sharesQuery={sharesQuery}
|
|
224
|
-
onError={(err) =>
|
|
225
|
-
toast.error(
|
|
226
|
-
err instanceof Error
|
|
227
|
-
? err.message
|
|
228
|
-
: t("clipsFinalRaw.inviteFailed"),
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
/>
|
|
232
|
-
) : null}
|
|
194
|
+
<SharePeopleInvite controller={controller} />
|
|
233
195
|
|
|
234
196
|
<div className="space-y-2">
|
|
235
197
|
<ShareSectionLabel>{t("shareUi.whoHasAccess")}</ShareSectionLabel>
|
|
236
198
|
<div className="flex flex-col gap-1">
|
|
237
|
-
<
|
|
238
|
-
|
|
239
|
-
resourceId={meetingId}
|
|
240
|
-
sharesQuery={sharesQuery}
|
|
241
|
-
canManage={canManage}
|
|
242
|
-
onError={(err, action) =>
|
|
243
|
-
toast.error(
|
|
244
|
-
err instanceof Error
|
|
245
|
-
? err.message
|
|
246
|
-
: action === "permission"
|
|
247
|
-
? t("clipsFinalRaw.permissionUpdateFailed")
|
|
248
|
-
: t("clipsFinalRaw.removePersonFailed"),
|
|
249
|
-
)
|
|
250
|
-
}
|
|
251
|
-
/>
|
|
252
|
-
<GeneralAccessSelect
|
|
253
|
-
visibility={visibility}
|
|
254
|
-
canManage={canManage}
|
|
255
|
-
isPending={visibilityPending}
|
|
256
|
-
onChange={onVisibilityChange}
|
|
257
|
-
/>
|
|
199
|
+
<SharePeopleList controller={controller} />
|
|
200
|
+
<ShareGeneralAccessRow controller={controller} sentenceTrigger />
|
|
258
201
|
</div>
|
|
259
202
|
</div>
|
|
260
203
|
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { trackEvent } from "@agent-native/core/client/analytics";
|
|
2
2
|
import { appPath } from "@agent-native/core/client/api-path";
|
|
3
|
-
import {
|
|
4
|
-
useActionMutation,
|
|
5
|
-
useActionQuery,
|
|
6
|
-
useSession,
|
|
7
|
-
} from "@agent-native/core/client/hooks";
|
|
3
|
+
import { useActionMutation, useSession } from "@agent-native/core/client/hooks";
|
|
8
4
|
import { useT } from "@agent-native/core/client/i18n";
|
|
5
|
+
import {
|
|
6
|
+
useShareButtonController,
|
|
7
|
+
type ShareButtonController,
|
|
8
|
+
} from "@agent-native/core/client/sharing/useShareButtonController";
|
|
9
|
+
import {
|
|
10
|
+
ShareGeneralAccessRow,
|
|
11
|
+
SharePeopleInvite,
|
|
12
|
+
SharePeopleList,
|
|
13
|
+
} from "@agent-native/toolkit/app/sharing";
|
|
9
14
|
import { writeClipboardText } from "@agent-native/toolkit/clipboard";
|
|
10
15
|
import {
|
|
11
16
|
AgentDestinationActions,
|
|
@@ -41,14 +46,8 @@ import {
|
|
|
41
46
|
} from "@/components/agent-destination-logos";
|
|
42
47
|
import {
|
|
43
48
|
CopyButton,
|
|
44
|
-
GeneralAccessSelect,
|
|
45
|
-
InvitePeopleField,
|
|
46
|
-
PeopleAccessSection,
|
|
47
49
|
ShareSectionLabel,
|
|
48
50
|
nestedLayerDismissGuards,
|
|
49
|
-
useResourceVisibilityMutation,
|
|
50
|
-
type SharesQuery,
|
|
51
|
-
type SharesResponse,
|
|
52
51
|
type Visibility,
|
|
53
52
|
} from "@/components/sharing/share-ui";
|
|
54
53
|
import { Button } from "@/components/ui/button";
|
|
@@ -326,19 +325,22 @@ function ShareRecordingContent({
|
|
|
326
325
|
setShareMode("people");
|
|
327
326
|
}, [recordingId]);
|
|
328
327
|
|
|
329
|
-
const
|
|
330
|
-
"
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
328
|
+
const controller = useShareButtonController({
|
|
329
|
+
resourceType: "recording",
|
|
330
|
+
resourceId: recordingId,
|
|
331
|
+
defaultOpen: !viewerReshareOnly,
|
|
332
|
+
shareUrl: absoluteAppUrl(`/r/${recordingId}`),
|
|
333
|
+
});
|
|
334
|
+
const sharesQuery = controller.sharesQuery;
|
|
335
|
+
const data = viewerReshareOnly ? undefined : controller.data;
|
|
336
336
|
const role = data?.role ?? initialRole;
|
|
337
|
-
const canManage =
|
|
337
|
+
const canManage = !viewerReshareOnly && controller.canManage;
|
|
338
338
|
const canViewShares =
|
|
339
339
|
role === "owner" || role === "admin" || role === "editor";
|
|
340
340
|
const visibility =
|
|
341
|
-
(
|
|
341
|
+
(viewerReshareOnly
|
|
342
|
+
? null
|
|
343
|
+
: (controller.visibilityOverride ?? data?.visibility)) ??
|
|
342
344
|
initialVisibility ??
|
|
343
345
|
null;
|
|
344
346
|
const canEmbed = canViewShares || visibility === "public";
|
|
@@ -355,9 +357,8 @@ function ShareRecordingContent({
|
|
|
355
357
|
ownerViaId,
|
|
356
358
|
);
|
|
357
359
|
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
const visibilityPending = visibilityMutationPending || sharesQuery.isLoading;
|
|
360
|
+
const visibilityPending =
|
|
361
|
+
controller.visibilityTransition.submitting || sharesQuery.isLoading;
|
|
361
362
|
const sharesLoaded = visibility !== null;
|
|
362
363
|
const viewTitle =
|
|
363
364
|
view === "social"
|
|
@@ -368,11 +369,8 @@ function ShareRecordingContent({
|
|
|
368
369
|
const peopleTab = (
|
|
369
370
|
<PeopleTab
|
|
370
371
|
recordingId={recordingId}
|
|
371
|
-
|
|
372
|
+
controller={controller}
|
|
372
373
|
visibility={visibility}
|
|
373
|
-
visibilityPending={visibilityPending}
|
|
374
|
-
onVisibilityChange={setResourceVisibility}
|
|
375
|
-
canManage={canManage}
|
|
376
374
|
hasPassword={passwordProtected}
|
|
377
375
|
expiresAt={currentExpiry}
|
|
378
376
|
onPasswordChange={setPasswordProtected}
|
|
@@ -462,7 +460,7 @@ function ShareRecordingContent({
|
|
|
462
460
|
) : (
|
|
463
461
|
<ClipsEmbedConfigurator
|
|
464
462
|
recordingId={recordingId}
|
|
465
|
-
|
|
463
|
+
controller={controller}
|
|
466
464
|
visibility={visibility}
|
|
467
465
|
canManage={canManage}
|
|
468
466
|
ownerViaId={ownerViaId}
|
|
@@ -498,11 +496,8 @@ function ShareOptionRow({
|
|
|
498
496
|
|
|
499
497
|
function PeopleTab({
|
|
500
498
|
recordingId,
|
|
501
|
-
|
|
499
|
+
controller,
|
|
502
500
|
visibility,
|
|
503
|
-
visibilityPending,
|
|
504
|
-
onVisibilityChange,
|
|
505
|
-
canManage,
|
|
506
501
|
hasPassword,
|
|
507
502
|
expiresAt,
|
|
508
503
|
onPasswordChange,
|
|
@@ -514,14 +509,8 @@ function PeopleTab({
|
|
|
514
509
|
onOpenEmbed,
|
|
515
510
|
}: {
|
|
516
511
|
recordingId: string;
|
|
517
|
-
|
|
512
|
+
controller: ShareButtonController;
|
|
518
513
|
visibility: Visibility | null;
|
|
519
|
-
visibilityPending: boolean;
|
|
520
|
-
onVisibilityChange: (
|
|
521
|
-
next: Visibility,
|
|
522
|
-
options?: { onSuccess?: () => void },
|
|
523
|
-
) => void;
|
|
524
|
-
canManage: boolean;
|
|
525
514
|
hasPassword?: boolean;
|
|
526
515
|
expiresAt: string | null;
|
|
527
516
|
onPasswordChange: (hasPassword: boolean) => void;
|
|
@@ -556,55 +545,37 @@ function PeopleTab({
|
|
|
556
545
|
return (
|
|
557
546
|
<div className="flex flex-col gap-3">
|
|
558
547
|
<div className="flex flex-col gap-3">
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
toast.error(
|
|
569
|
-
err instanceof Error
|
|
570
|
-
? err.message
|
|
571
|
-
: t("clipsFinalRaw.inviteFailed"),
|
|
572
|
-
)
|
|
573
|
-
}
|
|
574
|
-
/>
|
|
575
|
-
) : null}
|
|
548
|
+
<SharePeopleInvite
|
|
549
|
+
controller={controller}
|
|
550
|
+
roleCopy={{
|
|
551
|
+
commenter: {
|
|
552
|
+
label: t("shareUi.recordingCommenter.label"),
|
|
553
|
+
description: t("shareUi.recordingCommenter.description"),
|
|
554
|
+
},
|
|
555
|
+
}}
|
|
556
|
+
/>
|
|
576
557
|
|
|
577
558
|
{canViewShares ? (
|
|
578
559
|
visibility ? (
|
|
579
560
|
<div className="flex flex-col gap-1.5">
|
|
580
561
|
<ShareSectionLabel>{t("shareUi.whoHasAccess")}</ShareSectionLabel>
|
|
581
562
|
<div className="flex flex-col gap-0.5">
|
|
582
|
-
<
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
? t("clipsFinalRaw.permissionUpdateFailed")
|
|
599
|
-
: t("clipsFinalRaw.removePersonFailed"),
|
|
600
|
-
)
|
|
601
|
-
}
|
|
602
|
-
/>
|
|
603
|
-
<GeneralAccessSelect
|
|
604
|
-
visibility={visibility}
|
|
605
|
-
canManage={canManage}
|
|
606
|
-
isPending={visibilityPending}
|
|
607
|
-
onChange={onVisibilityChange}
|
|
563
|
+
<div className="max-h-72 overflow-y-auto">
|
|
564
|
+
<SharePeopleList
|
|
565
|
+
controller={controller}
|
|
566
|
+
roleCopy={{
|
|
567
|
+
commenter: {
|
|
568
|
+
label: t("shareUi.recordingCommenter.label"),
|
|
569
|
+
description: t(
|
|
570
|
+
"shareUi.recordingCommenter.description",
|
|
571
|
+
),
|
|
572
|
+
},
|
|
573
|
+
}}
|
|
574
|
+
/>
|
|
575
|
+
</div>
|
|
576
|
+
<ShareGeneralAccessRow
|
|
577
|
+
controller={{ ...controller, visibility }}
|
|
578
|
+
sentenceTrigger
|
|
608
579
|
/>
|
|
609
580
|
<RecordingAccessControls
|
|
610
581
|
recordingId={recordingId}
|
|
@@ -1133,13 +1104,13 @@ function SocialTab({
|
|
|
1133
1104
|
|
|
1134
1105
|
function ClipsEmbedConfigurator({
|
|
1135
1106
|
recordingId,
|
|
1136
|
-
|
|
1107
|
+
controller,
|
|
1137
1108
|
visibility,
|
|
1138
1109
|
canManage,
|
|
1139
1110
|
ownerViaId,
|
|
1140
1111
|
}: {
|
|
1141
1112
|
recordingId: string;
|
|
1142
|
-
|
|
1113
|
+
controller: ShareButtonController;
|
|
1143
1114
|
visibility: Visibility | null;
|
|
1144
1115
|
canManage: boolean;
|
|
1145
1116
|
ownerViaId?: string;
|
|
@@ -1156,12 +1127,8 @@ function ClipsEmbedConfigurator({
|
|
|
1156
1127
|
const visibilityLabel = visibility
|
|
1157
1128
|
? t(`shareUi.visibility.${visibility}.label`)
|
|
1158
1129
|
: "";
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1161
|
-
recordingId,
|
|
1162
|
-
sharesQuery,
|
|
1163
|
-
);
|
|
1164
|
-
const makePublic = () => setResourceVisibility("public");
|
|
1130
|
+
const isPending = controller.visibilityTransition.submitting;
|
|
1131
|
+
const makePublic = () => controller.handleVisibility("public");
|
|
1165
1132
|
|
|
1166
1133
|
const src = useMemo(() => {
|
|
1167
1134
|
const params: string[] = [];
|
|
@@ -1219,6 +1186,12 @@ function ClipsEmbedConfigurator({
|
|
|
1219
1186
|
</div>
|
|
1220
1187
|
) : null}
|
|
1221
1188
|
|
|
1189
|
+
{controller.shareError ? (
|
|
1190
|
+
<div role="alert" className="text-xs text-destructive">
|
|
1191
|
+
{controller.shareError}
|
|
1192
|
+
</div>
|
|
1193
|
+
) : null}
|
|
1194
|
+
|
|
1222
1195
|
<CopyButton value={code} className="w-full" variant="default">
|
|
1223
1196
|
{t("shareDialog.copyEmbedCode")}
|
|
1224
1197
|
</CopyButton>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { ShareButtonSharesResponse } from "@agent-native/core/client/sharing/useShareButtonController";
|
|
2
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3
|
+
import React, { act, type ReactNode } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { afterEach, beforeEach, expect, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
8
|
+
|
|
9
|
+
const mocks = vi.hoisted(() => ({
|
|
10
|
+
data: undefined as ShareButtonSharesResponse | undefined,
|
|
11
|
+
query: vi.fn(),
|
|
12
|
+
refetch: vi.fn(async () => undefined),
|
|
13
|
+
visibility: vi.fn(),
|
|
14
|
+
share: vi.fn(),
|
|
15
|
+
unshare: vi.fn(),
|
|
16
|
+
update: vi.fn(),
|
|
17
|
+
createLink: vi.fn(async () => ({
|
|
18
|
+
contextUrl: "https://clips.example.test/scoped-agent",
|
|
19
|
+
})),
|
|
20
|
+
clipboard: vi.fn(async (_value: string) => true),
|
|
21
|
+
track: vi.fn(),
|
|
22
|
+
}));
|
|
23
|
+
function mutation(name: string) {
|
|
24
|
+
if (name === "set-resource-visibility")
|
|
25
|
+
return { mutateAsync: mocks.visibility };
|
|
26
|
+
if (name === "share-resource") return { mutate: mocks.share };
|
|
27
|
+
if (name === "unshare-resource") return { mutate: mocks.unshare };
|
|
28
|
+
if (name.includes("agent-link") || name === "create-agent-resource-link")
|
|
29
|
+
return { mutateAsync: mocks.createLink };
|
|
30
|
+
return { mutate: mocks.update };
|
|
31
|
+
}
|
|
32
|
+
vi.mock("@agent-native/core/client/use-action", () => ({
|
|
33
|
+
useActionQuery: (...args: unknown[]) => {
|
|
34
|
+
mocks.query(...args);
|
|
35
|
+
return { data: mocks.data, refetch: mocks.refetch, isLoading: false };
|
|
36
|
+
},
|
|
37
|
+
useActionMutation: (name: string) => mutation(name),
|
|
38
|
+
}));
|
|
39
|
+
vi.mock("@agent-native/core/client/hooks", () => ({
|
|
40
|
+
useActionMutation: (name: string) => mutation(name),
|
|
41
|
+
useSession: () => ({ session: { userId: "test-owner" } }),
|
|
42
|
+
}));
|
|
43
|
+
vi.mock("@agent-native/core/client/org/hooks", () => ({
|
|
44
|
+
useOrg: () => ({ data: null }),
|
|
45
|
+
}));
|
|
46
|
+
vi.mock("@agent-native/core/client/analytics", () => ({
|
|
47
|
+
trackEvent: mocks.track,
|
|
48
|
+
}));
|
|
49
|
+
vi.mock("@agent-native/core/client/i18n", () => ({
|
|
50
|
+
useT: () => (key: string, options?: { defaultValue?: string }) =>
|
|
51
|
+
options?.defaultValue ?? key,
|
|
52
|
+
}));
|
|
53
|
+
vi.mock("@agent-native/toolkit/clipboard", () => ({
|
|
54
|
+
writeClipboardText: mocks.clipboard,
|
|
55
|
+
}));
|
|
56
|
+
vi.mock("@/components/ui/dialog", () => ({
|
|
57
|
+
Dialog: ({ open, children }: { open: boolean; children: ReactNode }) =>
|
|
58
|
+
open ? children : null,
|
|
59
|
+
DialogContent: ({ children }: { children: ReactNode }) => (
|
|
60
|
+
<div>{children}</div>
|
|
61
|
+
),
|
|
62
|
+
DialogTitle: ({ children }: { children: ReactNode }) => <h2>{children}</h2>,
|
|
63
|
+
}));
|
|
64
|
+
vi.mock("@/components/ui/popover", () => ({
|
|
65
|
+
Popover: ({ children }: { children: ReactNode }) => children,
|
|
66
|
+
PopoverContent: ({ children }: { children: ReactNode }) => (
|
|
67
|
+
<div>{children}</div>
|
|
68
|
+
),
|
|
69
|
+
PopoverTrigger: ({ children }: { children: ReactNode }) => children,
|
|
70
|
+
PopoverAnchor: ({ children }: { children: ReactNode }) => children,
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
export function shareTestHarness() {
|
|
74
|
+
let root: ReturnType<typeof createRoot>;
|
|
75
|
+
let container: HTMLDivElement;
|
|
76
|
+
let client: QueryClient;
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
vi.clearAllMocks();
|
|
79
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
80
|
+
vi.stubGlobal(
|
|
81
|
+
"fetch",
|
|
82
|
+
vi.fn(async () => ({ ok: true, json: async () => ({ members: [] }) })),
|
|
83
|
+
);
|
|
84
|
+
Element.prototype.scrollIntoView = vi.fn();
|
|
85
|
+
Element.prototype.hasPointerCapture = vi.fn(() => false);
|
|
86
|
+
Element.prototype.setPointerCapture = vi.fn();
|
|
87
|
+
Element.prototype.releasePointerCapture = vi.fn();
|
|
88
|
+
mocks.data = {
|
|
89
|
+
ownerEmail: "owner@example.test",
|
|
90
|
+
orgId: "org-test",
|
|
91
|
+
role: "owner",
|
|
92
|
+
visibility: "private",
|
|
93
|
+
shares: [
|
|
94
|
+
{
|
|
95
|
+
id: "share-test",
|
|
96
|
+
principalType: "user",
|
|
97
|
+
principalId: "viewer@example.test",
|
|
98
|
+
role: "viewer",
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
mocks.visibility
|
|
103
|
+
.mockReset()
|
|
104
|
+
.mockImplementation(async ({ visibility }: { visibility: string }) => ({
|
|
105
|
+
visibility,
|
|
106
|
+
}));
|
|
107
|
+
mocks.clipboard.mockResolvedValue(true);
|
|
108
|
+
client = new QueryClient({
|
|
109
|
+
defaultOptions: {
|
|
110
|
+
queries: { retry: false },
|
|
111
|
+
mutations: { retry: false },
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
container = document.createElement("div");
|
|
115
|
+
document.body.appendChild(container);
|
|
116
|
+
root = createRoot(container);
|
|
117
|
+
});
|
|
118
|
+
afterEach(() => {
|
|
119
|
+
act(() => root.unmount());
|
|
120
|
+
client.clear();
|
|
121
|
+
container.remove();
|
|
122
|
+
vi.unstubAllGlobals();
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
async render(children: ReactNode) {
|
|
126
|
+
await act(async () =>
|
|
127
|
+
root.render(
|
|
128
|
+
<QueryClientProvider client={client}>
|
|
129
|
+
<TooltipProvider>{children}</TooltipProvider>
|
|
130
|
+
</QueryClientProvider>,
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
get client() {
|
|
135
|
+
return client;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function button(label: string, scope: ParentNode = document.body) {
|
|
140
|
+
const result = Array.from(
|
|
141
|
+
scope.querySelectorAll<HTMLButtonElement>("button"),
|
|
142
|
+
).find(
|
|
143
|
+
(el) =>
|
|
144
|
+
el.textContent?.trim() === label ||
|
|
145
|
+
el.getAttribute("aria-label") === label,
|
|
146
|
+
);
|
|
147
|
+
expect(result, `button ${label}`).toBeDefined();
|
|
148
|
+
return result!;
|
|
149
|
+
}
|
|
150
|
+
export async function click(element: HTMLElement) {
|
|
151
|
+
await act(async () => {
|
|
152
|
+
element.dispatchEvent(
|
|
153
|
+
new MouseEvent("mousedown", { bubbles: true, button: 0 }),
|
|
154
|
+
);
|
|
155
|
+
element.click();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
export async function input(element: HTMLInputElement, value: string) {
|
|
159
|
+
await act(async () => {
|
|
160
|
+
Object.getOwnPropertyDescriptor(
|
|
161
|
+
HTMLInputElement.prototype,
|
|
162
|
+
"value",
|
|
163
|
+
)!.set!.call(element, value);
|
|
164
|
+
element.dispatchEvent(new Event("input", { bubbles: true }));
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
export async function select(trigger: HTMLElement, label: string) {
|
|
168
|
+
await act(async () =>
|
|
169
|
+
trigger.dispatchEvent(
|
|
170
|
+
new KeyboardEvent("keydown", { key: "ArrowDown", bubbles: true }),
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
const option = Array.from(
|
|
174
|
+
document.querySelectorAll<HTMLElement>('[role="option"]'),
|
|
175
|
+
).find((el) => el.textContent?.includes(label));
|
|
176
|
+
expect(option, `option ${label}`).toBeDefined();
|
|
177
|
+
await click(option!);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export { mocks };
|