@agent-native/core 0.164.4 → 0.164.12
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/calendar/.agents/skills/event-management/SKILL.md +84 -0
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/calendar/actions/delete-event.ts +1 -1
- package/corpus/templates/calendar/actions/delete-events.ts +508 -0
- package/corpus/templates/calendar/actions/event-action-helpers.ts +1 -1
- package/corpus/templates/calendar/actions/list-events.ts +53 -0
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +36 -47
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +18 -1
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +256 -38
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +43 -3
- package/corpus/templates/calendar/app/i18n-data.ts +120 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +113 -0
- package/corpus/templates/calendar/changelog/2026-08-18-the-agent-can-now-remove-many-meetings-at-once-such-as-every.md +6 -0
- package/corpus/templates/calendar/server/handlers/google-auth.ts +119 -3
- package/corpus/templates/calendar/server/lib/event-weekday.ts +112 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +12 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +18 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +114 -20
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +83 -78
- package/corpus/templates/clips/changelog/2026-08-19-clips-nightly-builds-are-available-for-trying-the-latest-upd.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-19-social-preview-video-frames.md +1 -0
- package/corpus/templates/clips/desktop/README.md +19 -4
- package/corpus/templates/clips/desktop/src/app.tsx +78 -16
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -2
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -0
- package/corpus/templates/clips/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +41 -3
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +22 -1
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +41 -22
- package/corpus/templates/factory/AGENTS.md +3 -2
- package/corpus/templates/factory/actions/get-factory-graph-version.ts +69 -0
- package/corpus/templates/factory/actions/list-factory-automations.ts +4 -0
- package/corpus/templates/factory/actions/list-factory-graph-versions.ts +82 -0
- package/corpus/templates/factory/actions/restore-factory-graph-version.ts +163 -0
- package/corpus/templates/factory/actions/save-factory-graph.ts +93 -60
- package/corpus/templates/factory/actions/start-builder-for-item.ts +19 -17
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +100 -36
- package/corpus/templates/factory/app/components/factory/FactoryHistoryView.tsx +709 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +62 -2
- package/corpus/templates/factory/app/components/ui/alert-dialog.tsx +1 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +47 -0
- package/corpus/templates/factory/app/routes/factory.tsx +324 -61
- package/corpus/templates/factory/server/connectors/slack.ts +44 -2
- package/corpus/templates/factory/server/plugins/agent-chat.ts +12 -8
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +13 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +5 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +72 -4
- package/corpus/templates/mail/actions/view-screen.ts +1 -1
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -18
- package/corpus/templates/mail/server/handlers/google-auth.ts +125 -24
- package/corpus/templates/mail/server/lib/gmail-query.ts +5 -2
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +0 -12
- package/corpus/templates/plan/changelog/2026-08-19-plan-prompts-now-guide-you-to-connect-ai-before-sending-and-.md +6 -0
- package/corpus/templates/slides/actions/approve-deck-access-request.ts +234 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +35 -2
- package/corpus/templates/slides/actions/request-deck-access.ts +263 -64
- package/corpus/templates/slides/app/components/editor/MissingDeckAccessPane.tsx +196 -0
- package/corpus/templates/slides/app/components/editor/RequestDeckAccessDialog.tsx +101 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +7 -4
- package/corpus/templates/slides/app/i18n/en-US.ts +29 -6
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +147 -169
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +250 -0
- package/corpus/templates/slides/server/db/schema.ts +8 -0
- package/corpus/templates/slides/server/lib/access-request-email.ts +36 -0
- package/corpus/templates/slides/server/lib/emails.ts +26 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/slides/server/plugins/db.ts +50 -0
- package/corpus/templates/slides/shared/deck-access.ts +31 -0
- package/dist/a2a/task-store.d.ts +1 -0
- package/dist/a2a/task-store.js +1 -1
- package/dist/agent/observational-memory/store.d.ts +1 -0
- package/dist/agent/observational-memory/store.js +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/tool-approval-store.d.ts +1 -0
- package/dist/agent/tool-approval-store.js +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.js +1 -1
- package/dist/browser-sessions/store.d.ts +1 -0
- package/dist/browser-sessions/store.js +1 -1
- package/dist/checkpoints/store.d.ts +1 -0
- package/dist/checkpoints/store.js +1 -1
- package/dist/cli/code-agent-schedules.d.ts +11 -0
- package/dist/cli/code-agent-schedules.js +44 -5
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AssistantChat.d.ts +5 -1
- package/dist/client/AssistantChat.js +40 -6
- package/dist/client/EnvironmentBadge.d.ts +7 -13
- package/dist/client/EnvironmentBadge.js +43 -92
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/agent-chat-adapter.js +76 -50
- package/dist/client/app-providers.js +4 -4
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.js +28 -1
- package/dist/client/chat/run-recovery.js +26 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -0
- package/dist/client/chat-first/apps-rail.js +28 -2
- package/dist/client/sse-event-processor.js +13 -8
- package/dist/client/use-active-agent-chat-run.d.ts +2 -0
- package/dist/client/use-active-agent-chat-run.js +22 -0
- package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
- package/dist/coding-tools/sandbox/executions-store.js +1 -1
- package/dist/collab/awareness-store.d.ts +1 -0
- package/dist/collab/awareness-store.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +1 -0
- package/dist/collab/storage.js +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.js +3 -3
- package/dist/db/ddl-guard.js +8 -0
- package/dist/db/migration-runtime.d.ts +23 -0
- package/dist/db/migration-runtime.js +41 -0
- package/dist/db/migrations.d.ts +1 -2
- package/dist/db/migrations.js +2 -24
- package/dist/email-catalog/log.d.ts +1 -0
- package/dist/email-catalog/log.js +1 -1
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/guards/release-schema-complete.d.ts +22 -0
- package/dist/guards/release-schema-complete.js +144 -0
- package/dist/integrations/a2a-continuations-store.d.ts +1 -0
- package/dist/integrations/a2a-continuations-store.js +1 -1
- package/dist/integrations/awaiting-input-store.d.ts +1 -0
- package/dist/integrations/awaiting-input-store.js +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.js +1 -1
- package/dist/integrations/controls-store.d.ts +1 -0
- package/dist/integrations/controls-store.js +1 -1
- package/dist/integrations/identity-links-store.d.ts +1 -0
- package/dist/integrations/identity-links-store.js +1 -1
- package/dist/integrations/installations-store.d.ts +1 -0
- package/dist/integrations/installations-store.js +1 -1
- package/dist/integrations/remote-commands-store.d.ts +1 -0
- package/dist/integrations/remote-commands-store.js +1 -1
- package/dist/integrations/remote-devices-store.d.ts +1 -0
- package/dist/integrations/remote-devices-store.js +1 -1
- package/dist/integrations/remote-push-store.d.ts +1 -0
- package/dist/integrations/remote-push-store.js +1 -1
- package/dist/integrations/remote-run-events-store.d.ts +1 -0
- package/dist/integrations/remote-run-events-store.js +1 -1
- package/dist/integrations/scope-store.d.ts +1 -0
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/thread-mapping-store.d.ts +1 -0
- package/dist/integrations/thread-mapping-store.js +1 -1
- package/dist/integrations/usage-budget-store.d.ts +1 -0
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/jobs/background-automation-runner.js +111 -9
- package/dist/jobs/run-history.d.ts +1 -0
- package/dist/jobs/run-history.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +1 -0
- package/dist/jobs/scheduler-health.js +1 -1
- package/dist/mcp/approval-store.d.ts +1 -0
- package/dist/mcp/approval-store.js +1 -1
- package/dist/mcp/connect-store.d.ts +1 -0
- package/dist/mcp/connect-store.js +1 -1
- package/dist/mcp/oauth-store.d.ts +1 -0
- package/dist/mcp/oauth-store.js +1 -1
- package/dist/notifications/store.d.ts +1 -0
- package/dist/notifications/store.js +1 -1
- package/dist/oauth-tokens/store.d.ts +1 -0
- package/dist/oauth-tokens/store.js +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/store.d.ts +1 -0
- package/dist/progress/store.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
- package/dist/provider-api/corpus-jobs-store.js +1 -1
- package/dist/provider-api/custom-registry.d.ts +1 -0
- package/dist/provider-api/custom-registry.js +1 -1
- package/dist/provider-api/quota-governor.d.ts +1 -0
- package/dist/provider-api/quota-governor.js +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts +1 -0
- package/dist/provider-api/staged-datasets-store.js +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/resources/store.d.ts +1 -0
- package/dist/resources/store.js +1 -1
- package/dist/scripts/dev/index.js +15 -1
- package/dist/search/index.js +3 -0
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/secrets/storage.d.ts +1 -0
- package/dist/secrets/storage.js +1 -1
- package/dist/server/agent-chat-plugin.js +38 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-teams-run-queue.d.ts +1 -0
- package/dist/server/agent-teams-run-queue.js +1 -1
- package/dist/server/auth-marketing.js +3 -1
- package/dist/server/auth.d.ts +18 -1
- package/dist/server/auth.js +370 -154
- package/dist/server/embed-session.d.ts +1 -0
- package/dist/server/embed-session.js +1 -1
- package/dist/server/google-auth-plugin.js +3 -1
- package/dist/server/google-oauth.d.ts +10 -0
- package/dist/server/google-oauth.js +25 -1
- package/dist/server/identity-sso-store.d.ts +1 -0
- package/dist/server/identity-sso-store.js +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/onboarding-html.js +200 -31
- package/dist/server/poll.d.ts +2 -0
- package/dist/server/poll.js +19 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +5 -0
- package/dist/server/release-schema.d.ts +46 -0
- package/dist/server/release-schema.js +307 -0
- package/dist/settings/store.d.ts +1 -0
- package/dist/settings/store.js +1 -1
- package/dist/shared/environment-lanes.d.ts +28 -0
- package/dist/shared/environment-lanes.js +61 -0
- package/dist/sharing/actions/share-resource.js +22 -2
- package/dist/styles/agent-native.css +17 -15
- package/dist/triggers/routes.d.ts +11 -0
- package/dist/triggers/routes.js +10 -0
- package/dist/usage/alerts-store.d.ts +1 -0
- package/dist/usage/alerts-store.js +1 -1
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +1 -1
- package/docs/content/actions-access-control.mdx +136 -2
- package/docs/content/actions-agent-tools.mdx +101 -0
- package/docs/content/actions-defining.mdx +2 -2
- package/docs/content/audit-log.mdx +1 -1
- package/docs/content/authentication.mdx +1 -1
- package/docs/content/cloudflare.mdx +43 -0
- package/docs/content/creating-templates.mdx +1 -1
- package/docs/content/deploy-an-app.mdx +109 -0
- package/docs/content/deployment-environment-variables.mdx +101 -0
- package/docs/content/deployment.mdx +125 -792
- package/docs/content/docs-components.mdx +2 -2
- package/docs/content/environment-variables.mdx +41 -41
- package/docs/content/file-uploads.mdx +74 -40
- package/docs/content/harness-agents.mdx +2 -2
- package/docs/content/internationalization.mdx +61 -65
- package/docs/content/key-concepts.mdx +3 -3
- package/docs/content/multi-app-workspace.mdx +2 -2
- package/docs/content/netlify.mdx +47 -0
- package/docs/content/node-docker.mdx +138 -0
- package/docs/content/organizations-teams-permissions.mdx +5 -5
- package/docs/content/other-platforms.mdx +27 -0
- package/docs/content/ssr-caching.mdx +45 -0
- package/docs/content/template-assets-developers.mdx +2 -2
- package/docs/content/template-chat-developers.mdx +2 -2
- package/docs/content/template-content-developers.mdx +2 -2
- package/docs/content/{local-file-mode.mdx → template-content-local-files.mdx} +2 -1
- package/docs/content/template-content-sync.mdx +2 -2
- package/docs/content/toolkit-agent-ux.mdx +1 -1
- package/docs/content/toolkit-resources.mdx +2 -2
- package/docs/content/updating-ui-in-production.mdx +35 -0
- package/docs/content/vercel.mdx +38 -0
- package/docs/content/what-is-agent-native.mdx +1 -1
- package/docs/content/workspace-deployment.mdx +350 -0
- package/package.json +2 -2
- package/docs/content/agents.mdx +0 -9
- package/docs/content/database.mdx +0 -317
- package/docs/content/human-approval.mdx +0 -156
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { IconLogin2 } from "@tabler/icons-react";
|
|
3
|
+
import type { FormEvent } from "react";
|
|
4
|
+
|
|
5
|
+
import { Button } from "@/components/ui/button";
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogHeader,
|
|
11
|
+
DialogTitle,
|
|
12
|
+
} from "@/components/ui/dialog";
|
|
13
|
+
import { Input } from "@/components/ui/input";
|
|
14
|
+
import { Label } from "@/components/ui/label";
|
|
15
|
+
import { Separator } from "@/components/ui/separator";
|
|
16
|
+
|
|
17
|
+
export interface RequestDeckAccessDialogProps {
|
|
18
|
+
open: boolean;
|
|
19
|
+
onOpenChange: (open: boolean) => void;
|
|
20
|
+
signInHref: string;
|
|
21
|
+
email: string;
|
|
22
|
+
onEmailChange: (email: string) => void;
|
|
23
|
+
onSubmit: (event: FormEvent<HTMLFormElement>) => void;
|
|
24
|
+
isSubmitting: boolean;
|
|
25
|
+
error?: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function RequestDeckAccessDialog({
|
|
29
|
+
open,
|
|
30
|
+
onOpenChange,
|
|
31
|
+
signInHref,
|
|
32
|
+
email,
|
|
33
|
+
onEmailChange,
|
|
34
|
+
onSubmit,
|
|
35
|
+
isSubmitting,
|
|
36
|
+
error,
|
|
37
|
+
}: RequestDeckAccessDialogProps) {
|
|
38
|
+
const t = useT();
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
42
|
+
<DialogContent className="sm:max-w-md">
|
|
43
|
+
<DialogHeader>
|
|
44
|
+
<DialogTitle>{t("deckEditor.requestAccessDialogTitle")}</DialogTitle>
|
|
45
|
+
<DialogDescription>
|
|
46
|
+
{t("deckEditor.requestAccessDialogDescription")}
|
|
47
|
+
</DialogDescription>
|
|
48
|
+
</DialogHeader>
|
|
49
|
+
|
|
50
|
+
<div className="grid gap-4">
|
|
51
|
+
<Button asChild className="w-full gap-2">
|
|
52
|
+
<a href={signInHref}>
|
|
53
|
+
<IconLogin2 className="size-4" aria-hidden="true" />
|
|
54
|
+
{t("deckEditor.requestAccessSignIn")}
|
|
55
|
+
</a>
|
|
56
|
+
</Button>
|
|
57
|
+
|
|
58
|
+
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
|
59
|
+
<Separator className="flex-1" />
|
|
60
|
+
<span>{t("deckEditor.requestAccessOr")}</span>
|
|
61
|
+
<Separator className="flex-1" />
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<form className="grid gap-3" onSubmit={onSubmit}>
|
|
65
|
+
<div className="grid gap-2">
|
|
66
|
+
<Label htmlFor="private-deck-request-email">
|
|
67
|
+
{t("deckEditor.requestAccessEmailLabel")}
|
|
68
|
+
</Label>
|
|
69
|
+
<Input
|
|
70
|
+
id="private-deck-request-email"
|
|
71
|
+
type="email"
|
|
72
|
+
inputMode="email"
|
|
73
|
+
autoComplete="email"
|
|
74
|
+
required
|
|
75
|
+
value={email}
|
|
76
|
+
onChange={(event) => onEmailChange(event.target.value)}
|
|
77
|
+
placeholder={t("deckEditor.requestAccessEmailPlaceholder")}
|
|
78
|
+
aria-invalid={Boolean(error)}
|
|
79
|
+
/>
|
|
80
|
+
<p className="text-xs text-muted-foreground">
|
|
81
|
+
{t("deckEditor.requestAccessEmailHint")}
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{error ? (
|
|
86
|
+
<p className="text-sm text-destructive" role="alert">
|
|
87
|
+
{error}
|
|
88
|
+
</p>
|
|
89
|
+
) : null}
|
|
90
|
+
|
|
91
|
+
<Button type="submit" className="w-full" disabled={isSubmitting}>
|
|
92
|
+
{isSubmitting
|
|
93
|
+
? t("deckEditor.requestingAccess")
|
|
94
|
+
: t("deckEditor.requestAccessWithEmail")}
|
|
95
|
+
</Button>
|
|
96
|
+
</form>
|
|
97
|
+
</div>
|
|
98
|
+
</DialogContent>
|
|
99
|
+
</Dialog>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -12,6 +12,7 @@ export type DeckAccessStatusResponse = {
|
|
|
12
12
|
viewerName: string | null;
|
|
13
13
|
role: "owner" | "viewer" | "commenter" | "editor" | "admin" | null;
|
|
14
14
|
visibility: "private" | "org" | "public" | null;
|
|
15
|
+
accessRequestToken?: string;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export function useDeckAccessStatus(deckId?: string) {
|
|
@@ -44,8 +45,10 @@ function showActionError(message: string) {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
export function useRequestDeckAccess() {
|
|
47
|
-
return useActionMutation<
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
48
|
+
return useActionMutation<
|
|
49
|
+
RequestDeckAccessResult,
|
|
50
|
+
{ accessRequestToken?: string; deckId: string; requesterEmail?: string }
|
|
51
|
+
>("request-deck-access", {
|
|
52
|
+
onError: showActionError("Failed to request access"),
|
|
53
|
+
});
|
|
51
54
|
}
|
|
@@ -554,20 +554,16 @@ const messages = {
|
|
|
554
554
|
},
|
|
555
555
|
deckEditor: {
|
|
556
556
|
lookingForDeck: "Looking for this deck",
|
|
557
|
-
teamAccessCheckFailed: "Couldn't check team access",
|
|
558
557
|
joinTeamToOpen: "Join your team to open this deck",
|
|
559
558
|
deckUnavailable: "Deck unavailable",
|
|
560
559
|
checkingSharedAccess:
|
|
561
560
|
"Checking whether this presentation is shared with your account.",
|
|
562
|
-
verifySharedAccessFailed:
|
|
563
|
-
"We couldn't verify whether this presentation is shared with your account. Try again to reload team access and the deck.",
|
|
564
561
|
joinTeamDescription:
|
|
565
562
|
"This link points to a team presentation. Join the team shown above and the deck will open here automatically.",
|
|
566
563
|
deckUnavailableDescription:
|
|
567
564
|
"This deck may have been removed, or your account does not have access to it.",
|
|
568
|
-
privateDeckTitle: "
|
|
569
|
-
privateDeckDescription:
|
|
570
|
-
"Ask the owner for access to open this deck. They’ll be notified when you send a request.",
|
|
565
|
+
privateDeckTitle: "You don't have access to this deck",
|
|
566
|
+
privateDeckDescription: "Request access and the owner will be notified.",
|
|
571
567
|
signedInAs: "You're signed in as",
|
|
572
568
|
accessRequestSentDescription:
|
|
573
569
|
"The owner has been notified. You can open this deck once access is granted.",
|
|
@@ -577,6 +573,33 @@ const messages = {
|
|
|
577
573
|
accessRequestSent: "Request sent",
|
|
578
574
|
requestAccess: "Request access",
|
|
579
575
|
signInToRequestAccess: "Sign in to request access",
|
|
576
|
+
requestAccessDialogTitle: "Request access",
|
|
577
|
+
requestAccessDialogDescription:
|
|
578
|
+
"Sign in, or enter the email address the owner should share this deck with.",
|
|
579
|
+
requestAccessSignIn: "Sign in or sign up",
|
|
580
|
+
requestAccessOr: "or",
|
|
581
|
+
requestAccessEmailLabel: "Email address",
|
|
582
|
+
requestAccessEmailPlaceholder: "you@example.com",
|
|
583
|
+
requestAccessEmailHint:
|
|
584
|
+
"After access is granted, sign in with this email to view the deck.",
|
|
585
|
+
requestAccessWithEmail: "Request with email",
|
|
586
|
+
requestAccessEmailRequired: "Enter a valid email address.",
|
|
587
|
+
requestingAccess: "Requesting access...",
|
|
588
|
+
accessRequestSentWithEmail:
|
|
589
|
+
"The deck owner was asked to share this deck with {{email}}.",
|
|
590
|
+
accessRequestFailed: "Couldn't request access. Try again.",
|
|
591
|
+
accessApprovalTitle: "Access granted",
|
|
592
|
+
accessApprovalAlreadyTitle: "Access already granted",
|
|
593
|
+
accessApprovalMessage: "{{email}} can now open this deck.",
|
|
594
|
+
accessApprovalAlreadyMessage: "{{email}} already has access to this deck.",
|
|
595
|
+
accessApprovalErrorTitle: "Couldn't grant access",
|
|
596
|
+
accessApprovalInvalid: "This access request is invalid or expired.",
|
|
597
|
+
accessApprovalSignInTitle: "Sign in to allow access",
|
|
598
|
+
accessApprovalSignInMessage:
|
|
599
|
+
"Sign in as the deck owner or an admin to approve this request.",
|
|
600
|
+
accessApprovalOpenDeck: "Open deck",
|
|
601
|
+
accessApprovalSignIn: "Sign in",
|
|
602
|
+
accessApprovalLoading: "Granting access...",
|
|
580
603
|
backToDecks: "Back to Decks",
|
|
581
604
|
tryAgain: "Try again",
|
|
582
605
|
imageUploadFailed: "Image upload failed",
|
|
@@ -20,18 +20,14 @@ import {
|
|
|
20
20
|
useSensors,
|
|
21
21
|
DragEndEvent,
|
|
22
22
|
} from "@dnd-kit/core";
|
|
23
|
-
import {
|
|
24
|
-
IconAt,
|
|
25
|
-
IconArrowLeft,
|
|
26
|
-
IconLock,
|
|
27
|
-
IconLoader2,
|
|
28
|
-
IconLogin2,
|
|
29
|
-
IconRefresh,
|
|
30
|
-
IconUserPlus,
|
|
31
|
-
IconUsersGroup,
|
|
32
|
-
} from "@tabler/icons-react";
|
|
33
23
|
import { nanoid } from "nanoid";
|
|
34
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
useState,
|
|
26
|
+
useCallback,
|
|
27
|
+
useRef,
|
|
28
|
+
useEffect,
|
|
29
|
+
type FormEvent,
|
|
30
|
+
} from "react";
|
|
35
31
|
import {
|
|
36
32
|
useBlocker,
|
|
37
33
|
useNavigate,
|
|
@@ -51,6 +47,7 @@ import { canExportPptxFromServer } from "@/components/editor/ExportMenu";
|
|
|
51
47
|
import GeneratingSlidePreview from "@/components/editor/GeneratingSlidePreview";
|
|
52
48
|
import HistoryPanel from "@/components/editor/HistoryPanel";
|
|
53
49
|
import ImageGenPanel from "@/components/editor/ImageGenPanel";
|
|
50
|
+
import { MissingDeckAccessPane } from "@/components/editor/MissingDeckAccessPane";
|
|
54
51
|
import { QuestionFlow } from "@/components/editor/QuestionFlow";
|
|
55
52
|
import SlideEditor from "@/components/editor/SlideEditor";
|
|
56
53
|
import { TweaksPanel } from "@/components/editor/TweaksPanel";
|
|
@@ -78,7 +75,6 @@ import { useAgentGenerating } from "@/hooks/use-agent-generating";
|
|
|
78
75
|
import {
|
|
79
76
|
useDeckAccessStatus,
|
|
80
77
|
useRequestDeckAccess,
|
|
81
|
-
type DeckAccessStatusResponse,
|
|
82
78
|
} from "@/hooks/use-deck-access";
|
|
83
79
|
import { useDeckDesignSystem } from "@/hooks/use-deck-design-system";
|
|
84
80
|
import { useDeckPresence } from "@/hooks/use-deck-presence";
|
|
@@ -121,147 +117,9 @@ import { shortcutLabel } from "@/lib/utils";
|
|
|
121
117
|
|
|
122
118
|
type EditorSidePanel = "comments" | null;
|
|
123
119
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
accessStatusLoading,
|
|
128
|
-
hasTeamJoinOption,
|
|
129
|
-
orgLoading,
|
|
130
|
-
orgError,
|
|
131
|
-
requestAccessPending,
|
|
132
|
-
accessRequestSent,
|
|
133
|
-
accessRequestNotified,
|
|
134
|
-
signedIn,
|
|
135
|
-
viewerEmail,
|
|
136
|
-
refreshing,
|
|
137
|
-
onRequestAccess,
|
|
138
|
-
onSignIn,
|
|
139
|
-
onRetry,
|
|
140
|
-
onBack,
|
|
141
|
-
}: {
|
|
142
|
-
accessStatus: DeckAccessStatusResponse | null;
|
|
143
|
-
accessStatusError: boolean;
|
|
144
|
-
accessStatusLoading: boolean;
|
|
145
|
-
hasTeamJoinOption: boolean;
|
|
146
|
-
orgLoading: boolean;
|
|
147
|
-
orgError: boolean;
|
|
148
|
-
requestAccessPending: boolean;
|
|
149
|
-
accessRequestSent: boolean;
|
|
150
|
-
accessRequestNotified: boolean;
|
|
151
|
-
signedIn: boolean;
|
|
152
|
-
viewerEmail: string | null;
|
|
153
|
-
refreshing: boolean;
|
|
154
|
-
onRequestAccess: () => void;
|
|
155
|
-
onSignIn: () => void;
|
|
156
|
-
onRetry: () => void;
|
|
157
|
-
onBack: () => void;
|
|
158
|
-
}) {
|
|
159
|
-
const t = useT();
|
|
160
|
-
const privateDeck = Boolean(
|
|
161
|
-
accessStatus?.exists &&
|
|
162
|
-
!accessStatus.hasAccess &&
|
|
163
|
-
accessStatus.visibility === "private",
|
|
164
|
-
);
|
|
165
|
-
const checkingAccess = !privateDeck && (accessStatusLoading || orgLoading);
|
|
166
|
-
const accessCheckFailed = accessStatusError || orgError;
|
|
167
|
-
const Icon =
|
|
168
|
-
privateDeck || (!hasTeamJoinOption && !checkingAccess && !accessCheckFailed)
|
|
169
|
-
? IconLock
|
|
170
|
-
: IconUsersGroup;
|
|
171
|
-
const title = checkingAccess
|
|
172
|
-
? t("deckEditor.lookingForDeck")
|
|
173
|
-
: privateDeck
|
|
174
|
-
? t("deckEditor.privateDeckTitle")
|
|
175
|
-
: accessCheckFailed
|
|
176
|
-
? t("deckEditor.teamAccessCheckFailed")
|
|
177
|
-
: hasTeamJoinOption
|
|
178
|
-
? t("deckEditor.joinTeamToOpen")
|
|
179
|
-
: t("deckEditor.deckUnavailable");
|
|
180
|
-
const description = checkingAccess
|
|
181
|
-
? t("deckEditor.checkingSharedAccess")
|
|
182
|
-
: privateDeck
|
|
183
|
-
? t("deckEditor.privateDeckDescription")
|
|
184
|
-
: accessCheckFailed
|
|
185
|
-
? t("deckEditor.verifySharedAccessFailed")
|
|
186
|
-
: hasTeamJoinOption
|
|
187
|
-
? t("deckEditor.joinTeamDescription")
|
|
188
|
-
: t("deckEditor.deckUnavailableDescription");
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<div className="flex min-h-screen items-center justify-center bg-background px-4 py-10">
|
|
192
|
-
<div className="w-full max-w-md rounded-lg border border-border bg-card p-6 shadow-sm">
|
|
193
|
-
<div className="mb-4 flex items-center gap-3">
|
|
194
|
-
<div className="flex size-10 items-center justify-center rounded-md border border-border bg-background text-muted-foreground">
|
|
195
|
-
<Icon className="size-5" />
|
|
196
|
-
</div>
|
|
197
|
-
<div className="min-w-0">
|
|
198
|
-
<h1 className="text-base font-semibold text-foreground">{title}</h1>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
<p className="text-sm leading-6 text-muted-foreground">{description}</p>
|
|
202
|
-
{privateDeck && viewerEmail ? (
|
|
203
|
-
<div className="mt-4 flex items-center gap-2 rounded-md border border-border bg-muted/35 px-3 py-2 text-sm">
|
|
204
|
-
<IconAt className="size-4 shrink-0 text-muted-foreground" />
|
|
205
|
-
<span className="min-w-0 truncate text-muted-foreground">
|
|
206
|
-
{t("deckEditor.signedInAs")}{" "}
|
|
207
|
-
<span className="font-medium text-foreground">{viewerEmail}</span>
|
|
208
|
-
</span>
|
|
209
|
-
</div>
|
|
210
|
-
) : null}
|
|
211
|
-
{privateDeck && accessRequestSent ? (
|
|
212
|
-
<div className="mt-3 rounded-md border border-emerald-500/25 bg-emerald-500/10 px-3 py-2 text-sm text-emerald-700 dark:text-emerald-300">
|
|
213
|
-
{t(
|
|
214
|
-
accessRequestNotified
|
|
215
|
-
? "deckEditor.accessRequestSentDescription"
|
|
216
|
-
: "deckEditor.accessRequestRecordedDescription",
|
|
217
|
-
)}
|
|
218
|
-
</div>
|
|
219
|
-
) : null}
|
|
220
|
-
<div className="mt-5 flex flex-col gap-2">
|
|
221
|
-
{privateDeck ? (
|
|
222
|
-
<Button
|
|
223
|
-
type="button"
|
|
224
|
-
onClick={signedIn ? onRequestAccess : onSignIn}
|
|
225
|
-
disabled={requestAccessPending || accessRequestSent}
|
|
226
|
-
>
|
|
227
|
-
{requestAccessPending ? (
|
|
228
|
-
<IconLoader2 className="size-4 animate-spin" />
|
|
229
|
-
) : signedIn ? (
|
|
230
|
-
<IconUserPlus className="size-4" />
|
|
231
|
-
) : (
|
|
232
|
-
<IconLogin2 className="size-4" />
|
|
233
|
-
)}
|
|
234
|
-
{requestAccessPending
|
|
235
|
-
? t("deckEditor.requestAccessPending")
|
|
236
|
-
: accessRequestSent
|
|
237
|
-
? t("deckEditor.accessRequestSent")
|
|
238
|
-
: signedIn
|
|
239
|
-
? t("deckEditor.requestAccess")
|
|
240
|
-
: t("deckEditor.signInToRequestAccess")}
|
|
241
|
-
</Button>
|
|
242
|
-
) : null}
|
|
243
|
-
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
|
244
|
-
<Button type="button" variant="outline" onClick={onBack}>
|
|
245
|
-
<IconArrowLeft className="size-4" />
|
|
246
|
-
{t("deckEditor.backToDecks")}
|
|
247
|
-
</Button>
|
|
248
|
-
<Button
|
|
249
|
-
type="button"
|
|
250
|
-
variant={privateDeck ? "ghost" : "default"}
|
|
251
|
-
onClick={onRetry}
|
|
252
|
-
disabled={refreshing || checkingAccess}
|
|
253
|
-
>
|
|
254
|
-
<IconRefresh
|
|
255
|
-
className={refreshing ? "size-4 animate-spin" : "size-4"}
|
|
256
|
-
/>
|
|
257
|
-
{t("deckEditor.tryAgain")}
|
|
258
|
-
</Button>
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
);
|
|
264
|
-
}
|
|
120
|
+
type AccessRequestCapability =
|
|
121
|
+
| { available: true; token: string }
|
|
122
|
+
| { available: false };
|
|
265
123
|
|
|
266
124
|
// The Cmd/Ctrl+C-then-V slide-duplicate shortcut can only tell "this key
|
|
267
125
|
// event targets the slide rail/canvas" apart from "focus fell back to
|
|
@@ -390,6 +248,13 @@ export default function DeckEditor() {
|
|
|
390
248
|
string | null
|
|
391
249
|
>(null);
|
|
392
250
|
const [accessRequestNotified, setAccessRequestNotified] = useState(false);
|
|
251
|
+
const [requestAccessDialogOpen, setRequestAccessDialogOpen] = useState(false);
|
|
252
|
+
const [requesterEmail, setRequesterEmail] = useState("");
|
|
253
|
+
const [requestAccessDialogError, setRequestAccessDialogError] = useState<
|
|
254
|
+
string | null
|
|
255
|
+
>(null);
|
|
256
|
+
const [accessRequestRefreshPending, setAccessRequestRefreshPending] =
|
|
257
|
+
useState(false);
|
|
393
258
|
const [checkedDeckAccessKey, setCheckedDeckAccessKey] = useState<
|
|
394
259
|
string | null
|
|
395
260
|
>(null);
|
|
@@ -609,23 +474,122 @@ export default function DeckEditor() {
|
|
|
609
474
|
}, [refetchOrg, reloadDecks]);
|
|
610
475
|
|
|
611
476
|
const openSignIn = useCallback(() => {
|
|
612
|
-
window.location.href = buildSignInReturnHref(
|
|
613
|
-
|
|
477
|
+
window.location.href = buildSignInReturnHref({
|
|
478
|
+
returnTo: id ? `/deck/${encodeURIComponent(id)}` : "/",
|
|
479
|
+
});
|
|
480
|
+
}, [id]);
|
|
614
481
|
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
{
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
482
|
+
const getFreshAccessRequestCapability =
|
|
483
|
+
useCallback(async (): Promise<AccessRequestCapability> => {
|
|
484
|
+
setAccessRequestRefreshPending(true);
|
|
485
|
+
try {
|
|
486
|
+
const result = await deckAccessStatusQuery.refetch();
|
|
487
|
+
const token = result.isSuccess
|
|
488
|
+
? result.data?.accessRequestToken
|
|
489
|
+
: undefined;
|
|
490
|
+
return token ? { available: true, token } : { available: false };
|
|
491
|
+
} catch (error) {
|
|
492
|
+
console.warn(
|
|
493
|
+
"[slides] deck access request capability refresh failed:",
|
|
494
|
+
error,
|
|
495
|
+
);
|
|
496
|
+
return { available: false };
|
|
497
|
+
} finally {
|
|
498
|
+
setAccessRequestRefreshPending(false);
|
|
499
|
+
}
|
|
500
|
+
}, [deckAccessStatusQuery]);
|
|
501
|
+
|
|
502
|
+
const submitDeckAccessRequest = useCallback(
|
|
503
|
+
async (guestEmail?: string) => {
|
|
504
|
+
if (!id) return;
|
|
505
|
+
const normalizedGuestEmail = guestEmail?.trim() || undefined;
|
|
506
|
+
setRequestAccessDialogError(null);
|
|
507
|
+
const accessRequestCapability = normalizedGuestEmail
|
|
508
|
+
? await getFreshAccessRequestCapability()
|
|
509
|
+
: { available: false as const };
|
|
510
|
+
if (normalizedGuestEmail && !accessRequestCapability.available) {
|
|
511
|
+
setRequestAccessDialogError(t("deckEditor.accessRequestFailed"));
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const accessRequestToken =
|
|
515
|
+
normalizedGuestEmail && accessRequestCapability.available
|
|
516
|
+
? accessRequestCapability.token
|
|
517
|
+
: undefined;
|
|
518
|
+
requestDeckAccessMutation.mutate(
|
|
519
|
+
{
|
|
520
|
+
deckId: id,
|
|
521
|
+
...(accessRequestToken ? { accessRequestToken } : {}),
|
|
522
|
+
...(normalizedGuestEmail
|
|
523
|
+
? { requesterEmail: normalizedGuestEmail }
|
|
524
|
+
: {}),
|
|
625
525
|
},
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
526
|
+
{
|
|
527
|
+
onSuccess: (result) => {
|
|
528
|
+
setAccessRequestSentDeckId(id);
|
|
529
|
+
setAccessRequestNotified(result.notifiedOwner);
|
|
530
|
+
if (normalizedGuestEmail) setRequestAccessDialogOpen(false);
|
|
531
|
+
toast.success(
|
|
532
|
+
normalizedGuestEmail
|
|
533
|
+
? t("deckEditor.accessRequestSentWithEmail", {
|
|
534
|
+
email: normalizedGuestEmail,
|
|
535
|
+
})
|
|
536
|
+
: result.message,
|
|
537
|
+
);
|
|
538
|
+
if (result.alreadyHasAccess) void reloadDecks();
|
|
539
|
+
},
|
|
540
|
+
onError: (error: unknown) => {
|
|
541
|
+
if (!normalizedGuestEmail) return;
|
|
542
|
+
setRequestAccessDialogError(
|
|
543
|
+
error instanceof Error && error.message
|
|
544
|
+
? error.message.replace(/^Action [\w-]+ failed:\s*/, "")
|
|
545
|
+
: t("deckEditor.accessRequestFailed"),
|
|
546
|
+
);
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
);
|
|
550
|
+
},
|
|
551
|
+
[
|
|
552
|
+
getFreshAccessRequestCapability,
|
|
553
|
+
id,
|
|
554
|
+
reloadDecks,
|
|
555
|
+
requestDeckAccessMutation,
|
|
556
|
+
t,
|
|
557
|
+
],
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
const requestDeckAccess = useCallback(() => {
|
|
561
|
+
void submitDeckAccessRequest();
|
|
562
|
+
}, [submitDeckAccessRequest]);
|
|
563
|
+
|
|
564
|
+
const submitGuestAccessRequest = useCallback(
|
|
565
|
+
(event: FormEvent<HTMLFormElement>) => {
|
|
566
|
+
event.preventDefault();
|
|
567
|
+
const email = requesterEmail.trim();
|
|
568
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
569
|
+
setRequestAccessDialogError(t("deckEditor.requestAccessEmailRequired"));
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
void submitDeckAccessRequest(email);
|
|
573
|
+
},
|
|
574
|
+
[requesterEmail, submitDeckAccessRequest, t],
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
const requestAccessDialogOpenChange = useCallback(
|
|
578
|
+
(open: boolean) => {
|
|
579
|
+
setRequestAccessDialogOpen(open);
|
|
580
|
+
if (!open) {
|
|
581
|
+
setRequestAccessDialogError(null);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
setRequestAccessDialogError(null);
|
|
585
|
+
void getFreshAccessRequestCapability().then((capability) => {
|
|
586
|
+
if (!capability.available) {
|
|
587
|
+
setRequestAccessDialogError(t("deckEditor.accessRequestFailed"));
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
},
|
|
591
|
+
[getFreshAccessRequestCapability, t],
|
|
592
|
+
);
|
|
629
593
|
|
|
630
594
|
useEffect(() => {
|
|
631
595
|
if (accessRequestSentDeckId && accessRequestSentDeckId !== id) {
|
|
@@ -1412,13 +1376,27 @@ export default function DeckEditor() {
|
|
|
1412
1376
|
hasTeamJoinOption={hasTeamJoinOption}
|
|
1413
1377
|
orgLoading={orgLoading}
|
|
1414
1378
|
orgError={orgError || loadError}
|
|
1415
|
-
requestAccessPending={
|
|
1379
|
+
requestAccessPending={
|
|
1380
|
+
requestDeckAccessMutation.isPending || accessRequestRefreshPending
|
|
1381
|
+
}
|
|
1416
1382
|
accessRequestSent={accessRequestSentDeckId === id}
|
|
1417
1383
|
accessRequestNotified={accessRequestNotified}
|
|
1384
|
+
requestAccessDialogOpen={requestAccessDialogOpen}
|
|
1385
|
+
requesterEmail={requesterEmail}
|
|
1386
|
+
requestAccessDialogError={requestAccessDialogError}
|
|
1418
1387
|
signedIn={Boolean(session) && !sessionLoading}
|
|
1388
|
+
signInHref={buildSignInReturnHref({
|
|
1389
|
+
returnTo: id ? `/deck/${encodeURIComponent(id)}` : "/",
|
|
1390
|
+
})}
|
|
1419
1391
|
viewerEmail={session?.email ?? deckAccessStatus?.viewerEmail ?? null}
|
|
1420
1392
|
refreshing={retryingMissingDeck}
|
|
1421
1393
|
onRequestAccess={requestDeckAccess}
|
|
1394
|
+
onRequestAccessDialogOpenChange={requestAccessDialogOpenChange}
|
|
1395
|
+
onRequesterEmailChange={(email) => {
|
|
1396
|
+
setRequesterEmail(email);
|
|
1397
|
+
setRequestAccessDialogError(null);
|
|
1398
|
+
}}
|
|
1399
|
+
onSubmitGuestAccessRequest={submitGuestAccessRequest}
|
|
1422
1400
|
onSignIn={openSignIn}
|
|
1423
1401
|
onRetry={() => void retryOpenDeck()}
|
|
1424
1402
|
onBack={() => navigate("/")}
|