@agent-native/core 0.151.2 → 0.152.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 +1 -1
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/analytics/actions/bigquery-query.ts +21 -0
- package/corpus/templates/analytics/app/components/ConnectionTestStatus.tsx +65 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +3 -3
- package/corpus/templates/analytics/app/pages/DataSources.tsx +15 -37
- package/corpus/templates/analytics/app/root.tsx +0 -1
- package/corpus/templates/analytics/changelog/2026-08-11-analytics-custom-blocks-keep-loading-with-legacy-bigquery-action.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-11-analytics-routes-company-knowledge-and-slack-context-questio.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/analytics/public/manifest.json +0 -1
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +5 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/assets/app/root.tsx +0 -1
- package/corpus/templates/assets/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/assets/public/manifest.json +0 -1
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/brain/app/root.tsx +0 -1
- package/corpus/templates/brain/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/brain/public/manifest.json +0 -1
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +0 -53
- package/corpus/templates/calendar/app/i18n-data.ts +0 -80
- package/corpus/templates/calendar/app/root.tsx +0 -1
- package/corpus/templates/calendar/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-11-google-calendar-connection-buttons-now-open-the-sign-in-flow.md +6 -0
- package/corpus/templates/calendar/public/manifest.json +0 -1
- package/corpus/templates/calendar/server/plugins/auth.ts +0 -10
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/chat/app/root.tsx +0 -1
- package/corpus/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/chat/public/manifest.json +0 -1
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +1 -1
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +6 -0
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +20 -3
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -4
- package/corpus/templates/clips/app/root.tsx +0 -1
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -3
- package/corpus/templates/clips/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-11-clips-desktop-settings-are-now-easier-to-scan-with-a-wider-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-11-google-calendar-connections-from-meetings-now-open-directly.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-11-recording-viewers-can-comment-and-react.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-11-system-audio-recording-now-lives-inside-the-microphone-menu-.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-11-timestamped-comments-stay-on-the-video-for-three-seconds-wh.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +773 -1001
- package/corpus/templates/clips/desktop/src/components/MediaDeviceRow.tsx +15 -27
- package/corpus/templates/clips/desktop/src/styles.css +364 -5
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +1 -1
- package/corpus/templates/clips/public/manifest.json +0 -1
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/content/AGENTS.md +3 -0
- package/corpus/templates/content/actions/resolve-content-landing.ts +120 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +196 -30
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +9 -0
- package/corpus/templates/content/app/i18n-data.ts +58 -0
- package/corpus/templates/content/app/lib/content-landing.ts +22 -0
- package/corpus/templates/content/app/root.tsx +0 -1
- package/corpus/templates/content/app/routes/_app._index.tsx +36 -26
- package/corpus/templates/content/changelog/2026-08-03-choose-text-or-a-heading-from-one-compact-formatting-control.md +6 -0
- package/corpus/templates/content/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/content/changelog/2026-08-11-content-opens-your-last-page-on-return-and-gives-new-users-a.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +7 -1
- package/corpus/templates/content/docs/solutions/evidence/content-text-selector/README.md +26 -0
- package/corpus/templates/content/parity/matrix.md +1 -0
- package/corpus/templates/content/parity/matrix.ts +22 -0
- package/corpus/templates/content/public/manifest.json +0 -1
- package/corpus/templates/content/shared/content-landing.ts +17 -0
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/crm/app/root.tsx +0 -1
- package/corpus/templates/crm/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/crm/public/manifest.json +0 -1
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/design/app/i18n/en-US.ts +5 -0
- package/corpus/templates/design/app/root.tsx +0 -1
- package/corpus/templates/design/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/design/changelog/2026-08-11-design-sharing-now-identifies-viewers-who-can-add-review-com.md +6 -0
- package/corpus/templates/design/public/manifest.json +0 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/dispatch/AGENTS.md +9 -0
- package/corpus/templates/dispatch/actions/list-dispatch-usage-metrics.ts +5 -19
- package/corpus/templates/dispatch/actions/view-screen.ts +10 -3
- package/corpus/templates/dispatch/app/root.tsx +0 -1
- package/corpus/templates/dispatch/app/routes/settings.tsx +13 -1
- package/corpus/templates/dispatch/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-clicking-the-dispatch-logo-returns-to-the-overview-page.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-links-to-itself-from-the-app-switcher.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-settings-now-link-directly-to-admin.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-shows-usage-trends-recent-prompts-and-an-agent-revi.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-11-human-friendly-app-names.md +6 -0
- package/corpus/templates/dispatch/public/manifest.json +0 -1
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +432 -158
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +204 -123
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +1 -0
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/factory/app/root.tsx +0 -1
- package/corpus/templates/factory/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/factory/public/manifest.json +0 -1
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/forms/app/root.tsx +0 -1
- package/corpus/templates/forms/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/forms/public/manifest.json +0 -1
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/mail/app/root.tsx +0 -1
- package/corpus/templates/mail/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/mail/changelog/2026-08-11-google-sign-in-now-opens-the-gmail-connection-flow-directly.md +6 -0
- package/corpus/templates/mail/public/manifest.json +0 -1
- package/corpus/templates/mail/server/plugins/auth.ts +0 -10
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/plan/app/i18n/en-US.ts +2 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +6 -0
- package/corpus/templates/plan/app/root.tsx +0 -1
- package/corpus/templates/plan/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/plan/changelog/2026-08-11-plan-sharing-now-identifies-viewers-who-can-add-comments.md +6 -0
- package/corpus/templates/plan/public/manifest.json +0 -1
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +6 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +2 -0
- package/corpus/templates/slides/app/root.tsx +0 -1
- package/corpus/templates/slides/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-share-dialog-uses-commenter-terminology.md +6 -0
- package/corpus/templates/slides/public/manifest.json +0 -1
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +1 -1
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/tasks/app/root.tsx +0 -1
- package/corpus/templates/tasks/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/corpus/templates/tasks/public/manifest.json +0 -1
- package/dist/agent/production-agent.d.ts +8 -0
- package/dist/agent/production-agent.js +67 -22
- package/dist/agent/run-manager.d.ts +7 -0
- package/dist/agent/run-manager.js +46 -3
- package/dist/agent/tool-approval-migrations.d.ts +40 -0
- package/dist/agent/tool-approval-migrations.js +51 -0
- package/dist/agent/tool-approval-store.js +5 -20
- package/dist/cli/templates-meta.js +2 -2
- package/dist/client/AgentPanel.js +10 -1
- package/dist/client/AssistantChat.d.ts +3 -0
- package/dist/client/AssistantChat.js +151 -141
- package/dist/client/agent-page/AgentTabsPage.js +2 -2
- package/dist/client/chat/attachment-adapters.js +8 -2
- package/dist/client/chat/tool-call-display.d.ts +1 -0
- package/dist/client/chat/tool-call-display.js +3 -1
- package/dist/client/chat-first.js +11 -5
- package/dist/client/guided-questions.d.ts +15 -1
- package/dist/client/guided-questions.js +33 -15
- package/dist/client/hooks/index.d.ts +1 -1
- package/dist/client/hooks/index.js +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +3 -1
- package/dist/client/org/OrgSwitcher.js +22 -16
- package/dist/client/org/WorkspaceNotice.js +3 -1
- package/dist/client/resources/index.d.ts +1 -1
- package/dist/client/resources/index.js +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.js +14 -0
- package/dist/client/settings/AccountSettingsCard.js +8 -4
- package/dist/client/settings/SettingsPanel.js +46 -13
- package/dist/client/settings/SettingsTabsPage.js +8 -3
- package/dist/client/sharing/ShareButton.d.ts +7 -1
- package/dist/client/sharing/ShareButton.js +14 -7
- package/dist/client/sharing/ShareDialog.js +5 -1
- package/dist/client/sharing/useShareButtonController.d.ts +4 -0
- package/dist/client/sharing/useShareButtonController.js +15 -0
- package/dist/client/sharing/useShareDialogController.d.ts +7 -0
- package/dist/client/sharing/useShareDialogController.js +14 -0
- package/dist/client/sse-event-processor.js +37 -0
- package/dist/client/use-session.d.ts +2 -0
- package/dist/client/use-session.js +69 -5
- package/dist/deploy/build.js +1 -1
- package/dist/file-upload/pre-upload-attachments.d.ts +3 -4
- package/dist/file-upload/pre-upload-attachments.js +65 -17
- package/dist/ingestion/index.d.ts +1 -0
- package/dist/ingestion/index.js +1 -0
- package/dist/ingestion/office.d.ts +3 -3
- package/dist/ingestion/office.js +24 -2
- package/dist/ingestion/spreadsheet.d.ts +41 -0
- package/dist/ingestion/spreadsheet.js +172 -0
- package/dist/integrations/adapters/slack.js +7 -3
- package/dist/integrations/webhook-handler.js +11 -3
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.js +3 -0
- package/dist/mcp/embed-app.js +20 -9
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/oauth-tokens/migrations.d.ts +8 -0
- package/dist/oauth-tokens/migrations.js +36 -0
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/workspace-url.d.ts +8 -0
- package/dist/org/workspace-url.js +26 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat/context-tools.js +27 -6
- package/dist/server/agent-chat-plugin.js +16 -8
- package/dist/server/auth.d.ts +0 -11
- package/dist/server/auth.js +37 -20
- package/dist/server/better-auth-migrations.js +23 -0
- package/dist/server/email-template.d.ts +5 -0
- package/dist/server/email-template.js +9 -0
- package/dist/server/embed-route.js +17 -5
- package/dist/server/identity-sso-store.d.ts +40 -66
- package/dist/server/identity-sso-store.js +187 -150
- package/dist/server/identity-sso.d.ts +17 -73
- package/dist/server/identity-sso.js +294 -297
- package/dist/server/onboarding-html.d.ts +0 -12
- package/dist/server/onboarding-html.js +46 -269
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +8 -0
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/workspace-app-id.d.ts +2 -0
- package/dist/shared/workspace-app-id.js +10 -0
- package/dist/sharing/actions/share-resource.d.ts +1 -0
- package/dist/sharing/actions/share-resource.js +20 -5
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/dist/templates/chat/app/root.tsx +0 -1
- package/dist/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/dist/templates/chat/public/manifest.json +0 -1
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/dist/templates/default/app/root.tsx +0 -1
- package/dist/templates/default/public/manifest.json +0 -1
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/docs/content/cross-app-sso.mdx +85 -27
- package/docs/content/template-mail.mdx +0 -6
- package/package.json +4 -3
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/src/templates/chat/app/root.tsx +0 -1
- package/src/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
- package/src/templates/chat/public/manifest.json +0 -1
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/src/templates/default/app/root.tsx +0 -1
- package/src/templates/default/public/manifest.json +0 -1
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
- package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +0 -6
- package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +0 -51
- package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +0 -6
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
2
|
import {
|
|
3
3
|
IconBold,
|
|
4
|
+
IconCheck,
|
|
5
|
+
IconChevronDown,
|
|
4
6
|
IconItalic,
|
|
5
7
|
IconStrikethrough,
|
|
6
8
|
IconCode,
|
|
7
9
|
IconLink,
|
|
8
10
|
IconMessageCircle,
|
|
9
|
-
IconH1,
|
|
10
|
-
IconH2,
|
|
11
|
-
IconH3,
|
|
12
|
-
IconH4,
|
|
13
11
|
} from "@tabler/icons-react";
|
|
14
12
|
import {
|
|
15
13
|
NodeSelection,
|
|
@@ -20,8 +18,13 @@ import {
|
|
|
20
18
|
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
21
19
|
import type { Editor } from "@tiptap/react";
|
|
22
20
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
23
|
-
import { useCallback, useEffect, useState } from "react";
|
|
21
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
24
22
|
|
|
23
|
+
import {
|
|
24
|
+
Popover,
|
|
25
|
+
PopoverContent,
|
|
26
|
+
PopoverTrigger,
|
|
27
|
+
} from "@/components/ui/popover";
|
|
25
28
|
import {
|
|
26
29
|
Tooltip,
|
|
27
30
|
TooltipContent,
|
|
@@ -56,6 +59,15 @@ type SelectionFillRange = {
|
|
|
56
59
|
to: number;
|
|
57
60
|
};
|
|
58
61
|
|
|
62
|
+
type TextStyle = "paragraph" | 1 | 2 | 3 | 4 | 5 | 6;
|
|
63
|
+
|
|
64
|
+
function activeTextStyle(editor: Editor): TextStyle {
|
|
65
|
+
for (const level of [1, 2, 3, 4, 5, 6] as const) {
|
|
66
|
+
if (editor.isActive("heading", { level })) return level;
|
|
67
|
+
}
|
|
68
|
+
return "paragraph";
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
const selectionFillPluginKey = new PluginKey<SelectionFillRange | null>(
|
|
60
72
|
"contentSelectionFill",
|
|
61
73
|
);
|
|
@@ -106,6 +118,86 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
106
118
|
const t = useT();
|
|
107
119
|
const [showLinkInput, setShowLinkInput] = useState(false);
|
|
108
120
|
const [linkUrl, setLinkUrl] = useState("");
|
|
121
|
+
const [textStyleOpen, setTextStyleOpen] = useState(false);
|
|
122
|
+
const textStyleSelection = useRef<{ from: number; to: number } | null>(null);
|
|
123
|
+
const textStyleApplied = useRef(false);
|
|
124
|
+
const restoreEditorFocusOnClose = useRef(false);
|
|
125
|
+
const [textStyle, setTextStyle] = useState<TextStyle>(() =>
|
|
126
|
+
activeTextStyle(editor),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const syncTextStyle = () => {
|
|
131
|
+
setTextStyle(activeTextStyle(editor));
|
|
132
|
+
const { from, to } = editor.state.selection;
|
|
133
|
+
if (from !== to) textStyleSelection.current = { from, to };
|
|
134
|
+
};
|
|
135
|
+
editor.on("selectionUpdate", syncTextStyle);
|
|
136
|
+
editor.on("transaction", syncTextStyle);
|
|
137
|
+
syncTextStyle();
|
|
138
|
+
return () => {
|
|
139
|
+
editor.off("selectionUpdate", syncTextStyle);
|
|
140
|
+
editor.off("transaction", syncTextStyle);
|
|
141
|
+
};
|
|
142
|
+
}, [editor]);
|
|
143
|
+
|
|
144
|
+
const textStyles = [
|
|
145
|
+
{
|
|
146
|
+
value: "paragraph" as const,
|
|
147
|
+
shortLabel: t("editor.slash.text"),
|
|
148
|
+
menuLabel: "T",
|
|
149
|
+
label: t("editor.slash.text"),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
value: 1 as const,
|
|
153
|
+
shortLabel: "H1",
|
|
154
|
+
menuLabel: "H1",
|
|
155
|
+
label: t("editor.heading1"),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
value: 2 as const,
|
|
159
|
+
shortLabel: "H2",
|
|
160
|
+
menuLabel: "H2",
|
|
161
|
+
label: t("editor.heading2"),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
value: 3 as const,
|
|
165
|
+
shortLabel: "H3",
|
|
166
|
+
menuLabel: "H3",
|
|
167
|
+
label: t("editor.heading3"),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
value: 4 as const,
|
|
171
|
+
shortLabel: "H4",
|
|
172
|
+
menuLabel: "H4",
|
|
173
|
+
label: t("editor.heading4"),
|
|
174
|
+
},
|
|
175
|
+
];
|
|
176
|
+
const selectedTextStyle =
|
|
177
|
+
textStyles.find((style) => style.value === textStyle) ??
|
|
178
|
+
(typeof textStyle === "number"
|
|
179
|
+
? {
|
|
180
|
+
value: textStyle,
|
|
181
|
+
shortLabel: `H${textStyle}`,
|
|
182
|
+
menuLabel: `H${textStyle}`,
|
|
183
|
+
label: textStyle === 5 ? t("editor.heading5") : t("editor.heading6"),
|
|
184
|
+
}
|
|
185
|
+
: textStyles[0]);
|
|
186
|
+
|
|
187
|
+
const applyTextStyle = (style: TextStyle) => {
|
|
188
|
+
const chain = editor.chain();
|
|
189
|
+
if (textStyleSelection.current) {
|
|
190
|
+
chain.setTextSelection(textStyleSelection.current);
|
|
191
|
+
}
|
|
192
|
+
if (style === "paragraph") {
|
|
193
|
+
chain.setParagraph().focus().run();
|
|
194
|
+
} else {
|
|
195
|
+
chain.setHeading({ level: style }).focus().run();
|
|
196
|
+
}
|
|
197
|
+
textStyleApplied.current = true;
|
|
198
|
+
setTextStyle(style);
|
|
199
|
+
setTextStyleOpen(false);
|
|
200
|
+
};
|
|
109
201
|
|
|
110
202
|
const openLinkInput = useCallback(() => {
|
|
111
203
|
setLinkUrl(editor.getAttributes("link").href || "");
|
|
@@ -251,30 +343,7 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
251
343
|
isActive: () => editor.isActive("code"),
|
|
252
344
|
},
|
|
253
345
|
{ type: "divider" as const },
|
|
254
|
-
{
|
|
255
|
-
icon: IconH1,
|
|
256
|
-
title: t("editor.heading1"),
|
|
257
|
-
action: () => editor.chain().focus().toggleHeading({ level: 1 }).run(),
|
|
258
|
-
isActive: () => editor.isActive("heading", { level: 1 }),
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
icon: IconH2,
|
|
262
|
-
title: t("editor.heading2"),
|
|
263
|
-
action: () => editor.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
264
|
-
isActive: () => editor.isActive("heading", { level: 2 }),
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
icon: IconH3,
|
|
268
|
-
title: t("editor.heading3"),
|
|
269
|
-
action: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
270
|
-
isActive: () => editor.isActive("heading", { level: 3 }),
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
icon: IconH4,
|
|
274
|
-
title: t("editor.heading4"),
|
|
275
|
-
action: () => editor.chain().focus().toggleHeading({ level: 4 }).run(),
|
|
276
|
-
isActive: () => editor.isActive("heading", { level: 4 }),
|
|
277
|
-
},
|
|
346
|
+
{ type: "text-style" as const },
|
|
278
347
|
{ type: "divider" as const },
|
|
279
348
|
{
|
|
280
349
|
icon: IconLink,
|
|
@@ -354,7 +423,7 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
354
423
|
</div>
|
|
355
424
|
) : (
|
|
356
425
|
<div
|
|
357
|
-
className="flex items-center gap-0.5
|
|
426
|
+
className="flex max-w-[calc(100vw-1rem)] items-center gap-0.5"
|
|
358
427
|
onMouseDown={(e) => e.preventDefault()}
|
|
359
428
|
>
|
|
360
429
|
{items.map((item, i) => {
|
|
@@ -363,6 +432,103 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
363
432
|
<div key={`d-${i}`} className="w-px h-5 bg-border mx-0.5" />
|
|
364
433
|
);
|
|
365
434
|
}
|
|
435
|
+
if ("type" in item && item.type === "text-style") {
|
|
436
|
+
return (
|
|
437
|
+
<Popover
|
|
438
|
+
key="text-style"
|
|
439
|
+
open={textStyleOpen}
|
|
440
|
+
onOpenChange={(open) => {
|
|
441
|
+
if (open) {
|
|
442
|
+
textStyleApplied.current = false;
|
|
443
|
+
restoreEditorFocusOnClose.current = false;
|
|
444
|
+
const { from, to } = editor.state.selection;
|
|
445
|
+
if (from !== to)
|
|
446
|
+
textStyleSelection.current = { from, to };
|
|
447
|
+
}
|
|
448
|
+
setTextStyleOpen(open);
|
|
449
|
+
}}
|
|
450
|
+
>
|
|
451
|
+
<PopoverTrigger asChild>
|
|
452
|
+
<button
|
|
453
|
+
type="button"
|
|
454
|
+
aria-label={`${t("editor.slash.turnInto")}: ${selectedTextStyle.label}`}
|
|
455
|
+
className="flex h-8 min-w-14 items-center justify-between gap-1 rounded px-2 text-sm font-medium text-popover-foreground/85 hover:bg-accent hover:text-accent-foreground"
|
|
456
|
+
>
|
|
457
|
+
<span>{selectedTextStyle.shortLabel}</span>
|
|
458
|
+
<IconChevronDown size={14} strokeWidth={2} />
|
|
459
|
+
</button>
|
|
460
|
+
</PopoverTrigger>
|
|
461
|
+
<PopoverContent
|
|
462
|
+
portalled={false}
|
|
463
|
+
align="start"
|
|
464
|
+
sideOffset={24}
|
|
465
|
+
className="w-44 p-1"
|
|
466
|
+
onEscapeKeyDown={() => {
|
|
467
|
+
restoreEditorFocusOnClose.current = true;
|
|
468
|
+
window.setTimeout(() => editor.commands.focus(), 0);
|
|
469
|
+
}}
|
|
470
|
+
onCloseAutoFocus={(event) => {
|
|
471
|
+
if (
|
|
472
|
+
textStyleApplied.current ||
|
|
473
|
+
restoreEditorFocusOnClose.current
|
|
474
|
+
) {
|
|
475
|
+
event.preventDefault();
|
|
476
|
+
}
|
|
477
|
+
if (restoreEditorFocusOnClose.current) {
|
|
478
|
+
editor.commands.focus();
|
|
479
|
+
}
|
|
480
|
+
textStyleApplied.current = false;
|
|
481
|
+
restoreEditorFocusOnClose.current = false;
|
|
482
|
+
}}
|
|
483
|
+
>
|
|
484
|
+
<div className="px-2 py-1 text-xs font-medium text-muted-foreground">
|
|
485
|
+
{t("editor.slash.turnInto")}
|
|
486
|
+
</div>
|
|
487
|
+
<div
|
|
488
|
+
role="menu"
|
|
489
|
+
aria-label={t("editor.slash.turnInto")}
|
|
490
|
+
className="flex flex-col gap-0.5"
|
|
491
|
+
>
|
|
492
|
+
{textStyles.map((style) => {
|
|
493
|
+
const isSelected = style.value === textStyle;
|
|
494
|
+
return (
|
|
495
|
+
<button
|
|
496
|
+
key={style.value}
|
|
497
|
+
type="button"
|
|
498
|
+
role="menuitemradio"
|
|
499
|
+
aria-checked={isSelected}
|
|
500
|
+
onPointerDown={(event) => {
|
|
501
|
+
event.preventDefault();
|
|
502
|
+
event.stopPropagation();
|
|
503
|
+
applyTextStyle(style.value);
|
|
504
|
+
}}
|
|
505
|
+
onClick={(event) => {
|
|
506
|
+
if (event.detail === 0) {
|
|
507
|
+
applyTextStyle(style.value);
|
|
508
|
+
}
|
|
509
|
+
}}
|
|
510
|
+
className={cn(
|
|
511
|
+
"flex h-8 w-full items-center gap-2 rounded px-2 text-left text-sm",
|
|
512
|
+
isSelected
|
|
513
|
+
? "bg-accent text-accent-foreground"
|
|
514
|
+
: "text-popover-foreground hover:bg-accent hover:text-accent-foreground",
|
|
515
|
+
)}
|
|
516
|
+
>
|
|
517
|
+
<span className="w-6 shrink-0 text-xs font-semibold text-muted-foreground">
|
|
518
|
+
{style.menuLabel}
|
|
519
|
+
</span>
|
|
520
|
+
<span className="flex-1">{style.label}</span>
|
|
521
|
+
{isSelected ? (
|
|
522
|
+
<IconCheck size={15} strokeWidth={2.25} />
|
|
523
|
+
) : null}
|
|
524
|
+
</button>
|
|
525
|
+
);
|
|
526
|
+
})}
|
|
527
|
+
</div>
|
|
528
|
+
</PopoverContent>
|
|
529
|
+
</Popover>
|
|
530
|
+
);
|
|
531
|
+
}
|
|
366
532
|
const {
|
|
367
533
|
icon: Icon,
|
|
368
534
|
title,
|
|
@@ -78,6 +78,7 @@ import {
|
|
|
78
78
|
useDocumentSyncStatus,
|
|
79
79
|
usePushDocumentToNotion,
|
|
80
80
|
} from "@/hooks/use-notion";
|
|
81
|
+
import { rememberContentLandingDocument } from "@/lib/content-landing";
|
|
81
82
|
import {
|
|
82
83
|
canWriteLinkedLocalSource,
|
|
83
84
|
writeDocumentToLinkedLocalSource,
|
|
@@ -538,6 +539,14 @@ function DocumentEditorBody({
|
|
|
538
539
|
databaseDocumentId,
|
|
539
540
|
}: DocumentEditorBodyProps) {
|
|
540
541
|
const t = useT();
|
|
542
|
+
useEffect(() => {
|
|
543
|
+
void rememberContentLandingDocument(documentId).catch((error) => {
|
|
544
|
+
toast.error(t("landing.saveFailed"), {
|
|
545
|
+
description:
|
|
546
|
+
error instanceof Error ? error.message : t("empty.genericError"),
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
}, [documentId, t]);
|
|
541
550
|
const updateDocument = useUpdateDocument();
|
|
542
551
|
const createDatabase = useCreateContentDatabase(documentId);
|
|
543
552
|
const deleteContentDatabase = useDeleteContentDatabase();
|
|
@@ -3041,6 +3041,11 @@ const enUS = {
|
|
|
3041
3041
|
agent: "Agent",
|
|
3042
3042
|
settings: "Settings",
|
|
3043
3043
|
},
|
|
3044
|
+
landing: {
|
|
3045
|
+
previousPageUnavailable:
|
|
3046
|
+
"Your previous page is no longer available, so we opened Welcome.",
|
|
3047
|
+
saveFailed: "Your place could not be saved",
|
|
3048
|
+
},
|
|
3044
3049
|
team: {
|
|
3045
3050
|
metaTitle: "Workspace access - Content",
|
|
3046
3051
|
pageTitle: "Workspace access",
|
|
@@ -8959,11 +8964,63 @@ const commentMessagesByLocale = {
|
|
|
8959
8964
|
"ar-SA": { unanchored: "التمييز غير متاح" },
|
|
8960
8965
|
} satisfies Partial<Record<LocaleCode, Partial<typeof enUS.comments>>>;
|
|
8961
8966
|
|
|
8967
|
+
const landingMessagesByLocale = {
|
|
8968
|
+
"zh-CN": {
|
|
8969
|
+
previousPageUnavailable: "您之前的页面已不可用,因此我们打开了欢迎页面。",
|
|
8970
|
+
saveFailed: "无法保存您的位置",
|
|
8971
|
+
},
|
|
8972
|
+
"zh-TW": {
|
|
8973
|
+
previousPageUnavailable: "您先前的頁面已無法使用,因此我們開啟了歡迎頁面。",
|
|
8974
|
+
saveFailed: "無法儲存您的位置",
|
|
8975
|
+
},
|
|
8976
|
+
"es-ES": {
|
|
8977
|
+
previousPageUnavailable:
|
|
8978
|
+
"Tu página anterior ya no está disponible, así que abrimos la página de bienvenida.",
|
|
8979
|
+
saveFailed: "No se pudo guardar tu ubicación",
|
|
8980
|
+
},
|
|
8981
|
+
"fr-FR": {
|
|
8982
|
+
previousPageUnavailable:
|
|
8983
|
+
"Votre page précédente n’est plus disponible. Nous avons donc ouvert la page de bienvenue.",
|
|
8984
|
+
saveFailed: "Votre emplacement n’a pas pu être enregistré",
|
|
8985
|
+
},
|
|
8986
|
+
"de-DE": {
|
|
8987
|
+
previousPageUnavailable:
|
|
8988
|
+
"Deine vorherige Seite ist nicht mehr verfügbar. Daher wurde die Willkommensseite geöffnet.",
|
|
8989
|
+
saveFailed: "Deine Position konnte nicht gespeichert werden",
|
|
8990
|
+
},
|
|
8991
|
+
"ja-JP": {
|
|
8992
|
+
previousPageUnavailable:
|
|
8993
|
+
"前回のページを利用できないため、ようこそページを開きました。",
|
|
8994
|
+
saveFailed: "現在位置を保存できませんでした",
|
|
8995
|
+
},
|
|
8996
|
+
"ko-KR": {
|
|
8997
|
+
previousPageUnavailable:
|
|
8998
|
+
"이전 페이지를 더 이상 사용할 수 없어 시작 페이지를 열었습니다.",
|
|
8999
|
+
saveFailed: "현재 위치를 저장하지 못했습니다",
|
|
9000
|
+
},
|
|
9001
|
+
"pt-BR": {
|
|
9002
|
+
previousPageUnavailable:
|
|
9003
|
+
"Sua página anterior não está mais disponível, então abrimos a página de boas-vindas.",
|
|
9004
|
+
saveFailed: "Não foi possível salvar sua localização",
|
|
9005
|
+
},
|
|
9006
|
+
"hi-IN": {
|
|
9007
|
+
previousPageUnavailable:
|
|
9008
|
+
"आपका पिछला पेज अब उपलब्ध नहीं है, इसलिए हमने स्वागत पेज खोल दिया है।",
|
|
9009
|
+
saveFailed: "आपकी जगह सेव नहीं की जा सकी",
|
|
9010
|
+
},
|
|
9011
|
+
"ar-SA": {
|
|
9012
|
+
previousPageUnavailable:
|
|
9013
|
+
"لم تعد صفحتك السابقة متاحة، لذلك فتحنا صفحة الترحيب.",
|
|
9014
|
+
saveFailed: "تعذر حفظ موضعك",
|
|
9015
|
+
},
|
|
9016
|
+
} satisfies Record<Exclude<LocaleCode, "en-US">, typeof enUS.landing>;
|
|
9017
|
+
|
|
8962
9018
|
function mergeMessages(overrides: PartialMessages): Messages {
|
|
8963
9019
|
return {
|
|
8964
9020
|
root: { ...enUS.root, ...overrides.root },
|
|
8965
9021
|
theme: { ...enUS.theme, ...overrides.theme },
|
|
8966
9022
|
navigation: { ...enUS.navigation, ...overrides.navigation },
|
|
9023
|
+
landing: { ...enUS.landing, ...overrides.landing },
|
|
8967
9024
|
team: { ...enUS.team, ...overrides.team },
|
|
8968
9025
|
settings: { ...enUS.settings, ...overrides.settings },
|
|
8969
9026
|
chat: { ...enUS.chat, ...overrides.chat },
|
|
@@ -9061,6 +9118,7 @@ function mergeMessagesForLocale(
|
|
|
9061
9118
|
return {
|
|
9062
9119
|
...base,
|
|
9063
9120
|
comments: { ...base.comments, ...commentMessagesByLocale[locale] },
|
|
9121
|
+
landing: { ...base.landing, ...landingMessagesByLocale[locale] },
|
|
9064
9122
|
root: { ...base.root, ...rawLiteralOverrides.root },
|
|
9065
9123
|
team: { ...base.team, ...rawLiteralOverrides.team },
|
|
9066
9124
|
settings: { ...base.settings, ...rawLiteralOverrides.settings },
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { writeClientAppState } from "@agent-native/core/client/application-state";
|
|
2
|
+
import {
|
|
3
|
+
CONTENT_LAST_LOCATION_STATE_KEY,
|
|
4
|
+
type ContentLastLocationState,
|
|
5
|
+
} from "@shared/content-landing";
|
|
6
|
+
|
|
7
|
+
let landingWriteQueue = Promise.resolve();
|
|
8
|
+
|
|
9
|
+
export function rememberContentLandingDocument(documentId: string) {
|
|
10
|
+
const write = landingWriteQueue.then(() =>
|
|
11
|
+
writeClientAppState<ContentLastLocationState>(
|
|
12
|
+
CONTENT_LAST_LOCATION_STATE_KEY,
|
|
13
|
+
{ documentId },
|
|
14
|
+
{ requestSource: "content-landing" },
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
landingWriteQueue = write.then(
|
|
18
|
+
() => undefined,
|
|
19
|
+
() => undefined,
|
|
20
|
+
);
|
|
21
|
+
return write;
|
|
22
|
+
}
|
|
@@ -212,7 +212,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
|
|
212
212
|
suppressHydrationWarning
|
|
213
213
|
dangerouslySetInnerHTML={{ __html: localeInitScript }}
|
|
214
214
|
/>
|
|
215
|
-
<link rel="manifest" href={appPath("/manifest.json")} />
|
|
216
215
|
<meta name="theme-color" content="#10B981" />
|
|
217
216
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
218
217
|
<meta
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { useActionMutation } from "@agent-native/core/client/hooks";
|
|
2
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
3
|
+
import type { ContentLandingResult } from "@shared/content-landing";
|
|
4
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
5
|
import { useNavigate } from "react-router";
|
|
6
|
+
import { toast } from "sonner";
|
|
4
7
|
|
|
5
|
-
import { EmptyState } from "@/components/EmptyState";
|
|
6
8
|
import { QueryErrorState } from "@/components/QueryErrorState";
|
|
7
9
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
8
|
-
import { useDocuments } from "@/hooks/use-documents";
|
|
9
10
|
|
|
10
11
|
const SEO_TITLE = "Content - Open Source, agent-friendly Obsidian alternative";
|
|
11
12
|
const SEO_DESCRIPTION =
|
|
@@ -46,36 +47,45 @@ function DocumentSkeleton() {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export default function IndexRoute() {
|
|
50
|
+
const t = useT();
|
|
49
51
|
const navigate = useNavigate();
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
52
|
+
const startedRef = useRef(false);
|
|
53
|
+
const resolveLanding = useActionMutation<
|
|
54
|
+
ContentLandingResult,
|
|
55
|
+
Record<string, never>
|
|
56
|
+
>("resolve-content-landing");
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
const openLanding = useCallback(async () => {
|
|
59
|
+
if (startedRef.current) return;
|
|
60
|
+
startedRef.current = true;
|
|
61
|
+
try {
|
|
62
|
+
const result = await resolveLanding.mutateAsync({});
|
|
63
|
+
if (result.fallbackReason === "saved-document-unavailable") {
|
|
64
|
+
toast.info(t("landing.previousPageUnavailable"));
|
|
65
|
+
}
|
|
66
|
+
navigate(`/page/${result.documentId}`, { replace: true });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Keep the typed mutation error available to QueryErrorState. Retrying
|
|
69
|
+
// starts a fresh resolver attempt rather than pretending arrival worked.
|
|
70
|
+
console.error("Failed to resolve the Content landing page", error);
|
|
64
71
|
}
|
|
65
|
-
}, [
|
|
72
|
+
}, [navigate, resolveLanding, t]);
|
|
66
73
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
void openLanding();
|
|
76
|
+
}, [openLanding]);
|
|
70
77
|
|
|
71
|
-
if (
|
|
72
|
-
if (documentsQuery.isError) {
|
|
78
|
+
if (resolveLanding.isError) {
|
|
73
79
|
return (
|
|
74
80
|
<QueryErrorState
|
|
75
|
-
onRetry={() =>
|
|
76
|
-
|
|
81
|
+
onRetry={() => {
|
|
82
|
+
resolveLanding.reset();
|
|
83
|
+
startedRef.current = false;
|
|
84
|
+
void openLanding();
|
|
85
|
+
}}
|
|
86
|
+
retrying={resolveLanding.isPending}
|
|
77
87
|
/>
|
|
78
88
|
);
|
|
79
89
|
}
|
|
80
|
-
return <
|
|
90
|
+
return <DocumentSkeleton />;
|
|
81
91
|
}
|
package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md
CHANGED
|
@@ -42,6 +42,8 @@ If the Page was deleted or access changed, Content opens a safe fallback and exp
|
|
|
42
42
|
- Restoration reauthorizes every target before reopening it and drops invalid state safely.
|
|
43
43
|
- Saved or personal View focus restores when still authorized; ephemeral renderer state is bounded.
|
|
44
44
|
- Recovery distinguishes normal restoration, missing target, denied target, and unavailable source.
|
|
45
|
+
- At the root route, Content restores the last authorized Page. When no saved Page exists or the target is no longer available, it creates or reuses one private, editable Personal `Welcome to Agent-Native Content` Page.
|
|
46
|
+
- Explicit Page links take precedence over root-route restoration. A fallback does not reveal the unavailable Page's title, preview, or owning context.
|
|
45
47
|
|
|
46
48
|
## Boundaries and non-goals
|
|
47
49
|
|
|
@@ -60,6 +62,10 @@ Content reopens that object and View with a usable focus target.
|
|
|
60
62
|
Given saved state for an object whose access is revoked, when the session restores, then
|
|
61
63
|
Content omits the object and does not reveal its title, preview, or prior selection.
|
|
62
64
|
|
|
65
|
+
### Give a new person an honest starting place
|
|
66
|
+
|
|
67
|
+
Given a person with no saved Content location but with organization-visible Pages, when they open the root route, then Content opens one private Personal welcome Page instead of selecting an arbitrary organization Page.
|
|
68
|
+
|
|
63
69
|
## Current evidence
|
|
64
70
|
|
|
65
71
|
Persisted navigation donors do not prove reauthorization, fallback, and recovery. This
|
|
@@ -73,4 +79,4 @@ Capability remains `approved_shape`.
|
|
|
73
79
|
|
|
74
80
|
## Open questions
|
|
75
81
|
|
|
76
|
-
The
|
|
82
|
+
The first Page-level fallback order is settled. Full saved View, selection, and renderer-state restoration remains to be designed and proven.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Content text selector visual evidence
|
|
2
|
+
|
|
3
|
+
Matched desktop captures for the compact Text/H1-H4 selector in the Content editor.
|
|
4
|
+
|
|
5
|
+
## Before
|
|
6
|
+
|
|
7
|
+
- Source revision: `dcc028cb7d67a0f9279f9235cdc4c16710ce5689`
|
|
8
|
+
- Route: `http://127.0.0.1:3317/page/j4a5KAEDBHXY`
|
|
9
|
+
- Viewport: `1496 x 846`, desktop Chrome
|
|
10
|
+
- Fixture account: disposable local account `toolbar-demo@example.com`
|
|
11
|
+
- Fixture page: `Toolbar comparison`
|
|
12
|
+
- Fixture paragraph: `Select this sentence to compare the formatting toolbar.`
|
|
13
|
+
- UI state: Personal workspace expanded, agent panel closed, full paragraph selected, formatting bubble open, text-style submenu closed
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
## After
|
|
18
|
+
|
|
19
|
+
- Source: this pull request's production build
|
|
20
|
+
- Route: `http://127.0.0.1:3317/page/vDisteHisXMq`
|
|
21
|
+
- Viewport: `1496 x 846`, desktop Chrome
|
|
22
|
+
- Fixture account, page title, paragraph, sidebar state, and agent-panel state match the before capture
|
|
23
|
+
- UI state: full paragraph selected, formatting bubble open, Text selector expanded, Text checked, H1-H4 visible
|
|
24
|
+
- The route differs because the isolated worktree uses its own disposable local fixture database; the rendered fixture and viewport are matched
|
|
25
|
+
|
|
26
|
+

|
|
@@ -30,4 +30,5 @@ This generated matrix tracks whether high-value Content UI operations use the sa
|
|
|
30
30
|
| source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `list-notion-database-sources`, `preview-content-database-source-attach`, `refresh-content-database-source`, `suggest-source-join-key` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/DocumentProperties.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Mounted database source metadata, fields, source role, join keys, and source-field/property bindings are stored and refreshed. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
|
|
31
31
|
| source-sync.provider-api-and-staged-datasets | source-sync | Inspect provider APIs and stage/query/delete large provider datasets | action-backed | `delete-staged-dataset`, `list-staged-datasets`, `provider-api-catalog`, `provider-api-docs`, `provider-api-request`, `query-staged-dataset` | `actions/provider-api-catalog.ts`, `actions/provider-api-docs.ts`, `actions/provider-api-request.ts`, `actions/query-staged-dataset.ts` | Provider API metadata and staged dataset scratch storage support scoped agent/source analysis. | - | - | P1 | seeded | - | - | - |
|
|
32
32
|
| versions.history-and-restore | versions | Open version history and restore a previous document version | action-backed | `list-document-versions`, `restore-document-version` | `app/components/editor/VersionHistoryPanel.tsx`, `app/hooks/use-document-versions.ts` | Document versions are listed and selected versions can restore the document while snapshotting current state. | - | - | P0 | seeded | - | - | - |
|
|
33
|
+
| workspace.root-landing-resolver | workspace | Resolve the app root to the caller's last authorized page or a private welcome page | action-backed | `resolve-content-landing` | `app/routes/_app._index.tsx`, `app/lib/content-landing.ts` | The root route restores the most recent authorized page when possible and otherwise converges on one private personal welcome page while preserving last-location state. | - | - | P0 | covered | `actions/resolve-content-landing.db.test.ts`, `app/lib/content-landing.test.ts` | - | - |
|
|
33
34
|
| workspace.spaces-and-files-catalog | workspace | Provision, navigate, and delete Content spaces through Files and Workspaces with personal expansion state | action-backed | `backfill-content-files`, `create-content-space`, `delete-content-space`, `ensure-content-spaces`, `get-content-sidebar-state`, `list-content-spaces`, `update-content-sidebar-state` | `app/components/sidebar/DocumentSidebar.tsx`, `app/hooks/use-content-spaces.ts` | Personal and organization spaces, user-created workspaces, their canonical Files databases, the personal Workspaces catalog, and each user's sidebar expansion state are stored and reconciled in SQL; deleting a user-created workspace atomically removes its catalog row and contents. | - | - | P0 | covered | `actions/content-spaces.db.test.ts`, `actions/content-files.db.test.ts`, `actions/content-sidebar-state.test.ts` | - | - |
|
|
@@ -95,6 +95,28 @@ export const parityMatrix: ParityRow[] = [
|
|
|
95
95
|
testCoverage: "seeded",
|
|
96
96
|
followUpPR: null,
|
|
97
97
|
},
|
|
98
|
+
{
|
|
99
|
+
id: "workspace.root-landing-resolver",
|
|
100
|
+
surface: "workspace",
|
|
101
|
+
label:
|
|
102
|
+
"Resolve the app root to the caller's last authorized page or a private welcome page",
|
|
103
|
+
uiEntrypoints: ["app/routes/_app._index.tsx", "app/lib/content-landing.ts"],
|
|
104
|
+
durableEffect:
|
|
105
|
+
"The root route restores the most recent authorized page when possible and otherwise converges on one private personal welcome page while preserving last-location state.",
|
|
106
|
+
uiImplementation:
|
|
107
|
+
"The index route invokes the shared landing resolver on first load, then navigates to the resolved page and records the landing document in application state.",
|
|
108
|
+
status: "action-backed",
|
|
109
|
+
actions: ["resolve-content-landing"],
|
|
110
|
+
exception: null,
|
|
111
|
+
reliabilityRisk: "none",
|
|
112
|
+
spinePriority: "P0",
|
|
113
|
+
testCoverage: "covered",
|
|
114
|
+
followUpPR: null,
|
|
115
|
+
coverageRefs: [
|
|
116
|
+
"actions/resolve-content-landing.db.test.ts",
|
|
117
|
+
"app/lib/content-landing.test.ts",
|
|
118
|
+
],
|
|
119
|
+
},
|
|
98
120
|
{
|
|
99
121
|
id: "sidebar.chrome-state",
|
|
100
122
|
surface: "sidebar",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const CONTENT_LAST_LOCATION_STATE_KEY = "content-last-location-v1";
|
|
2
|
+
|
|
3
|
+
export type ContentLastLocationState = {
|
|
4
|
+
documentId: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type ContentLandingResolution =
|
|
8
|
+
| "restored"
|
|
9
|
+
| "welcome-created"
|
|
10
|
+
| "welcome-reused"
|
|
11
|
+
| "fallback";
|
|
12
|
+
|
|
13
|
+
export type ContentLandingResult = {
|
|
14
|
+
documentId: string;
|
|
15
|
+
resolution: ContentLandingResolution;
|
|
16
|
+
fallbackReason?: "saved-document-unavailable";
|
|
17
|
+
};
|