@agent-native/toolkit 0.211.0 → 0.212.0-nightly-20261021010049
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/agent-native.eject.json +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +23 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +23 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +23 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +23 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +23 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +23 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +23 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +23 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +23 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +23 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +23 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +23 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/sharing/OwnershipFilter.d.ts +8 -0
- package/dist/app/sharing/OwnershipFilter.d.ts.map +1 -0
- package/dist/app/sharing/OwnershipFilter.js +20 -0
- package/dist/app/sharing/OwnershipFilter.js.map +1 -0
- package/dist/app/sharing/ShareButton.d.ts +43 -1
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +102 -63
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/app/sharing/ShareDialog.d.ts +3 -1
- package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/app/sharing/ShareDialog.js +18 -12
- package/dist/app/sharing/ShareDialog.js.map +1 -1
- package/dist/app/sharing/ShareVisibilityConfirmDialog.d.ts +20 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.d.ts.map +1 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.js +57 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.js.map +1 -0
- package/dist/app/sharing/VisibilityBadge.d.ts +8 -1
- package/dist/app/sharing/VisibilityBadge.d.ts.map +1 -1
- package/dist/app/sharing/VisibilityBadge.js +16 -1
- package/dist/app/sharing/VisibilityBadge.js.map +1 -1
- package/dist/app/sharing/index.d.ts +2 -0
- package/dist/app/sharing/index.d.ts.map +1 -1
- package/dist/app/sharing/index.js +2 -0
- package/dist/app/sharing/index.js.map +1 -1
- package/dist/chat-history/ChatHistoryList.d.ts +19 -0
- package/dist/chat-history/ChatHistoryList.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryList.js +19 -7
- package/dist/chat-history/ChatHistoryList.js.map +1 -1
- package/dist/chat-history/ChatHistoryRail.d.ts +55 -8
- package/dist/chat-history/ChatHistoryRail.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryRail.js +33 -7
- package/dist/chat-history/ChatHistoryRail.js.map +1 -1
- package/dist/chat-history/index.d.ts +3 -3
- package/dist/chat-history/index.d.ts.map +1 -1
- package/dist/chat-history/index.js +1 -1
- package/dist/chat-history/index.js.map +1 -1
- package/dist/chat-history/useChatHistoryRailController.d.ts +44 -0
- package/dist/chat-history/useChatHistoryRailController.d.ts.map +1 -1
- package/dist/chat-history/useChatHistoryRailController.js +46 -0
- package/dist/chat-history/useChatHistoryRailController.js.map +1 -1
- package/dist/chat-history.css +29 -0
- package/dist/composer/TiptapComposer.d.ts +7 -0
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +15 -2
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/sharing/OwnershipFilter.d.ts +21 -0
- package/dist/sharing/OwnershipFilter.d.ts.map +1 -0
- package/dist/sharing/OwnershipFilter.js +30 -0
- package/dist/sharing/OwnershipFilter.js.map +1 -0
- package/dist/sharing/VisibilityBadge.d.ts +12 -2
- package/dist/sharing/VisibilityBadge.d.ts.map +1 -1
- package/dist/sharing/VisibilityBadge.js +13 -4
- package/dist/sharing/VisibilityBadge.js.map +1 -1
- package/dist/sharing/index.d.ts +2 -1
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +2 -1
- package/dist/sharing/index.js.map +1 -1
- package/dist/ui/alert-dialog.d.ts +2 -0
- package/dist/ui/alert-dialog.d.ts.map +1 -1
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/tooltip.d.ts +6 -1
- package/dist/ui/tooltip.d.ts.map +1 -1
- package/dist/ui/tooltip.js +13 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/package.json +4 -4
- package/src/app/i18n/catalogs/ar-SA.ts +26 -0
- package/src/app/i18n/catalogs/de-DE.ts +25 -0
- package/src/app/i18n/catalogs/en-US.ts +25 -0
- package/src/app/i18n/catalogs/es-ES.ts +25 -0
- package/src/app/i18n/catalogs/fr-FR.ts +25 -0
- package/src/app/i18n/catalogs/hi-IN.ts +25 -0
- package/src/app/i18n/catalogs/ja-JP.ts +25 -0
- package/src/app/i18n/catalogs/ko-KR.ts +25 -0
- package/src/app/i18n/catalogs/pt-BR.ts +25 -0
- package/src/app/i18n/catalogs/zh-CN.ts +25 -0
- package/src/app/i18n/catalogs/zh-TW.ts +25 -0
- package/src/app/sharing/OwnershipFilter.tsx +35 -0
- package/src/app/sharing/ShareButton.tsx +384 -259
- package/src/app/sharing/ShareDialog.spec.tsx +50 -0
- package/src/app/sharing/ShareDialog.tsx +51 -15
- package/src/app/sharing/ShareVisibilityConfirmDialog.spec.tsx +138 -0
- package/src/app/sharing/ShareVisibilityConfirmDialog.tsx +124 -0
- package/src/app/sharing/ShareVisibilityKeyboard.spec.tsx +244 -0
- package/src/app/sharing/VisibilityBadge.spec.tsx +65 -0
- package/src/app/sharing/VisibilityBadge.tsx +31 -3
- package/src/app/sharing/index.ts +2 -0
- package/src/app/sharing/share-visibility-mutation-lifecycle.spec.tsx +1107 -0
- package/src/app/sharing/useShareButtonController.spec.tsx +226 -37
- package/src/app/sharing/useShareDialogController.spec.tsx +357 -9
- package/src/chat-history/ChatHistoryList.spec.tsx +157 -0
- package/src/chat-history/ChatHistoryList.tsx +104 -10
- package/src/chat-history/ChatHistoryRail.spec.tsx +50 -1
- package/src/chat-history/ChatHistoryRail.tsx +177 -26
- package/src/chat-history/ChatHistoryRailSections.spec.tsx +410 -0
- package/src/chat-history/index.ts +8 -0
- package/src/chat-history/useChatHistoryRailController.ts +94 -0
- package/src/chat-history/useChatHistoryRailSectionsController.spec.tsx +133 -0
- package/src/chat-history.css +29 -0
- package/src/composer/TiptapComposer.spec.ts +19 -0
- package/src/composer/TiptapComposer.tsx +26 -5
- package/src/sharing/OwnershipFilter.spec.tsx +108 -0
- package/src/sharing/OwnershipFilter.tsx +103 -0
- package/src/sharing/VisibilityBadge.spec.ts +53 -35
- package/src/sharing/VisibilityBadge.tsx +23 -3
- package/src/sharing/index.ts +11 -0
- package/src/ui/alert-dialog.tsx +7 -2
- package/src/ui/tooltip.tsx +22 -1
|
@@ -55,11 +55,13 @@ import {
|
|
|
55
55
|
} from "react";
|
|
56
56
|
import type {
|
|
57
57
|
KeyboardEvent as ReactKeyboardEvent,
|
|
58
|
+
Ref,
|
|
58
59
|
UIEvent as ReactUIEvent,
|
|
59
60
|
} from "react";
|
|
60
61
|
|
|
61
62
|
import { AccessRequestsSection } from "./AccessRequestsSection.js";
|
|
62
63
|
import { AgentShareSection } from "./AgentShareSection.js";
|
|
64
|
+
import { ShareVisibilityConfirmDialog } from "./ShareVisibilityConfirmDialog.js";
|
|
63
65
|
|
|
64
66
|
export interface ShareButtonProps {
|
|
65
67
|
resourceType: string;
|
|
@@ -125,6 +127,11 @@ export interface ShareButtonProps {
|
|
|
125
127
|
visibilityCopy?: Partial<
|
|
126
128
|
Record<Visibility, { label?: string; description?: string }>
|
|
127
129
|
>;
|
|
130
|
+
/**
|
|
131
|
+
* What is specific to this resource, already translated, added to the
|
|
132
|
+
* confirmation shown before it becomes visible to the organization.
|
|
133
|
+
*/
|
|
134
|
+
visibilityConfirmDetail?: ReactNode;
|
|
128
135
|
roleCopy?: Partial<Record<Role, { label?: string; description?: string }>>;
|
|
129
136
|
allowedRoles?: readonly Role[];
|
|
130
137
|
peopleAccessLabel?: ReactNode;
|
|
@@ -450,44 +457,17 @@ function SharePanel(
|
|
|
450
457
|
const t = useT();
|
|
451
458
|
const { controller } = props;
|
|
452
459
|
const {
|
|
453
|
-
inviteEmail,
|
|
454
|
-
setInviteEmail: onInviteEmailChange,
|
|
455
460
|
activeShareTab,
|
|
456
461
|
handleShareTabChange,
|
|
457
462
|
data,
|
|
458
|
-
policy,
|
|
459
463
|
visibility,
|
|
460
464
|
canManage,
|
|
461
|
-
role,
|
|
462
|
-
setRole,
|
|
463
|
-
notifyPeople,
|
|
464
|
-
setNotifyPeople,
|
|
465
|
-
shareMessage,
|
|
466
|
-
setShareMessage,
|
|
467
|
-
messageOpen,
|
|
468
|
-
setMessageOpen,
|
|
469
465
|
shareError,
|
|
470
|
-
setShareError,
|
|
471
|
-
suggestionsOpen,
|
|
472
|
-
setSuggestionsOpen,
|
|
473
|
-
inFlight,
|
|
474
|
-
memberSearch,
|
|
475
|
-
memberSuggestions,
|
|
476
|
-
groupSuggestions,
|
|
477
|
-
selectGroup,
|
|
478
|
-
knownMembers,
|
|
479
|
-
shares,
|
|
480
|
-
handleVisibility,
|
|
481
466
|
handleHideInSearch,
|
|
482
|
-
handleAdd,
|
|
483
|
-
handleChangeRole,
|
|
484
|
-
handleRemove,
|
|
485
467
|
} = controller;
|
|
486
|
-
const hasInviteEmail = inviteEmail.trim().length > 0;
|
|
487
468
|
|
|
488
469
|
const loadFailed = controller.sharesQuery.isError && data === undefined;
|
|
489
470
|
const isLoading = !loadFailed && data === undefined;
|
|
490
|
-
const meta = visibilityMeta(visibility, t, props.visibilityCopy);
|
|
491
471
|
const peopleAccessLabel =
|
|
492
472
|
props.peopleAccessLabel ??
|
|
493
473
|
t("agentChat.share.peopleWithAccess", {
|
|
@@ -599,36 +579,20 @@ function SharePanel(
|
|
|
599
579
|
{generalAccessLabel}
|
|
600
580
|
</div>
|
|
601
581
|
) : null}
|
|
602
|
-
<
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
disabled={!canManage}
|
|
614
|
-
sentenceTrigger={Boolean(props.agentTabContent)}
|
|
615
|
-
visibilityCopy={props.visibilityCopy}
|
|
616
|
-
allowPublic={policy.allowPublic}
|
|
582
|
+
<ShareGeneralAccessRow
|
|
583
|
+
controller={controller}
|
|
584
|
+
visibilityCopy={props.visibilityCopy}
|
|
585
|
+
sentenceTrigger={Boolean(props.agentTabContent)}
|
|
586
|
+
confirmDetail={props.visibilityConfirmDetail}
|
|
587
|
+
>
|
|
588
|
+
{visibility === "org" && props.hideInSearchControl ? (
|
|
589
|
+
<AdvancedAccessPopover
|
|
590
|
+
control={props.hideInSearchControl}
|
|
591
|
+
canManage={canManage}
|
|
592
|
+
onToggle={handleHideInSearch}
|
|
617
593
|
/>
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
<span className="sr-only">{meta.description}</span>
|
|
621
|
-
) : null}
|
|
622
|
-
{visibility === "org" && props.hideInSearchControl ? (
|
|
623
|
-
<AdvancedAccessPopover
|
|
624
|
-
control={props.hideInSearchControl}
|
|
625
|
-
canManage={canManage}
|
|
626
|
-
onToggle={handleHideInSearch}
|
|
627
|
-
/>
|
|
628
|
-
) : null}
|
|
629
|
-
</div>
|
|
630
|
-
</div>
|
|
631
|
-
</div>
|
|
594
|
+
) : null}
|
|
595
|
+
</ShareGeneralAccessRow>
|
|
632
596
|
</div>
|
|
633
597
|
|
|
634
598
|
<div className={cn("mb-3 space-y-3", props.agentTabContent && "order-1")}>
|
|
@@ -638,134 +602,12 @@ function SharePanel(
|
|
|
638
602
|
<div className={SHARE_SECTION_LABEL}>{peopleAccessLabel}</div>
|
|
639
603
|
</>
|
|
640
604
|
) : null}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
onOpenChange={(open) => {
|
|
648
|
-
if (!props.basicSharingOnly) setSuggestionsOpen(open);
|
|
649
|
-
}}
|
|
650
|
-
onValueChange={(next) => {
|
|
651
|
-
onInviteEmailChange(next);
|
|
652
|
-
if (shareError) setShareError(null);
|
|
653
|
-
}}
|
|
654
|
-
onSelectSuggestion={(suggestion) => {
|
|
655
|
-
if (suggestion.principalType === "group") {
|
|
656
|
-
selectGroup(suggestion);
|
|
657
|
-
} else {
|
|
658
|
-
onInviteEmailChange(suggestion.email);
|
|
659
|
-
}
|
|
660
|
-
setSuggestionsOpen(false);
|
|
661
|
-
if (shareError) setShareError(null);
|
|
662
|
-
}}
|
|
663
|
-
onSubmit={handleAdd}
|
|
664
|
-
placeholder={
|
|
665
|
-
policy.requireOrgMemberForUserShares
|
|
666
|
-
? t("agentChat.share.addPeopleOrganization", {
|
|
667
|
-
defaultValue: "Add people from your organization",
|
|
668
|
-
})
|
|
669
|
-
: t("agentChat.share.addPeopleEmail", {
|
|
670
|
-
defaultValue: policy.supportsGroupShares
|
|
671
|
-
? "Add people or groups"
|
|
672
|
-
: "Add people by email",
|
|
673
|
-
})
|
|
674
|
-
}
|
|
675
|
-
suggestions={[
|
|
676
|
-
...memberSuggestions.map((member) => ({
|
|
677
|
-
...member,
|
|
678
|
-
principalType: "user" as const,
|
|
679
|
-
})),
|
|
680
|
-
...(policy.supportsGroupShares
|
|
681
|
-
? groupSuggestions.map((group) => ({
|
|
682
|
-
...group,
|
|
683
|
-
principalType: "group" as const,
|
|
684
|
-
}))
|
|
685
|
-
: []),
|
|
686
|
-
]}
|
|
687
|
-
search={memberSearch}
|
|
688
|
-
trailing={
|
|
689
|
-
<RoleSelect
|
|
690
|
-
value={role}
|
|
691
|
-
onChange={setRole}
|
|
692
|
-
roleCopy={props.roleCopy}
|
|
693
|
-
allowedRoles={allowedRolesFor(props)}
|
|
694
|
-
/>
|
|
695
|
-
}
|
|
696
|
-
/>
|
|
697
|
-
<button
|
|
698
|
-
type="button"
|
|
699
|
-
onClick={handleAdd}
|
|
700
|
-
disabled={!hasInviteEmail}
|
|
701
|
-
aria-label={t("agentChat.share.add", { defaultValue: "Add" })}
|
|
702
|
-
title={t("agentChat.share.add", { defaultValue: "Add" })}
|
|
703
|
-
className={BUTTON_PRIMARY_ICON}
|
|
704
|
-
>
|
|
705
|
-
<IconSend2 />
|
|
706
|
-
</button>
|
|
707
|
-
</div>
|
|
708
|
-
{shareError ? (
|
|
709
|
-
<div
|
|
710
|
-
role="alert"
|
|
711
|
-
className="rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive"
|
|
712
|
-
>
|
|
713
|
-
{shareError}
|
|
714
|
-
</div>
|
|
715
|
-
) : null}
|
|
716
|
-
{hasInviteEmail ? (
|
|
717
|
-
<div className="flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground">
|
|
718
|
-
<label className="inline-flex items-center gap-2">
|
|
719
|
-
<input
|
|
720
|
-
type="checkbox"
|
|
721
|
-
checked={notifyPeople}
|
|
722
|
-
onChange={(e) => setNotifyPeople(e.target.checked)}
|
|
723
|
-
className="h-4 w-4 rounded border-input accent-primary"
|
|
724
|
-
/>
|
|
725
|
-
{t("agentChat.share.notifyPeople", {
|
|
726
|
-
defaultValue: "Notify people",
|
|
727
|
-
})}
|
|
728
|
-
</label>
|
|
729
|
-
{notifyPeople && !props.basicSharingOnly ? (
|
|
730
|
-
<button
|
|
731
|
-
type="button"
|
|
732
|
-
aria-expanded={messageOpen}
|
|
733
|
-
onClick={() => setMessageOpen(!messageOpen)}
|
|
734
|
-
className="rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground"
|
|
735
|
-
>
|
|
736
|
-
{messageOpen
|
|
737
|
-
? t("agentChat.share.hideMessage", {
|
|
738
|
-
defaultValue: "Hide message",
|
|
739
|
-
})
|
|
740
|
-
: t("agentChat.share.addMessage", {
|
|
741
|
-
defaultValue: "Add a message",
|
|
742
|
-
})}
|
|
743
|
-
</button>
|
|
744
|
-
) : null}
|
|
745
|
-
</div>
|
|
746
|
-
) : null}
|
|
747
|
-
{hasInviteEmail &&
|
|
748
|
-
notifyPeople &&
|
|
749
|
-
messageOpen &&
|
|
750
|
-
!props.basicSharingOnly ? (
|
|
751
|
-
<div className="rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
752
|
-
<textarea
|
|
753
|
-
aria-label={t("agentChat.share.message", {
|
|
754
|
-
defaultValue: "Message",
|
|
755
|
-
})}
|
|
756
|
-
placeholder={t("agentChat.share.messagePlaceholder", {
|
|
757
|
-
defaultValue: "Add a short note (optional)",
|
|
758
|
-
})}
|
|
759
|
-
value={shareMessage}
|
|
760
|
-
onChange={(event) => setShareMessage(event.target.value)}
|
|
761
|
-
maxLength={500}
|
|
762
|
-
rows={3}
|
|
763
|
-
className="w-full resize-y rounded-md border border-input bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background"
|
|
764
|
-
/>
|
|
765
|
-
</div>
|
|
766
|
-
) : null}
|
|
767
|
-
</div>
|
|
768
|
-
) : null}
|
|
605
|
+
<SharePeopleInvite
|
|
606
|
+
controller={controller}
|
|
607
|
+
basicSharingOnly={props.basicSharingOnly}
|
|
608
|
+
roleCopy={props.roleCopy}
|
|
609
|
+
allowedRoles={allowedRolesFor(props)}
|
|
610
|
+
/>
|
|
769
611
|
|
|
770
612
|
{props.agentTabContent ? (
|
|
771
613
|
<>
|
|
@@ -773,81 +615,11 @@ function SharePanel(
|
|
|
773
615
|
<div className={SHARE_SECTION_LABEL}>{peopleAccessLabel}</div>
|
|
774
616
|
</>
|
|
775
617
|
) : null}
|
|
776
|
-
<
|
|
777
|
-
{
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
image={memberImage(data.ownerEmail, knownMembers)}
|
|
782
|
-
label={displayName(data.ownerEmail, knownMembers, t)}
|
|
783
|
-
/>
|
|
784
|
-
<span className="flex-1 min-w-0 truncate">
|
|
785
|
-
{displayName(data.ownerEmail, knownMembers, t)}
|
|
786
|
-
</span>
|
|
787
|
-
<span className="text-xs text-muted-foreground">
|
|
788
|
-
{t("agentChat.share.owner", { defaultValue: "Owner" })}
|
|
789
|
-
</span>
|
|
790
|
-
</li>
|
|
791
|
-
) : null}
|
|
792
|
-
{shares.map((s) => (
|
|
793
|
-
<li
|
|
794
|
-
key={keyOf(s)}
|
|
795
|
-
className={cn(
|
|
796
|
-
"flex min-h-8 items-center gap-2 px-1.5 py-1 text-sm",
|
|
797
|
-
inFlight.has(keyOf(s)) && "opacity-60",
|
|
798
|
-
)}
|
|
799
|
-
>
|
|
800
|
-
<Avatar
|
|
801
|
-
email={s.principalType === "user" ? s.principalId : undefined}
|
|
802
|
-
image={
|
|
803
|
-
s.principalType === "user"
|
|
804
|
-
? memberImage(s.principalId, knownMembers)
|
|
805
|
-
: undefined
|
|
806
|
-
}
|
|
807
|
-
label={principalLabel(s, knownMembers, t)}
|
|
808
|
-
org={s.principalType === "org"}
|
|
809
|
-
group={s.principalType === "group"}
|
|
810
|
-
/>
|
|
811
|
-
<span className="flex-1 min-w-0 truncate">
|
|
812
|
-
{principalLabel(s, knownMembers, t)}
|
|
813
|
-
</span>
|
|
814
|
-
{canManage ? (
|
|
815
|
-
<RoleSelect
|
|
816
|
-
value={s.role}
|
|
817
|
-
onChange={(r) => handleChangeRole(s, r)}
|
|
818
|
-
disabled={inFlight.has(keyOf(s))}
|
|
819
|
-
plain
|
|
820
|
-
roleCopy={props.roleCopy}
|
|
821
|
-
allowedRoles={allowedRolesFor(props)}
|
|
822
|
-
/>
|
|
823
|
-
) : (
|
|
824
|
-
<span className="text-xs text-muted-foreground">
|
|
825
|
-
{roleMeta(s.role, t, props.roleCopy).label}
|
|
826
|
-
</span>
|
|
827
|
-
)}
|
|
828
|
-
{canManage ? (
|
|
829
|
-
<button
|
|
830
|
-
type="button"
|
|
831
|
-
aria-label={t("agentChat.share.remove", {
|
|
832
|
-
defaultValue: "Remove",
|
|
833
|
-
})}
|
|
834
|
-
onClick={() => handleRemove(s)}
|
|
835
|
-
disabled={inFlight.has(keyOf(s))}
|
|
836
|
-
className={BUTTON_GHOST_ICON}
|
|
837
|
-
>
|
|
838
|
-
<IconTrash size={14} />
|
|
839
|
-
</button>
|
|
840
|
-
) : null}
|
|
841
|
-
</li>
|
|
842
|
-
))}
|
|
843
|
-
{!shares.length && !data?.ownerEmail ? (
|
|
844
|
-
<li className="px-1.5 py-1 text-sm text-muted-foreground">
|
|
845
|
-
{t("agentChat.share.noAccess", {
|
|
846
|
-
defaultValue: "No one has access yet.",
|
|
847
|
-
})}
|
|
848
|
-
</li>
|
|
849
|
-
) : null}
|
|
850
|
-
</ul>
|
|
618
|
+
<SharePeopleList
|
|
619
|
+
controller={controller}
|
|
620
|
+
roleCopy={props.roleCopy}
|
|
621
|
+
allowedRoles={allowedRolesFor(props)}
|
|
622
|
+
/>
|
|
851
623
|
</div>
|
|
852
624
|
|
|
853
625
|
{shareError && !canManage ? (
|
|
@@ -969,6 +741,282 @@ function SharePanel(
|
|
|
969
741
|
);
|
|
970
742
|
}
|
|
971
743
|
|
|
744
|
+
export interface SharePeopleControlProps {
|
|
745
|
+
controller: ShareButtonController;
|
|
746
|
+
roleCopy?: ShareButtonProps["roleCopy"];
|
|
747
|
+
allowedRoles?: readonly ShareButtonRole[];
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* The add-people field (member and group suggestions, role, notify and
|
|
752
|
+
* message) of the share panel. Renders nothing unless the user can manage
|
|
753
|
+
* access. Apps that compose their own sharing surface reuse it with
|
|
754
|
+
* `useShareButtonController`, next to `ShareGeneralAccessRow` and
|
|
755
|
+
* `SharePeopleList`.
|
|
756
|
+
*/
|
|
757
|
+
export function SharePeopleInvite({
|
|
758
|
+
controller,
|
|
759
|
+
basicSharingOnly,
|
|
760
|
+
roleCopy,
|
|
761
|
+
allowedRoles,
|
|
762
|
+
}: SharePeopleControlProps & { basicSharingOnly?: boolean }) {
|
|
763
|
+
const t = useT();
|
|
764
|
+
const {
|
|
765
|
+
inviteEmail,
|
|
766
|
+
setInviteEmail: onInviteEmailChange,
|
|
767
|
+
policy,
|
|
768
|
+
canManage,
|
|
769
|
+
role,
|
|
770
|
+
setRole,
|
|
771
|
+
notifyPeople,
|
|
772
|
+
setNotifyPeople,
|
|
773
|
+
shareMessage,
|
|
774
|
+
setShareMessage,
|
|
775
|
+
messageOpen,
|
|
776
|
+
setMessageOpen,
|
|
777
|
+
shareError,
|
|
778
|
+
setShareError,
|
|
779
|
+
suggestionsOpen,
|
|
780
|
+
setSuggestionsOpen,
|
|
781
|
+
memberSearch,
|
|
782
|
+
memberSuggestions,
|
|
783
|
+
groupSuggestions,
|
|
784
|
+
selectGroup,
|
|
785
|
+
handleAdd,
|
|
786
|
+
} = controller;
|
|
787
|
+
const hasInviteEmail = inviteEmail.trim().length > 0;
|
|
788
|
+
return (
|
|
789
|
+
<>
|
|
790
|
+
{canManage ? (
|
|
791
|
+
<div className="space-y-2">
|
|
792
|
+
<div className="flex items-stretch gap-1.5">
|
|
793
|
+
<MemberAutocomplete
|
|
794
|
+
value={inviteEmail}
|
|
795
|
+
open={suggestionsOpen && !basicSharingOnly}
|
|
796
|
+
onOpenChange={(open) => {
|
|
797
|
+
if (!basicSharingOnly) setSuggestionsOpen(open);
|
|
798
|
+
}}
|
|
799
|
+
onValueChange={(next) => {
|
|
800
|
+
onInviteEmailChange(next);
|
|
801
|
+
if (shareError) setShareError(null);
|
|
802
|
+
}}
|
|
803
|
+
onSelectSuggestion={(suggestion) => {
|
|
804
|
+
if (suggestion.principalType === "group") {
|
|
805
|
+
selectGroup(suggestion);
|
|
806
|
+
} else {
|
|
807
|
+
onInviteEmailChange(suggestion.email);
|
|
808
|
+
}
|
|
809
|
+
setSuggestionsOpen(false);
|
|
810
|
+
if (shareError) setShareError(null);
|
|
811
|
+
}}
|
|
812
|
+
onSubmit={handleAdd}
|
|
813
|
+
placeholder={
|
|
814
|
+
policy.requireOrgMemberForUserShares
|
|
815
|
+
? t("agentChat.share.addPeopleOrganization", {
|
|
816
|
+
defaultValue: "Add people from your organization",
|
|
817
|
+
})
|
|
818
|
+
: t("agentChat.share.addPeopleEmail", {
|
|
819
|
+
defaultValue: policy.supportsGroupShares
|
|
820
|
+
? "Add people or groups"
|
|
821
|
+
: "Add people by email",
|
|
822
|
+
})
|
|
823
|
+
}
|
|
824
|
+
suggestions={[
|
|
825
|
+
...memberSuggestions.map((member) => ({
|
|
826
|
+
...member,
|
|
827
|
+
principalType: "user" as const,
|
|
828
|
+
})),
|
|
829
|
+
...(policy.supportsGroupShares
|
|
830
|
+
? groupSuggestions.map((group) => ({
|
|
831
|
+
...group,
|
|
832
|
+
principalType: "group" as const,
|
|
833
|
+
}))
|
|
834
|
+
: []),
|
|
835
|
+
]}
|
|
836
|
+
search={memberSearch}
|
|
837
|
+
trailing={
|
|
838
|
+
<RoleSelect
|
|
839
|
+
value={role}
|
|
840
|
+
onChange={setRole}
|
|
841
|
+
roleCopy={roleCopy}
|
|
842
|
+
allowedRoles={allowedRoles}
|
|
843
|
+
/>
|
|
844
|
+
}
|
|
845
|
+
/>
|
|
846
|
+
<button
|
|
847
|
+
type="button"
|
|
848
|
+
onClick={handleAdd}
|
|
849
|
+
disabled={!hasInviteEmail}
|
|
850
|
+
aria-label={t("agentChat.share.add", { defaultValue: "Add" })}
|
|
851
|
+
title={t("agentChat.share.add", { defaultValue: "Add" })}
|
|
852
|
+
className={BUTTON_PRIMARY_ICON}
|
|
853
|
+
>
|
|
854
|
+
<IconSend2 />
|
|
855
|
+
</button>
|
|
856
|
+
</div>
|
|
857
|
+
{shareError ? (
|
|
858
|
+
<div
|
|
859
|
+
role="alert"
|
|
860
|
+
className="rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive"
|
|
861
|
+
>
|
|
862
|
+
{shareError}
|
|
863
|
+
</div>
|
|
864
|
+
) : null}
|
|
865
|
+
{hasInviteEmail ? (
|
|
866
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground">
|
|
867
|
+
<label className="inline-flex items-center gap-2">
|
|
868
|
+
<input
|
|
869
|
+
type="checkbox"
|
|
870
|
+
checked={notifyPeople}
|
|
871
|
+
onChange={(e) => setNotifyPeople(e.target.checked)}
|
|
872
|
+
className="h-4 w-4 rounded border-input accent-primary"
|
|
873
|
+
/>
|
|
874
|
+
{t("agentChat.share.notifyPeople", {
|
|
875
|
+
defaultValue: "Notify people",
|
|
876
|
+
})}
|
|
877
|
+
</label>
|
|
878
|
+
{notifyPeople && !basicSharingOnly ? (
|
|
879
|
+
<button
|
|
880
|
+
type="button"
|
|
881
|
+
aria-expanded={messageOpen}
|
|
882
|
+
onClick={() => setMessageOpen(!messageOpen)}
|
|
883
|
+
className="rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground"
|
|
884
|
+
>
|
|
885
|
+
{messageOpen
|
|
886
|
+
? t("agentChat.share.hideMessage", {
|
|
887
|
+
defaultValue: "Hide message",
|
|
888
|
+
})
|
|
889
|
+
: t("agentChat.share.addMessage", {
|
|
890
|
+
defaultValue: "Add a message",
|
|
891
|
+
})}
|
|
892
|
+
</button>
|
|
893
|
+
) : null}
|
|
894
|
+
</div>
|
|
895
|
+
) : null}
|
|
896
|
+
{hasInviteEmail &&
|
|
897
|
+
notifyPeople &&
|
|
898
|
+
messageOpen &&
|
|
899
|
+
!basicSharingOnly ? (
|
|
900
|
+
<div className="rounded-md border border-border/70 bg-muted/20 p-2.5">
|
|
901
|
+
<textarea
|
|
902
|
+
aria-label={t("agentChat.share.message", {
|
|
903
|
+
defaultValue: "Message",
|
|
904
|
+
})}
|
|
905
|
+
placeholder={t("agentChat.share.messagePlaceholder", {
|
|
906
|
+
defaultValue: "Add a short note (optional)",
|
|
907
|
+
})}
|
|
908
|
+
value={shareMessage}
|
|
909
|
+
onChange={(event) => setShareMessage(event.target.value)}
|
|
910
|
+
maxLength={500}
|
|
911
|
+
rows={3}
|
|
912
|
+
className="w-full resize-y rounded-md border border-input bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background"
|
|
913
|
+
/>
|
|
914
|
+
</div>
|
|
915
|
+
) : null}
|
|
916
|
+
</div>
|
|
917
|
+
) : null}
|
|
918
|
+
</>
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* The owner and the people who have access, with role pickers and remove
|
|
924
|
+
* buttons for managers.
|
|
925
|
+
*/
|
|
926
|
+
export function SharePeopleList({
|
|
927
|
+
controller,
|
|
928
|
+
roleCopy,
|
|
929
|
+
allowedRoles,
|
|
930
|
+
}: SharePeopleControlProps) {
|
|
931
|
+
const t = useT();
|
|
932
|
+
const {
|
|
933
|
+
data,
|
|
934
|
+
canManage,
|
|
935
|
+
inFlight,
|
|
936
|
+
knownMembers,
|
|
937
|
+
shares,
|
|
938
|
+
handleChangeRole,
|
|
939
|
+
handleRemove,
|
|
940
|
+
} = controller;
|
|
941
|
+
return (
|
|
942
|
+
<ul className="flex list-none flex-col gap-1 p-0 m-0">
|
|
943
|
+
{data?.ownerEmail ? (
|
|
944
|
+
<li className="flex min-h-8 items-center gap-2 px-1.5 py-1 text-sm">
|
|
945
|
+
<Avatar
|
|
946
|
+
email={data.ownerEmail}
|
|
947
|
+
image={memberImage(data.ownerEmail, knownMembers)}
|
|
948
|
+
label={displayName(data.ownerEmail, knownMembers, t)}
|
|
949
|
+
/>
|
|
950
|
+
<span className="flex-1 min-w-0 truncate">
|
|
951
|
+
{displayName(data.ownerEmail, knownMembers, t)}
|
|
952
|
+
</span>
|
|
953
|
+
<span className="text-xs text-muted-foreground">
|
|
954
|
+
{t("agentChat.share.owner", { defaultValue: "Owner" })}
|
|
955
|
+
</span>
|
|
956
|
+
</li>
|
|
957
|
+
) : null}
|
|
958
|
+
{shares.map((s) => (
|
|
959
|
+
<li
|
|
960
|
+
key={keyOf(s)}
|
|
961
|
+
className={cn(
|
|
962
|
+
"flex min-h-8 items-center gap-2 px-1.5 py-1 text-sm",
|
|
963
|
+
inFlight.has(keyOf(s)) && "opacity-60",
|
|
964
|
+
)}
|
|
965
|
+
>
|
|
966
|
+
<Avatar
|
|
967
|
+
email={s.principalType === "user" ? s.principalId : undefined}
|
|
968
|
+
image={
|
|
969
|
+
s.principalType === "user"
|
|
970
|
+
? memberImage(s.principalId, knownMembers)
|
|
971
|
+
: undefined
|
|
972
|
+
}
|
|
973
|
+
label={principalLabel(s, knownMembers, t)}
|
|
974
|
+
org={s.principalType === "org"}
|
|
975
|
+
group={s.principalType === "group"}
|
|
976
|
+
/>
|
|
977
|
+
<span className="flex-1 min-w-0 truncate">
|
|
978
|
+
{principalLabel(s, knownMembers, t)}
|
|
979
|
+
</span>
|
|
980
|
+
{canManage ? (
|
|
981
|
+
<RoleSelect
|
|
982
|
+
value={s.role}
|
|
983
|
+
onChange={(r) => handleChangeRole(s, r)}
|
|
984
|
+
disabled={inFlight.has(keyOf(s))}
|
|
985
|
+
plain
|
|
986
|
+
roleCopy={roleCopy}
|
|
987
|
+
allowedRoles={allowedRoles}
|
|
988
|
+
/>
|
|
989
|
+
) : (
|
|
990
|
+
<span className="text-xs text-muted-foreground">
|
|
991
|
+
{roleMeta(s.role, t, roleCopy).label}
|
|
992
|
+
</span>
|
|
993
|
+
)}
|
|
994
|
+
{canManage ? (
|
|
995
|
+
<button
|
|
996
|
+
type="button"
|
|
997
|
+
aria-label={t("agentChat.share.remove", {
|
|
998
|
+
defaultValue: "Remove",
|
|
999
|
+
})}
|
|
1000
|
+
onClick={() => handleRemove(s)}
|
|
1001
|
+
disabled={inFlight.has(keyOf(s))}
|
|
1002
|
+
className={BUTTON_GHOST_ICON}
|
|
1003
|
+
>
|
|
1004
|
+
<IconTrash size={14} />
|
|
1005
|
+
</button>
|
|
1006
|
+
) : null}
|
|
1007
|
+
</li>
|
|
1008
|
+
))}
|
|
1009
|
+
{!shares.length && !data?.ownerEmail ? (
|
|
1010
|
+
<li className="px-1.5 py-1 text-sm text-muted-foreground">
|
|
1011
|
+
{t("agentChat.share.noAccess", {
|
|
1012
|
+
defaultValue: "No one has access yet.",
|
|
1013
|
+
})}
|
|
1014
|
+
</li>
|
|
1015
|
+
) : null}
|
|
1016
|
+
</ul>
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
972
1020
|
function AdvancedAccessPopover({
|
|
973
1021
|
control,
|
|
974
1022
|
canManage,
|
|
@@ -1495,6 +1543,76 @@ function RoleSelect(props: {
|
|
|
1495
1543
|
);
|
|
1496
1544
|
}
|
|
1497
1545
|
|
|
1546
|
+
export interface ShareGeneralAccessRowProps {
|
|
1547
|
+
controller: Pick<
|
|
1548
|
+
ShareButtonController,
|
|
1549
|
+
| "visibility"
|
|
1550
|
+
| "canManage"
|
|
1551
|
+
| "policy"
|
|
1552
|
+
| "handleVisibility"
|
|
1553
|
+
| "visibilityTransition"
|
|
1554
|
+
>;
|
|
1555
|
+
visibilityCopy?: ShareButtonProps["visibilityCopy"];
|
|
1556
|
+
/** Show the description in the trigger instead of the label. */
|
|
1557
|
+
sentenceTrigger?: boolean;
|
|
1558
|
+
/** Resource-specific text added to the organization confirmation. */
|
|
1559
|
+
confirmDetail?: ReactNode;
|
|
1560
|
+
/** Shown beside the access control, such as an advanced-access popover. */
|
|
1561
|
+
children?: ReactNode;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/**
|
|
1565
|
+
* The "general access" control of the share panel: the visibility picker and
|
|
1566
|
+
* the confirmation shown before a resource opens to the organization. Apps
|
|
1567
|
+
* that compose their own sharing surface (Clips) reuse it with
|
|
1568
|
+
* `useShareButtonController` so the confirmation stays the same everywhere.
|
|
1569
|
+
*/
|
|
1570
|
+
export function ShareGeneralAccessRow({
|
|
1571
|
+
controller,
|
|
1572
|
+
visibilityCopy,
|
|
1573
|
+
sentenceTrigger,
|
|
1574
|
+
confirmDetail,
|
|
1575
|
+
children,
|
|
1576
|
+
}: ShareGeneralAccessRowProps) {
|
|
1577
|
+
const t = useT();
|
|
1578
|
+
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
1579
|
+
const meta = visibilityMeta(controller.visibility, t, visibilityCopy);
|
|
1580
|
+
return (
|
|
1581
|
+
<div className="flex items-center gap-2">
|
|
1582
|
+
<span
|
|
1583
|
+
aria-hidden
|
|
1584
|
+
className="inline-flex size-6 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground"
|
|
1585
|
+
>
|
|
1586
|
+
<meta.Icon size={12} strokeWidth={1.75} />
|
|
1587
|
+
</span>
|
|
1588
|
+
<div className="min-w-0 flex-1">
|
|
1589
|
+
<VisibilitySelect
|
|
1590
|
+
value={controller.visibility}
|
|
1591
|
+
onChange={controller.handleVisibility}
|
|
1592
|
+
disabled={
|
|
1593
|
+
!controller.canManage || controller.visibilityTransition.submitting
|
|
1594
|
+
}
|
|
1595
|
+
sentenceTrigger={sentenceTrigger}
|
|
1596
|
+
visibilityCopy={visibilityCopy}
|
|
1597
|
+
allowPublic={controller.policy.allowPublic}
|
|
1598
|
+
triggerRef={triggerRef}
|
|
1599
|
+
/>
|
|
1600
|
+
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground">
|
|
1601
|
+
{!sentenceTrigger ? (
|
|
1602
|
+
<span className="sr-only">{meta.description}</span>
|
|
1603
|
+
) : null}
|
|
1604
|
+
{children}
|
|
1605
|
+
</div>
|
|
1606
|
+
</div>
|
|
1607
|
+
<ShareVisibilityConfirmDialog
|
|
1608
|
+
transition={controller.visibilityTransition}
|
|
1609
|
+
detail={confirmDetail}
|
|
1610
|
+
returnFocusRef={triggerRef}
|
|
1611
|
+
/>
|
|
1612
|
+
</div>
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1498
1616
|
function VisibilitySelect(props: {
|
|
1499
1617
|
value: Visibility;
|
|
1500
1618
|
onChange: (v: Visibility) => void;
|
|
@@ -1503,6 +1621,7 @@ function VisibilitySelect(props: {
|
|
|
1503
1621
|
visibilityCopy?: ShareButtonProps["visibilityCopy"];
|
|
1504
1622
|
allowPrivate?: boolean;
|
|
1505
1623
|
allowPublic?: boolean;
|
|
1624
|
+
triggerRef?: Ref<HTMLButtonElement>;
|
|
1506
1625
|
}) {
|
|
1507
1626
|
const t = useT();
|
|
1508
1627
|
const allowPrivate = props.allowPrivate !== false;
|
|
@@ -1521,6 +1640,7 @@ function VisibilitySelect(props: {
|
|
|
1521
1640
|
disabled={props.disabled}
|
|
1522
1641
|
>
|
|
1523
1642
|
<Select.Trigger
|
|
1643
|
+
ref={props.triggerRef}
|
|
1524
1644
|
className={cn(
|
|
1525
1645
|
BUTTON_BASE,
|
|
1526
1646
|
"h-7 px-1 -ms-1 bg-transparent font-normal text-foreground hover:bg-accent hover:text-accent-foreground",
|
|
@@ -1543,6 +1663,11 @@ function VisibilitySelect(props: {
|
|
|
1543
1663
|
className={selectContentClass}
|
|
1544
1664
|
position="popper"
|
|
1545
1665
|
sideOffset={4}
|
|
1666
|
+
// Runs after the item has selected. Enter may open a confirmation
|
|
1667
|
+
// that takes focus; its keypress must not land on the button there.
|
|
1668
|
+
onKeyDown={(event) => {
|
|
1669
|
+
if (event.key === "Enter") event.preventDefault();
|
|
1670
|
+
}}
|
|
1546
1671
|
>
|
|
1547
1672
|
<Select.Viewport>
|
|
1548
1673
|
<SelectItems
|