@agent-native/core 0.162.0 → 0.163.1
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/sharing/SKILL.md +27 -2
- package/corpus/templates/analytics/server/plugins/collab.ts +1 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/content/actions/create-content-database.ts +1 -1
- package/corpus/templates/content/actions/create-document.ts +1 -1
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/DEVELOPING.md +17 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +67 -0
- package/corpus/templates/slides/actions/request-deck-access.ts +569 -0
- package/corpus/templates/slides/agent-native.json +3 -0
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +51 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +12 -0
- package/corpus/templates/slides/app/lib/deck-editor-loading.ts +7 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +173 -33
- package/corpus/templates/slides/changelog/2026-08-18-private-deck-links-now-explain-access-and-let-viewers-notify.md +6 -0
- package/corpus/templates/slides/server/db/schema.ts +10 -0
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
- package/corpus/templates/slides/server/plugins/db.ts +17 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/app-config/workspace.d.ts +1 -0
- package/dist/app-config/workspace.js +8 -0
- package/dist/chat-threads/schema.d.ts +2 -2
- package/dist/client/analytics.d.ts +1 -0
- package/dist/client/analytics.js +19 -5
- package/dist/client/org/TeamPage.js +15 -2
- package/dist/client/org/hooks.d.ts +2 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/org/index.d.ts +2 -2
- package/dist/client/org/index.js +1 -1
- package/dist/client/sharing/ShareButton.js +43 -18
- package/dist/client/sharing/useShareButtonController.d.ts +12 -2
- package/dist/client/sharing/useShareButtonController.js +38 -8
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +2 -0
- package/dist/collab/storage.js +7 -0
- package/dist/config.js +11 -1
- package/dist/dashboard-storage/schema.d.ts +2 -2
- package/dist/data-programs/schema.d.ts +2 -2
- package/dist/deploy/build.d.ts +1 -1
- package/dist/deploy/build.js +89 -12
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/extensions/store.js +3 -0
- package/dist/localization/core-messages/ar-SA.js +1 -0
- package/dist/localization/core-messages/de-DE.js +1 -0
- package/dist/localization/core-messages/en-US.d.ts +1 -0
- package/dist/localization/core-messages/en-US.js +1 -0
- package/dist/localization/core-messages/es-ES.js +1 -0
- package/dist/localization/core-messages/fr-FR.js +1 -0
- package/dist/localization/core-messages/hi-IN.js +1 -0
- package/dist/localization/core-messages/ja-JP.js +1 -0
- package/dist/localization/core-messages/ko-KR.js +1 -0
- package/dist/localization/core-messages/pt-BR.js +1 -0
- package/dist/localization/core-messages/zh-CN.js +1 -0
- package/dist/localization/core-messages/zh-TW.js +1 -0
- package/dist/localization/core-messages.d.ts +1 -0
- package/dist/localization/default-messages.d.ts +4 -0
- package/dist/localization/default-messages.js +4 -0
- package/dist/observability/routes.d.ts +1 -1
- package/dist/observability/tracking-identity.js +2 -0
- package/dist/org/handlers.d.ts +6 -1
- package/dist/org/handlers.js +43 -0
- package/dist/org/index.d.ts +3 -3
- package/dist/org/index.js +2 -2
- package/dist/org/migrations.js +33 -0
- package/dist/org/plugin.js +10 -1
- package/dist/org/schema.d.ts +315 -0
- package/dist/org/schema.js +20 -1
- package/dist/org/types.d.ts +3 -0
- package/dist/org/workspace-app-access.d.ts +10 -0
- package/dist/org/workspace-app-access.js +179 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +14 -1
- package/dist/server/collab-plugin.d.ts +6 -0
- package/dist/server/collab-plugin.js +27 -6
- package/dist/server/deploy-environment.d.ts +1 -1
- package/dist/server/deploy-environment.js +40 -2
- package/dist/server/poll.js +6 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/sentry-config.js +8 -4
- package/dist/server/sentry.js +4 -0
- package/dist/sharing/access.d.ts +2 -2
- package/dist/sharing/access.js +56 -3
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +26 -1
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +23 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/actions/unshare-resource.js +1 -1
- package/dist/sharing/registry.d.ts +12 -0
- package/dist/sharing/schema.d.ts +4 -4
- package/dist/sharing/schema.js +2 -2
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/tracking/registry.js +8 -6
- package/dist/vite/client.js +5 -0
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
- package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
- package/dist/workspace-connections/groups.d.ts +2 -0
- package/dist/workspace-connections/groups.js +16 -5
- package/docs/content/deployment.mdx +19 -5
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
package/dist/client/analytics.js
CHANGED
|
@@ -3,6 +3,7 @@ import { llmConnectionTrackingProperties, } from "../shared/llm-connection.js";
|
|
|
3
3
|
import { toPostHogExceptionProperties } from "../tracking/posthog-exception.js";
|
|
4
4
|
import { getAnalyticsClientPlatform } from "./analytics-platform.js";
|
|
5
5
|
import { getOrCreateAnalyticsAnonymousId, getOrCreateAnalyticsSessionId, } from "./analytics-session.js";
|
|
6
|
+
import { injectedAgentNativeConfig } from "./app-config.js";
|
|
6
7
|
export { clearAnalyticsSessionId, setAnalyticsSessionId, } from "./analytics-session.js";
|
|
7
8
|
import { fetchAgentEngineStatus, fetchAuthSessionStatus, } from "./client-status-requests.js";
|
|
8
9
|
import { installErrorCapture, } from "./error-capture.js";
|
|
@@ -681,6 +682,16 @@ function getClientSentryDsn() {
|
|
|
681
682
|
window.__AGENT_NATIVE_CONFIG__?.sentryDsn ||
|
|
682
683
|
resolveClientSentryDsnFromKeyProject(env));
|
|
683
684
|
}
|
|
685
|
+
function resolveClientDeploymentEnvironment() {
|
|
686
|
+
const env = import.meta.env ?? {};
|
|
687
|
+
return (window.__AGENT_NATIVE_CONFIG__?.deploymentEnvironment ||
|
|
688
|
+
injectedAgentNativeConfig().deployment?.environment ||
|
|
689
|
+
env.VITE_AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT ||
|
|
690
|
+
env.VITE_SENTRY_ENVIRONMENT ||
|
|
691
|
+
window.__AGENT_NATIVE_CONFIG__?.sentryEnvironment ||
|
|
692
|
+
env.MODE ||
|
|
693
|
+
"production");
|
|
694
|
+
}
|
|
684
695
|
function captureWithSentry(module, error, context) {
|
|
685
696
|
return module.withScope((scope) => {
|
|
686
697
|
if (context.tags) {
|
|
@@ -721,10 +732,12 @@ function ensureSentry(loadWithoutDsn = false) {
|
|
|
721
732
|
}
|
|
722
733
|
module.init({
|
|
723
734
|
dsn,
|
|
724
|
-
environment:
|
|
725
|
-
import.meta.env?.MODE ||
|
|
726
|
-
"production",
|
|
735
|
+
environment: resolveClientDeploymentEnvironment(),
|
|
727
736
|
beforeSend(event) {
|
|
737
|
+
event.tags = {
|
|
738
|
+
...event.tags,
|
|
739
|
+
deployment_environment: resolveClientDeploymentEnvironment(),
|
|
740
|
+
};
|
|
728
741
|
if (shouldDropBrowserSentryNoise(event)) {
|
|
729
742
|
return null;
|
|
730
743
|
}
|
|
@@ -756,6 +769,7 @@ function ensureSentry(loadWithoutDsn = false) {
|
|
|
756
769
|
},
|
|
757
770
|
});
|
|
758
771
|
module.setTag("runtime", "browser");
|
|
772
|
+
module.setTag("deployment_environment", resolveClientDeploymentEnvironment());
|
|
759
773
|
_sentryInitialized = true;
|
|
760
774
|
// Flush any user/tag that was set before init.
|
|
761
775
|
if (_pendingSentryUser !== undefined) {
|
|
@@ -1169,8 +1183,7 @@ function maybeInstallErrorCapture(config) {
|
|
|
1169
1183
|
send: sendExceptionEvent,
|
|
1170
1184
|
getSessionContext: errorCaptureSessionContext,
|
|
1171
1185
|
emitReplayEvent: emitExceptionToReplay,
|
|
1172
|
-
environment: options.environment ||
|
|
1173
|
-
import.meta.env?.MODE,
|
|
1186
|
+
environment: options.environment || resolveClientDeploymentEnvironment(),
|
|
1174
1187
|
...(options.release ? { release: options.release } : {}),
|
|
1175
1188
|
...(options.captureGlobalErrors !== undefined
|
|
1176
1189
|
? { captureGlobalErrors: options.captureGlobalErrors }
|
|
@@ -1410,6 +1423,7 @@ function resolveProps(name, params) {
|
|
|
1410
1423
|
}
|
|
1411
1424
|
const llmProps = llmConnectionTrackingProperties(_llmConnectionStatus);
|
|
1412
1425
|
const enriched = { ...withTemplate };
|
|
1426
|
+
enriched.deployment_environment = resolveClientDeploymentEnvironment();
|
|
1413
1427
|
for (const [key, value] of Object.entries(llmProps)) {
|
|
1414
1428
|
if (enriched[key] === undefined)
|
|
1415
1429
|
enriched[key] = value;
|
|
@@ -19,7 +19,7 @@ import { SettingsSkeleton } from "../settings/SettingsSkeleton.js";
|
|
|
19
19
|
import { useShareOrgMemberSearch } from "../sharing/share-controller-helpers.js";
|
|
20
20
|
import { useActionMutation, useActionQuery } from "../use-action.js";
|
|
21
21
|
import { cn } from "../utils.js";
|
|
22
|
-
import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRole, ORG_MEMBER_PAGE_SIZE, } from "./hooks.js";
|
|
22
|
+
import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRole, ORG_MEMBER_PAGE_SIZE, } from "./hooks.js";
|
|
23
23
|
const Button = forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
|
|
24
24
|
Button.displayName = "TeamPrimitiveButton";
|
|
25
25
|
function RoleIcon({ role }) {
|
|
@@ -219,7 +219,20 @@ function MembersCard({ appRoles }) {
|
|
|
219
219
|
const totalMembers = membersData?.totalCount ?? 0;
|
|
220
220
|
const pendingInvites = invitationsData?.invitations ?? [];
|
|
221
221
|
const hasMultipleOrgs = (org.orgs?.length ?? 0) > 1;
|
|
222
|
-
return (_jsxs("div", { className: "space-y-6", children: [_jsxs(SettingsGroup, { title: "Organization", children: [_jsx(SettingsRow, { id: "organization", label: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(IconUsersGroup, { className: "size-4 text-muted-foreground" }), _jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin })] }), description: `${t("org.memberCount", { count: totalMembers })} · ${t("org.youAreRole", { role: org.role })}`, control: hasMultipleOrgs ? (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] })) : undefined }), isOwnerOrAdmin && (_jsxs(_Fragment, { children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), switchOrg.error && (_jsx("div", { className: "px-5 pb-4", children: _jsx(ErrorText, { error: switchOrg.error }) }))] }), _jsx(MembersTableCard, { members: members, totalMembers: totalMembers, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, isFetchingMembers: isFetchingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles, groups: groupsQuery.data ?? [], canManageGroups: isOwnerOrAdmin, memberOffset: memberOffset, hasNextPage: membersData?.hasMore === true, nextMemberOffset: membersData?.nextOffset ?? null, onMemberPageChange: setMemberOffset }), isOwnerOrAdmin && (_jsx(WorkspaceGroupsCard, { groups: groupsQuery.data ?? [] })), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
|
|
222
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs(SettingsGroup, { title: "Organization", children: [_jsx(SettingsRow, { id: "organization", label: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(IconUsersGroup, { className: "size-4 text-muted-foreground" }), _jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin })] }), description: `${t("org.memberCount", { count: totalMembers })} · ${t("org.youAreRole", { role: org.role })}`, control: hasMultipleOrgs ? (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] })) : undefined }), isOwnerOrAdmin && (_jsxs(_Fragment, { children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceAppPrivacySettingsSection, { visibility: org.workspaceAppDefaultVisibility ?? "org" }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), switchOrg.error && (_jsx("div", { className: "px-5 pb-4", children: _jsx(ErrorText, { error: switchOrg.error }) }))] }), _jsx(MembersTableCard, { members: members, totalMembers: totalMembers, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, isFetchingMembers: isFetchingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles, groups: groupsQuery.data ?? [], canManageGroups: isOwnerOrAdmin, memberOffset: memberOffset, hasNextPage: membersData?.hasMore === true, nextMemberOffset: membersData?.nextOffset ?? null, onMemberPageChange: setMemberOffset }), isOwnerOrAdmin && (_jsx(WorkspaceGroupsCard, { groups: groupsQuery.data ?? [] })), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
|
|
223
|
+
}
|
|
224
|
+
function WorkspaceAppPrivacySettingsSection({ visibility, }) {
|
|
225
|
+
const t = useT();
|
|
226
|
+
const setDefault = useSetWorkspaceAppDefaultVisibility();
|
|
227
|
+
return (_jsx(SettingsRow, { id: "workspace-app-default-visibility", label: t("org.workspaceAppsDefaultPrivacy", {
|
|
228
|
+
defaultValue: "New app privacy",
|
|
229
|
+
}), description: t("org.workspaceAppsDefaultPrivacyDescription", {
|
|
230
|
+
defaultValue: "Choose whether new workspace apps start private to their creator or visible to the organization.",
|
|
231
|
+
}), control: _jsxs(Select, { value: visibility, onValueChange: (value) => setDefault.mutate(value === "private" ? "private" : "org"), disabled: setDefault.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "org", children: t("org.workspaceAppsOrganization", {
|
|
232
|
+
defaultValue: "Organization",
|
|
233
|
+
}) }), _jsx(SelectItem, { value: "private", children: t("org.workspaceAppsCreatorOnly", {
|
|
234
|
+
defaultValue: "Creator only",
|
|
235
|
+
}) })] })] }) }));
|
|
223
236
|
}
|
|
224
237
|
function MembersTableCard({ members, totalMembers, pendingInvites, isLoadingMembers, isFetchingMembers, currentUserEmail, currentUserRole, appRoles, groups, canManageGroups, memberOffset, hasNextPage, nextMemberOffset, onMemberPageChange, }) {
|
|
225
238
|
const t = useT();
|
|
@@ -59,6 +59,8 @@ export declare function useSwitchOrg(): import("@tanstack/react-query").UseMutat
|
|
|
59
59
|
export declare function useDeleteOrg(): import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
|
|
60
60
|
export declare function useJoinByDomain(): import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
|
|
61
61
|
export declare function useSetOrgDomain(): import("@tanstack/react-query").UseMutationResult<any, Error, string | null, unknown>;
|
|
62
|
+
export type WorkspaceAppDefaultVisibility = "private" | "org";
|
|
63
|
+
export declare function useSetWorkspaceAppDefaultVisibility(): import("@tanstack/react-query").UseMutationResult<any, Error, WorkspaceAppDefaultVisibility, unknown>;
|
|
62
64
|
export declare function useSetOrgWorkspaceUrl(): import("@tanstack/react-query").UseMutationResult<any, Error, string | null, unknown>;
|
|
63
65
|
export declare function useSetOrgAuthProvider(): import("@tanstack/react-query").UseMutationResult<any, Error, "google" | null, unknown>;
|
|
64
66
|
export interface AppRoleAssignment {
|
package/dist/client/org/hooks.js
CHANGED
|
@@ -247,6 +247,18 @@ export function useSetOrgDomain() {
|
|
|
247
247
|
},
|
|
248
248
|
});
|
|
249
249
|
}
|
|
250
|
+
export function useSetWorkspaceAppDefaultVisibility() {
|
|
251
|
+
const qc = useQueryClient();
|
|
252
|
+
return useMutation({
|
|
253
|
+
mutationFn: (visibility) => apiFetch(`${ORG_BASE}/workspace-app-default-visibility`, {
|
|
254
|
+
method: "PUT",
|
|
255
|
+
body: JSON.stringify({ visibility }),
|
|
256
|
+
}),
|
|
257
|
+
onSuccess: async () => {
|
|
258
|
+
await qc.invalidateQueries({ queryKey: ["org-me"] });
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
250
262
|
export function useSetOrgWorkspaceUrl() {
|
|
251
263
|
const qc = useQueryClient();
|
|
252
264
|
return useMutation({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
-
export type { InviteRole, InviteVars, BulkInviteResult, SyncA2ASecretResult, UseOrgRoleResult, AppRoleAssignment, AppRolesInfo, } from "./hooks.js";
|
|
1
|
+
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
+
export type { InviteRole, InviteVars, BulkInviteResult, SyncA2ASecretResult, UseOrgRoleResult, AppRoleAssignment, AppRolesInfo, WorkspaceAppDefaultVisibility, } from "./hooks.js";
|
|
3
3
|
export type { AppRolesDescriptor } from "../../org/app-roles.js";
|
|
4
4
|
export { OrgSwitcher, type OrgSwitcherProps } from "./OrgSwitcher.js";
|
|
5
5
|
export { InvitationBanner, type InvitationBannerProps, } from "./InvitationBanner.js";
|
package/dist/client/org/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Public client API for the org module.
|
|
2
|
-
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
+
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
3
3
|
export { OrgSwitcher } from "./OrgSwitcher.js";
|
|
4
4
|
export { InvitationBanner, } from "./InvitationBanner.js";
|
|
5
5
|
export { WorkspaceNotice } from "./WorkspaceNotice.js";
|
|
@@ -131,7 +131,7 @@ export function ShareButton(props) {
|
|
|
131
131
|
function SharePanel(props) {
|
|
132
132
|
const t = useT();
|
|
133
133
|
const { controller } = props;
|
|
134
|
-
const { inviteEmail, setInviteEmail: onInviteEmailChange, activeShareTab, handleShareTabChange, data, policy, visibility, canManage, role, setRole, notifyPeople, setNotifyPeople, shareMessage, setShareMessage, messageOpen, setMessageOpen, shareError, setShareError, suggestionsOpen, setSuggestionsOpen, inFlight, memberSearch, memberSuggestions, knownMembers, shares, handleVisibility, handleHideInSearch, handleAdd, handleChangeRole, handleRemove, } = controller;
|
|
134
|
+
const { inviteEmail, setInviteEmail: onInviteEmailChange, activeShareTab, handleShareTabChange, data, policy, visibility, canManage, role, setRole, notifyPeople, setNotifyPeople, shareMessage, setShareMessage, messageOpen, setMessageOpen, shareError, setShareError, suggestionsOpen, setSuggestionsOpen, inFlight, memberSearch, memberSuggestions, groupSuggestions, selectGroup, knownMembers, shares, handleVisibility, handleHideInSearch, handleAdd, handleChangeRole, handleRemove, } = controller;
|
|
135
135
|
const hasInviteEmail = inviteEmail.trim().length > 0;
|
|
136
136
|
const isLoading = data === undefined;
|
|
137
137
|
const meta = visibilityMeta(visibility, t, props.visibilityCopy);
|
|
@@ -155,8 +155,13 @@ function SharePanel(props) {
|
|
|
155
155
|
onInviteEmailChange(next);
|
|
156
156
|
if (shareError)
|
|
157
157
|
setShareError(null);
|
|
158
|
-
},
|
|
159
|
-
|
|
158
|
+
}, onSelectSuggestion: (suggestion) => {
|
|
159
|
+
if (suggestion.principalType === "group") {
|
|
160
|
+
selectGroup(suggestion);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
onInviteEmailChange(suggestion.email);
|
|
164
|
+
}
|
|
160
165
|
setSuggestionsOpen(false);
|
|
161
166
|
if (shareError)
|
|
162
167
|
setShareError(null);
|
|
@@ -165,8 +170,21 @@ function SharePanel(props) {
|
|
|
165
170
|
defaultValue: "Add people from your organization",
|
|
166
171
|
})
|
|
167
172
|
: t("agentChat.share.addPeopleEmail", {
|
|
168
|
-
defaultValue:
|
|
169
|
-
|
|
173
|
+
defaultValue: policy.supportsGroupShares
|
|
174
|
+
? "Add people or groups"
|
|
175
|
+
: "Add people by email",
|
|
176
|
+
}), suggestions: [
|
|
177
|
+
...memberSuggestions.map((member) => ({
|
|
178
|
+
...member,
|
|
179
|
+
principalType: "user",
|
|
180
|
+
})),
|
|
181
|
+
...(policy.supportsGroupShares
|
|
182
|
+
? groupSuggestions.map((group) => ({
|
|
183
|
+
...group,
|
|
184
|
+
principalType: "group",
|
|
185
|
+
}))
|
|
186
|
+
: []),
|
|
187
|
+
], search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: t("agentChat.share.add", { defaultValue: "Add" }) })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), t("agentChat.share.notifyPeople", {
|
|
170
188
|
defaultValue: "Notify people",
|
|
171
189
|
})] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), 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", children: messageOpen
|
|
172
190
|
? t("agentChat.share.hideMessage", {
|
|
@@ -178,7 +196,7 @@ function SharePanel(props) {
|
|
|
178
196
|
defaultValue: "Message",
|
|
179
197
|
}), placeholder: t("agentChat.share.messagePlaceholder", {
|
|
180
198
|
defaultValue: "Add a short note (optional)",
|
|
181
|
-
}), value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, 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" }) })) : null] })) : null, _jsxs("ul", { className: "flex list-none flex-col gap-1 p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "text-xs text-muted-foreground", children: t("agentChat.share.owner", { defaultValue: "Owner" }) })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers, t), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers, t) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, t, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": t("agentChat.share.remove", {
|
|
199
|
+
}), value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, 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" }) })) : null] })) : null, _jsxs("ul", { className: "flex list-none flex-col gap-1 p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers, t) }), _jsx("span", { className: "text-xs text-muted-foreground", children: t("agentChat.share.owner", { defaultValue: "Owner" }) })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers, t), org: s.principalType === "org", group: s.principalType === "group" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers, t) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, t, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": t("agentChat.share.remove", {
|
|
182
200
|
defaultValue: "Remove",
|
|
183
201
|
}), onClick: () => handleRemove(s), disabled: inFlight.has(keyOf(s)), className: BUTTON_GHOST_ICON, children: _jsx(IconTrash, { size: 14 }) })) : null] }, keyOf(s)))), !shares.length && !data?.ownerEmail ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: t("agentChat.share.noAccess", {
|
|
184
202
|
defaultValue: "No one has access yet.",
|
|
@@ -219,13 +237,13 @@ function AdvancedAccessPopover({ control, canManage, onToggle, }) {
|
|
|
219
237
|
defaultValue: "People with the link can still open this.",
|
|
220
238
|
}) })] })] })] }) })] }));
|
|
221
239
|
}
|
|
222
|
-
function MemberAutocomplete({ value, open, onOpenChange, onValueChange,
|
|
240
|
+
function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelectSuggestion, onSubmit, placeholder, suggestions, search, }) {
|
|
223
241
|
const t = useT();
|
|
224
242
|
const rawListboxId = useId();
|
|
225
243
|
const listboxId = rawListboxId.replace(/:/g, "");
|
|
226
244
|
const inputRef = useRef(null);
|
|
227
245
|
const [activeIndex, setActiveIndex] = useState(-1);
|
|
228
|
-
const
|
|
246
|
+
const activeSuggestion = activeIndex >= 0 && activeIndex < suggestions.length
|
|
229
247
|
? suggestions[activeIndex]
|
|
230
248
|
: null;
|
|
231
249
|
useEffect(() => {
|
|
@@ -243,8 +261,8 @@ function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelect
|
|
|
243
261
|
.getElementById(optionId(listboxId, activeIndex))
|
|
244
262
|
?.scrollIntoView({ block: "nearest" });
|
|
245
263
|
}, [activeIndex, listboxId]);
|
|
246
|
-
const
|
|
247
|
-
|
|
264
|
+
const chooseSuggestion = (suggestion) => {
|
|
265
|
+
onSelectSuggestion(suggestion);
|
|
248
266
|
onOpenChange(false);
|
|
249
267
|
inputRef.current?.focus();
|
|
250
268
|
};
|
|
@@ -273,9 +291,9 @@ function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelect
|
|
|
273
291
|
return;
|
|
274
292
|
}
|
|
275
293
|
if (event.key === "Enter") {
|
|
276
|
-
if (open &&
|
|
294
|
+
if (open && activeSuggestion) {
|
|
277
295
|
event.preventDefault();
|
|
278
|
-
|
|
296
|
+
chooseSuggestion(activeSuggestion);
|
|
279
297
|
return;
|
|
280
298
|
}
|
|
281
299
|
if (value.trim()) {
|
|
@@ -299,7 +317,7 @@ function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelect
|
|
|
299
317
|
search.loadMore();
|
|
300
318
|
}
|
|
301
319
|
};
|
|
302
|
-
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsxs("div", { className: "relative flex-1 min-w-0", children: [_jsx(IconSearch, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "pointer-events-none absolute start-2.5 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { ref: inputRef, type: "
|
|
320
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsxs("div", { className: "relative flex-1 min-w-0", children: [_jsx(IconSearch, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "pointer-events-none absolute start-2.5 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { ref: inputRef, type: "text", role: "combobox", "aria-autocomplete": "list", "aria-expanded": open, "aria-controls": open ? listboxId : undefined, "aria-activedescendant": activeIndex >= 0 ? optionId(listboxId, activeIndex) : undefined, placeholder: placeholder, value: value, onChange: (event) => {
|
|
303
321
|
onValueChange(event.target.value);
|
|
304
322
|
onOpenChange(true);
|
|
305
323
|
}, onFocus: () => onOpenChange(true), onBlur: () => {
|
|
@@ -308,11 +326,15 @@ function MemberAutocomplete({ value, open, onOpenChange, onValueChange, onSelect
|
|
|
308
326
|
onOpenChange(false);
|
|
309
327
|
}
|
|
310
328
|
}, 0);
|
|
311
|
-
}, onKeyDown: handleKeyDown, autoComplete: "off", className: "h-9 w-full min-w-0 rounded-md border border-input bg-card ps-8 pe-8 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" }), search.isLoading ? (_jsx(IconLoader2, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "pointer-events-none absolute end-2.5 top-1/2 -translate-y-1/2 animate-spin text-muted-foreground" })) : null] }) }), _jsx(PopoverContent, { align: "start", sideOffset: 4, "data-agent-native-share-overlay": "", onOpenAutoFocus: (event) => event.preventDefault(), className: cn(SHARE_NESTED_OVERLAY_Z, "w-[var(--radix-popper-anchor-width)] min-w-[18rem] rounded-md p-1 shadow-lg", SHARE_POPOVER_SURFACE), children: _jsxs("div", { id: listboxId, role: "listbox", className: "max-h-56 overflow-y-auto overflow-x-hidden", onScroll: handleScroll, children: [suggestions.map((
|
|
329
|
+
}, onKeyDown: handleKeyDown, autoComplete: "off", className: "h-9 w-full min-w-0 rounded-md border border-input bg-card ps-8 pe-8 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" }), search.isLoading ? (_jsx(IconLoader2, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "pointer-events-none absolute end-2.5 top-1/2 -translate-y-1/2 animate-spin text-muted-foreground" })) : null] }) }), _jsx(PopoverContent, { align: "start", sideOffset: 4, "data-agent-native-share-overlay": "", onOpenAutoFocus: (event) => event.preventDefault(), className: cn(SHARE_NESTED_OVERLAY_Z, "w-[var(--radix-popper-anchor-width)] min-w-[18rem] rounded-md p-1 shadow-lg", SHARE_POPOVER_SURFACE), children: _jsxs("div", { id: listboxId, role: "listbox", className: "max-h-56 overflow-y-auto overflow-x-hidden", onScroll: handleScroll, children: [suggestions.map((suggestion, index) => {
|
|
312
330
|
const active = index === activeIndex;
|
|
313
|
-
return (_jsxs("div", { id: optionId(listboxId, index), role: "option", "aria-selected": active, onMouseDown: (event) => event.preventDefault(), onMouseEnter: () => setActiveIndex(index), onClick: () =>
|
|
331
|
+
return (_jsxs("div", { id: optionId(listboxId, index), role: "option", "aria-selected": active, onMouseDown: (event) => event.preventDefault(), onMouseEnter: () => setActiveIndex(index), onClick: () => chooseSuggestion(suggestion), className: cn("flex cursor-pointer select-none flex-col rounded-sm px-3 py-2 text-sm outline-none", active
|
|
314
332
|
? "bg-accent text-accent-foreground"
|
|
315
|
-
: "text-foreground hover:bg-accent hover:text-accent-foreground"), children: [
|
|
333
|
+
: "text-foreground hover:bg-accent hover:text-accent-foreground"), children: [_jsxs("span", { className: "flex items-center gap-2 truncate font-medium", children: [suggestion.principalType === "group" ? (_jsx(IconUsersGroup, { "aria-hidden": true, size: 14, strokeWidth: 1.8, className: "shrink-0 text-muted-foreground" })) : null, _jsx("span", { className: "truncate", children: suggestion.principalType === "group"
|
|
334
|
+
? suggestion.name
|
|
335
|
+
: suggestion.name?.trim() || suggestion.email })] }), suggestion.principalType === "group" ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: t("agentChat.share.userGroup", {
|
|
336
|
+
defaultValue: "User group",
|
|
337
|
+
}) })) : suggestion.name?.trim() ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: suggestion.email })) : null] }, `${suggestion.principalType}:${suggestion.principalType === "group" ? suggestion.id : suggestion.email}`));
|
|
316
338
|
}), search.isLoading && suggestions.length === 0 ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: t("agentChat.share.searching", {
|
|
317
339
|
defaultValue: "Searching...",
|
|
318
340
|
}) })) : null, search.error ? (_jsx("div", { className: "px-3 py-3 text-sm text-muted-foreground", children: t("agentChat.share.loadPeopleFailed", {
|
|
@@ -375,8 +397,8 @@ function VisibilitySelect(props) {
|
|
|
375
397
|
.description,
|
|
376
398
|
})) }) }) }) })] }));
|
|
377
399
|
}
|
|
378
|
-
function Avatar({ label, org }) {
|
|
379
|
-
return (_jsx("span", { "aria-hidden": true, className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-muted text-[11px] font-semibold text-muted-foreground", children: org ? _jsx(IconUsersGroup, { size: 14, strokeWidth: 1.75 }) : initials(label) }));
|
|
400
|
+
function Avatar({ label, org, group, }) {
|
|
401
|
+
return (_jsx("span", { "aria-hidden": true, className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-muted text-[11px] font-semibold text-muted-foreground", children: org || group ? (_jsx(IconUsersGroup, { size: 14, strokeWidth: 1.75 })) : (initials(label)) }));
|
|
380
402
|
}
|
|
381
403
|
function keyOf(s) {
|
|
382
404
|
return `${s.principalType}:${s.principalId}`;
|
|
@@ -393,6 +415,9 @@ function principalLabel(share, members, t) {
|
|
|
393
415
|
return t("agentChat.share.organization", {
|
|
394
416
|
defaultValue: "Organization",
|
|
395
417
|
});
|
|
418
|
+
if (share.principalType === "group")
|
|
419
|
+
return (serverLabel ||
|
|
420
|
+
t("agentChat.share.userGroup", { defaultValue: "User group" }));
|
|
396
421
|
return displayName(share.principalId, members, t);
|
|
397
422
|
}
|
|
398
423
|
function displayName(emailOrId, members, t) {
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useActionQuery } from "../use-action.js";
|
|
2
2
|
export type ShareButtonVisibility = "private" | "org" | "public";
|
|
3
3
|
export type ShareButtonRole = "viewer" | "commenter" | "editor" | "admin";
|
|
4
4
|
export interface ShareButtonShare {
|
|
5
5
|
id: string;
|
|
6
|
-
principalType: "user" | "org";
|
|
6
|
+
principalType: "user" | "group" | "org";
|
|
7
7
|
principalId: string;
|
|
8
8
|
displayName?: string | null;
|
|
9
9
|
role: ShareButtonRole;
|
|
10
10
|
}
|
|
11
|
+
export interface ShareButtonGroup {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
memberEmails?: string[];
|
|
15
|
+
}
|
|
11
16
|
export interface ShareButtonSharesResponse {
|
|
12
17
|
ownerEmail: string | null;
|
|
13
18
|
orgId: string | null;
|
|
@@ -18,6 +23,7 @@ export interface ShareButtonSharesResponse {
|
|
|
18
23
|
policy?: {
|
|
19
24
|
allowPublic: boolean;
|
|
20
25
|
requireOrgMemberForUserShares: boolean;
|
|
26
|
+
supportsGroupShares?: boolean;
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
29
|
export interface ShareButtonOrgMember {
|
|
@@ -65,6 +71,7 @@ export interface ShareButtonController {
|
|
|
65
71
|
policy: {
|
|
66
72
|
allowPublic: boolean;
|
|
67
73
|
requireOrgMemberForUserShares: boolean;
|
|
74
|
+
supportsGroupShares?: boolean;
|
|
68
75
|
};
|
|
69
76
|
visibility: ShareButtonVisibility;
|
|
70
77
|
triggerVisibility: ShareButtonVisibility | null;
|
|
@@ -84,7 +91,10 @@ export interface ShareButtonController {
|
|
|
84
91
|
inFlight: Set<string>;
|
|
85
92
|
memberSearch: ShareButtonOrgMemberSearch;
|
|
86
93
|
memberSuggestions: ShareButtonOrgMember[];
|
|
94
|
+
groupSuggestions: ShareButtonGroup[];
|
|
87
95
|
knownMembers: ShareButtonOrgMember[];
|
|
96
|
+
selectedGroup: ShareButtonGroup | null;
|
|
97
|
+
selectGroup: (group: ShareButtonGroup) => void;
|
|
88
98
|
shares: ShareButtonShare[];
|
|
89
99
|
handleVisibility: (visibility: ShareButtonVisibility) => void;
|
|
90
100
|
handleHideInSearch: () => void;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { useActionQuery } from "../use-action.js";
|
|
2
3
|
import { DEFAULT_MEMBER_SEARCH_DEBOUNCE_MS, DEFAULT_MEMBER_SUGGESTION_LIMIT, extractShareErrorMessage, optimisticallyUpdateShareCache, rollbackShareCache, useShareOrgMemberSearch, useShareMutationGuard, useShareMutations, useShareQuery, } from "./share-controller-helpers.js";
|
|
3
4
|
export function useShareButtonController(options) {
|
|
4
5
|
const [open, setOpen] = useState(false);
|
|
5
6
|
const [inviteEmail, setInviteEmail] = useState("");
|
|
7
|
+
const [selectedGroup, setSelectedGroup] = useState(null);
|
|
6
8
|
const shareTabDefaultValue = options.shareTabs?.defaultValue ?? "share";
|
|
7
9
|
const [activeShareTab, setActiveShareTab] = useState(shareTabDefaultValue);
|
|
8
10
|
const [visibilityOverride, setVisibilityOverride] = useState(null);
|
|
@@ -25,6 +27,7 @@ export function useShareButtonController(options) {
|
|
|
25
27
|
}, [options, shareTabDefaultValue, sharesQuery, visibilityOverride]);
|
|
26
28
|
useEffect(() => {
|
|
27
29
|
setInviteEmail("");
|
|
30
|
+
setSelectedGroup(null);
|
|
28
31
|
setShareMessage("");
|
|
29
32
|
setMessageOpen(false);
|
|
30
33
|
}, [options.resourceId, options.resourceType]);
|
|
@@ -141,6 +144,10 @@ export function useShareButtonController(options) {
|
|
|
141
144
|
limit: DEFAULT_MEMBER_SUGGESTION_LIMIT,
|
|
142
145
|
debounceMs: DEFAULT_MEMBER_SEARCH_DEBOUNCE_MS,
|
|
143
146
|
});
|
|
147
|
+
const groupsQuery = useActionQuery("list-workspace-user-groups", {}, {
|
|
148
|
+
enabled: canManage && policy.supportsGroupShares === true && suggestionsOpen,
|
|
149
|
+
staleTime: 30_000,
|
|
150
|
+
});
|
|
144
151
|
const serverShares = data?.shares ?? [];
|
|
145
152
|
const shares = [
|
|
146
153
|
...serverShares
|
|
@@ -160,7 +167,21 @@ export function useShareButtonController(options) {
|
|
|
160
167
|
}
|
|
161
168
|
}
|
|
162
169
|
const memberSuggestions = memberSearch.members.filter((member) => !excludedMemberEmails.has(member.email.toLowerCase()));
|
|
170
|
+
const excludedGroupIds = new Set(shares
|
|
171
|
+
.filter((share) => share.principalType === "group")
|
|
172
|
+
.map((share) => share.principalId));
|
|
173
|
+
const groupSuggestions = (Array.isArray(groupsQuery.data) ? groupsQuery.data : []).filter((group) => !excludedGroupIds.has(group.id) &&
|
|
174
|
+
(!inviteEmail.trim() ||
|
|
175
|
+
group.name.toLowerCase().includes(inviteEmail.trim().toLowerCase())));
|
|
163
176
|
const knownMembers = memberSearch.members;
|
|
177
|
+
const setInviteEmailValue = useCallback((email) => {
|
|
178
|
+
setSelectedGroup(null);
|
|
179
|
+
setInviteEmail(email);
|
|
180
|
+
}, []);
|
|
181
|
+
const selectGroup = useCallback((group) => {
|
|
182
|
+
setSelectedGroup(group);
|
|
183
|
+
setInviteEmail(group.name);
|
|
184
|
+
}, []);
|
|
164
185
|
const handleVisibility = useCallback((next) => {
|
|
165
186
|
if (next === visibility)
|
|
166
187
|
return;
|
|
@@ -189,11 +210,14 @@ export function useShareButtonController(options) {
|
|
|
189
210
|
const trimmed = inviteEmail.trim();
|
|
190
211
|
if (!trimmed || !canManage)
|
|
191
212
|
return;
|
|
192
|
-
const
|
|
213
|
+
const principalType = selectedGroup ? "group" : "user";
|
|
214
|
+
const principalId = selectedGroup?.id ?? trimmed;
|
|
215
|
+
const message = principalType === "user" && notifyPeople ? shareMessage.trim() : "";
|
|
193
216
|
const optimistic = {
|
|
194
|
-
id: `pending-${
|
|
195
|
-
principalType
|
|
196
|
-
principalId
|
|
217
|
+
id: `pending-${principalType}-${principalId}`,
|
|
218
|
+
principalType,
|
|
219
|
+
principalId,
|
|
220
|
+
...(selectedGroup ? { displayName: selectedGroup.name } : {}),
|
|
197
221
|
role,
|
|
198
222
|
};
|
|
199
223
|
const key = keyOf(optimistic);
|
|
@@ -202,6 +226,7 @@ export function useShareButtonController(options) {
|
|
|
202
226
|
setShareError(null);
|
|
203
227
|
setPendingAdds((previous) => [...previous, optimistic]);
|
|
204
228
|
setInviteEmail("");
|
|
229
|
+
setSelectedGroup(null);
|
|
205
230
|
setShareMessage("");
|
|
206
231
|
setMessageOpen(false);
|
|
207
232
|
setSuggestionsOpen(false);
|
|
@@ -210,10 +235,10 @@ export function useShareButtonController(options) {
|
|
|
210
235
|
share.mutate({
|
|
211
236
|
resourceType: options.resourceType,
|
|
212
237
|
resourceId: options.resourceId,
|
|
213
|
-
principalType
|
|
214
|
-
principalId
|
|
238
|
+
principalType,
|
|
239
|
+
principalId,
|
|
215
240
|
role,
|
|
216
|
-
notify: notifyPeople,
|
|
241
|
+
notify: principalType === "user" && notifyPeople,
|
|
217
242
|
resourceUrl: getNotificationUrl(options.shareUrl),
|
|
218
243
|
...(message ? { message } : {}),
|
|
219
244
|
}, {
|
|
@@ -228,6 +253,7 @@ export function useShareButtonController(options) {
|
|
|
228
253
|
setPendingAdds((previous) => previous.filter((item) => item.id !== optimistic.id));
|
|
229
254
|
clearInFlight(key);
|
|
230
255
|
setInviteEmail(trimmed);
|
|
256
|
+
setSelectedGroup(selectedGroup);
|
|
231
257
|
setShareMessage((current) => current || message);
|
|
232
258
|
setMessageOpen((current) => current || Boolean(message));
|
|
233
259
|
setShareError(extractShareErrorMessage(error));
|
|
@@ -244,6 +270,7 @@ export function useShareButtonController(options) {
|
|
|
244
270
|
options.resourceType,
|
|
245
271
|
options.shareUrl,
|
|
246
272
|
role,
|
|
273
|
+
selectedGroup,
|
|
247
274
|
shareMessage,
|
|
248
275
|
share,
|
|
249
276
|
queryClient,
|
|
@@ -368,7 +395,7 @@ export function useShareButtonController(options) {
|
|
|
368
395
|
activeShareTab,
|
|
369
396
|
handleShareTabChange,
|
|
370
397
|
inviteEmail,
|
|
371
|
-
setInviteEmail,
|
|
398
|
+
setInviteEmail: setInviteEmailValue,
|
|
372
399
|
sharesQuery,
|
|
373
400
|
visibilityOverride,
|
|
374
401
|
handleVisibilityChange,
|
|
@@ -399,6 +426,9 @@ export function useShareButtonController(options) {
|
|
|
399
426
|
handleAdd,
|
|
400
427
|
handleChangeRole,
|
|
401
428
|
handleRemove,
|
|
429
|
+
groupSuggestions,
|
|
430
|
+
selectedGroup,
|
|
431
|
+
selectGroup,
|
|
402
432
|
};
|
|
403
433
|
}
|
|
404
434
|
function keyOf(share) {
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
-
error?: undefined;
|
|
66
65
|
states: {
|
|
67
66
|
clientId: number;
|
|
68
67
|
state: string;
|
|
69
68
|
}[];
|
|
69
|
+
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
-
error?: undefined;
|
|
81
80
|
users: {
|
|
82
81
|
clientId: number;
|
|
83
82
|
lastSeen: number;
|
|
84
83
|
}[];
|
|
84
|
+
error?: undefined;
|
|
85
85
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
error: string;
|
|
30
29
|
ok?: undefined;
|
|
30
|
+
error: string;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
package/dist/collab/storage.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare function trySaveYDocState(docId: string, state: Uint8Array, textS
|
|
|
18
18
|
export declare function saveYDocState(docId: string, state: Uint8Array, textSnapshot: string): Promise<void>;
|
|
19
19
|
/** Check if a document has collaborative state. */
|
|
20
20
|
export declare function hasCollabState(docId: string): Promise<boolean>;
|
|
21
|
+
/** Load all existing document ids in one query for startup reconciliation. */
|
|
22
|
+
export declare function listCollabDocIds(): Promise<Set<string>>;
|
|
21
23
|
/** Delete collaborative state for a document. */
|
|
22
24
|
export declare function deleteCollabState(docId: string): Promise<void>;
|
|
23
25
|
declare function uint8ArrayToBase64(arr: Uint8Array): string;
|
package/dist/collab/storage.js
CHANGED
|
@@ -148,6 +148,13 @@ export async function hasCollabState(docId) {
|
|
|
148
148
|
});
|
|
149
149
|
return rows.length > 0;
|
|
150
150
|
}
|
|
151
|
+
/** Load all existing document ids in one query for startup reconciliation. */
|
|
152
|
+
export async function listCollabDocIds() {
|
|
153
|
+
await ensureTable();
|
|
154
|
+
const client = getDbExec();
|
|
155
|
+
const { rows } = await client.execute("SELECT doc_id FROM _collab_docs");
|
|
156
|
+
return new Set(rows.flatMap((row) => typeof row.doc_id === "string" && row.doc_id ? [row.doc_id] : []));
|
|
157
|
+
}
|
|
151
158
|
/** Delete collaborative state for a document. */
|
|
152
159
|
export async function deleteCollabState(docId) {
|
|
153
160
|
await ensureTable();
|
package/dist/config.js
CHANGED
|
@@ -374,14 +374,24 @@ export function isAgentNativeDeploymentEnvironment(value) {
|
|
|
374
374
|
* never parses process.env itself.
|
|
375
375
|
*/
|
|
376
376
|
export function inferAgentNativeDeploymentEnvironment(env, mode) {
|
|
377
|
+
const explicit = env.AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT?.trim().toLowerCase();
|
|
378
|
+
if (explicit && !isAgentNativeDeploymentEnvironment(explicit)) {
|
|
379
|
+
throw new Error('AGENT_NATIVE_DEPLOYMENT_ENVIRONMENT must be "local", "beta", "production", or "preview"');
|
|
380
|
+
}
|
|
381
|
+
if (isAgentNativeDeploymentEnvironment(explicit))
|
|
382
|
+
return explicit;
|
|
377
383
|
const context = env.CONTEXT?.trim().toLowerCase();
|
|
378
384
|
const branch = env.BRANCH?.trim().toLowerCase();
|
|
379
|
-
|
|
385
|
+
const vercelEnv = env.VERCEL_ENV?.trim().toLowerCase();
|
|
386
|
+
if (branch === "production" ||
|
|
387
|
+
(context === "production" && branch !== "beta")) {
|
|
380
388
|
return "production";
|
|
381
389
|
}
|
|
382
390
|
if (branch === "beta" || (context === "branch-deploy" && branch === "main")) {
|
|
383
391
|
return "beta";
|
|
384
392
|
}
|
|
393
|
+
if (vercelEnv === "preview")
|
|
394
|
+
return "preview";
|
|
385
395
|
if (context === "deploy-preview" ||
|
|
386
396
|
context === "branch-deploy" ||
|
|
387
397
|
branch?.startsWith("deploy-preview")) {
|
|
@@ -464,14 +464,14 @@ export declare function createDashboardStorageSchema(options?: DashboardStorageS
|
|
|
464
464
|
tableName: string;
|
|
465
465
|
dataType: "string";
|
|
466
466
|
columnType: "SQLiteText";
|
|
467
|
-
data: "org" | "user";
|
|
467
|
+
data: "group" | "org" | "user";
|
|
468
468
|
driverParam: string;
|
|
469
469
|
notNull: true;
|
|
470
470
|
hasDefault: false;
|
|
471
471
|
isPrimaryKey: false;
|
|
472
472
|
isAutoincrement: false;
|
|
473
473
|
hasRuntimeDefault: false;
|
|
474
|
-
enumValues: ["user", "org"];
|
|
474
|
+
enumValues: ["user", "group", "org"];
|
|
475
475
|
baseColumn: never;
|
|
476
476
|
identity: undefined;
|
|
477
477
|
generated: undefined;
|
|
@@ -411,14 +411,14 @@ export declare const dataProgramShares: import("drizzle-orm/sqlite-core").SQLite
|
|
|
411
411
|
tableName: string;
|
|
412
412
|
dataType: "string";
|
|
413
413
|
columnType: "SQLiteText";
|
|
414
|
-
data: "org" | "user";
|
|
414
|
+
data: "group" | "org" | "user";
|
|
415
415
|
driverParam: string;
|
|
416
416
|
notNull: true;
|
|
417
417
|
hasDefault: false;
|
|
418
418
|
isPrimaryKey: false;
|
|
419
419
|
isAutoincrement: false;
|
|
420
420
|
hasRuntimeDefault: false;
|
|
421
|
-
enumValues: ["user", "org"];
|
|
421
|
+
enumValues: ["user", "group", "org"];
|
|
422
422
|
baseColumn: never;
|
|
423
423
|
identity: undefined;
|
|
424
424
|
generated: undefined;
|
package/dist/deploy/build.d.ts
CHANGED
|
@@ -337,4 +337,4 @@ export declare function resolveNitroBundledYjsEntry(): string;
|
|
|
337
337
|
* small set above through the controlled post-build pass.
|
|
338
338
|
*/
|
|
339
339
|
export declare function nitroNoExternalsForPreset(targetPreset: string): true | readonly string[];
|
|
340
|
-
export declare function resolveNitroBuildReplacements(env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
340
|
+
export declare function resolveNitroBuildReplacements(env?: NodeJS.ProcessEnv, deploymentEnvironment?: string): Record<string, string>;
|