@agent-native/core-corpus 0.210.2 → 0.211.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +41 -2
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +4 -2
- package/corpus/templates/analytics/CHANGELOG.md +18 -0
- package/corpus/templates/analytics/actions/build-data-index.ts +11 -2
- package/corpus/templates/analytics/actions/configure-content-collection.ts +29 -4
- package/corpus/templates/analytics/actions/configure-first-party-events-model.ts +9 -7
- package/corpus/templates/analytics/actions/create-analytics-public-key.ts +4 -0
- package/corpus/templates/analytics/actions/estimate-content-signups-cost.ts +72 -0
- package/corpus/templates/analytics/actions/estimate-query-cost.ts +16 -134
- package/corpus/templates/analytics/actions/list-sigma-workbooks.ts +123 -42
- package/corpus/templates/analytics/actions/migrate-sigma-workbook.ts +20 -17
- package/corpus/templates/analytics/actions/revoke-analytics-public-key.ts +4 -0
- package/corpus/templates/analytics/app/components/dashboard/SigmaMigrationDialog.tsx +246 -680
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/analytics/app/i18n/en-US.ts +54 -55
- package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +0 -1
- package/corpus/templates/analytics/app/pages/DataSources.tsx +56 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/filter-vars.ts +4 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +26 -8
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/interpolate.ts +3 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/panel-cost-notice.ts +172 -0
- package/corpus/templates/analytics/app/pages/data-sources/SearchConsoleDetail.tsx +441 -0
- package/corpus/templates/analytics/changelog/2026-10-15-a-content-dashboard-lists-every-blog-article-with-its-author.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-15-data-sources-has-a-google-search-console-card-that-shows-the.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-the-content-dashboard-can-show-signups-per-blog-article.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-19-creating-or-revoking-a-public-analytics-key-now-asks-you-to-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-19-search-sigma-workbooks-by-name-and-open-ones-a-teammate-alre.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-blog-signup-attribution-excludes-signups-before-the-first-vi.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-collapsed-analytics-navigation-starts-at-the-top.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-content-keeps-successful-coverage-dates-and-missing-day-gaps.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-private-github-repositories-can-be-indexed-with-your-connect.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-search-console-preserves-backfill-and-paused-collection.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-search-console-refreshes-historical-coverage-when-properties.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-20-search-console-setup-keeps-saved-properties-readable-and-sup.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/content-view.json +182 -0
- package/corpus/templates/analytics/server/db/schema.ts +1 -0
- package/corpus/templates/analytics/server/lib/bi-migration/external-dashboards-store.ts +56 -18
- package/corpus/templates/analytics/server/lib/bi-migration/unfinished-import.ts +64 -0
- package/corpus/templates/analytics/server/lib/builtin-dashboard-pass.ts +17 -2
- package/corpus/templates/analytics/server/lib/content-metrics/collect.ts +2 -0
- package/corpus/templates/analytics/server/lib/content-metrics/config.ts +92 -3
- package/corpus/templates/analytics/server/lib/content-metrics/legacy-content-view.json +172 -0
- package/corpus/templates/analytics/server/lib/content-metrics/migration.ts +2 -0
- package/corpus/templates/analytics/server/lib/content-metrics/steps/daily-metrics.ts +8 -3
- package/corpus/templates/analytics/server/lib/content-metrics/steps/search-console.ts +16 -3
- package/corpus/templates/analytics/server/lib/content-metrics/steps/signups.ts +240 -0
- package/corpus/templates/analytics/server/lib/content-metrics/store.ts +5 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +21 -0
- package/corpus/templates/analytics/server/lib/dashboard-panel-verification.ts +300 -5
- package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +28 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +128 -24
- package/corpus/templates/analytics/server/lib/google-analytics.ts +56 -16
- package/corpus/templates/analytics/server/lib/index-build-github.ts +5 -0
- package/corpus/templates/analytics/server/lib/provider-credentials.ts +47 -2
- package/corpus/templates/analytics/server/lib/query-cost-estimate.ts +184 -5
- package/corpus/templates/analytics/server/plugins/db.ts +9 -1
- package/corpus/templates/analytics/shared/builtin-dashboard-ids.ts +2 -0
- package/corpus/templates/analytics/shared/search-console-property.ts +78 -0
- package/corpus/templates/assets/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/brain/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/calendar/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/calendar/actions/delete-event.ts +1 -3
- package/corpus/templates/calendar/actions/delete-events.ts +1 -2
- package/corpus/templates/calendar/actions/event-action-helpers.ts +0 -4
- package/corpus/templates/calendar/actions/update-event.ts +2 -6
- package/corpus/templates/chat/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/clips/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/clips/CHANGELOG.md +11 -24
- package/corpus/templates/clips/actions/create-recording-upload.ts +5 -1
- package/corpus/templates/clips/app/components/player/chapter-list.tsx +7 -6
- package/corpus/templates/clips/app/components/player/comment-composer.tsx +5 -1
- package/corpus/templates/clips/app/components/player/player-controls.tsx +1 -0
- package/corpus/templates/clips/app/components/player/scrubber.tsx +4 -2
- package/corpus/templates/clips/app/i18n/en-US.ts +3 -3
- package/corpus/templates/clips/app/lib/extension-auth.ts +70 -0
- package/corpus/templates/clips/app/root.tsx +22 -10
- package/corpus/templates/clips/app/routes/_app.notifications.tsx +3 -0
- package/corpus/templates/clips/app/routes/import.tsx +115 -110
- package/corpus/templates/clips/changelog/2026-10-16-agent-uploads-can-use-free-clips-storage.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-19-agents-see-a-clip-s-frames-as-soon-as-it-finishes-processing.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-19-chapter-list-times-now-match-the-player-s-clock-and-each-cha.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-19-editing-a-comment-puts-the-cursor-after-its-text-and-reply-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-19-youtube-import-followups.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-20-locally-saved-desktop-recordings-now-appear-in-the-recovery-.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +29 -186
- package/corpus/templates/clips/desktop/src/components/RecordingRecovery.tsx +171 -16
- package/corpus/templates/clips/desktop/src/lib/record-first.ts +9 -32
- package/corpus/templates/clips/desktop/src/lib/recording-recovery.ts +30 -1
- package/corpus/templates/clips/server/lib/agent-frame-request.ts +5 -2
- package/corpus/templates/clips/server/lib/recording-upload-ticket.ts +8 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +2 -0
- package/corpus/templates/content/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/content/CHANGELOG.md +12 -0
- package/corpus/templates/content/actions/_content-database-personal-view.ts +5 -15
- package/corpus/templates/content/actions/_database-navigation.ts +3 -3
- package/corpus/templates/content/actions/_database-utils.ts +10 -22
- package/corpus/templates/content/actions/_database-view-setup.ts +16 -76
- package/corpus/templates/content/actions/create-comment-ai-suggestion.ts +93 -44
- package/corpus/templates/content/actions/export-document.ts +2 -14
- package/corpus/templates/content/actions/suggest-document-edit.ts +5 -7
- package/corpus/templates/content/actions/update-content-database-view.ts +2 -14
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +86 -30
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +64 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +6 -46
- package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +72 -7
- package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +292 -103
- package/corpus/templates/content/app/components/editor/ThreadSuggestion.tsx +147 -40
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +108 -11
- package/corpus/templates/content/app/components/editor/database/ContentTable.tsx +2 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +150 -166
- package/corpus/templates/content/app/components/editor/database/database-cell-comments.tsx +515 -0
- package/corpus/templates/content/app/components/editor/database/database-item-comments.tsx +5 -43
- package/corpus/templates/content/app/components/editor/database/filter-sort.ts +8 -783
- package/corpus/templates/content/app/components/editor/live-editor-session.ts +5 -1
- package/corpus/templates/content/app/components/editor/page-draft-journal.ts +61 -1
- package/corpus/templates/content/app/components/editor/property-comments.tsx +35 -4
- package/corpus/templates/content/app/components/editor/property-date-format.ts +45 -0
- package/corpus/templates/content/app/components/editor/thread-suggestions.ts +30 -0
- package/corpus/templates/content/app/components/editor/useDocumentReconcileRecovery.ts +23 -4
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +36 -10
- package/corpus/templates/content/app/global.css +23 -0
- package/corpus/templates/content/app/i18n-data.ts +1 -0
- package/corpus/templates/content/changelog/2026-10-16-opening-a-page-in-a-new-tab-while-another-tab-is-still-savin.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-typing-steadily-in-one-tab-no-longer-makes-another-open-tab-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-19-database-views-can-filter-the-same-property-more-than-once-n.md +6 -0
- package/corpus/templates/content/changelog/2026-10-19-edits-made-from-a-block-s-menu-or-a-table-s-row-and-column-m.md +6 -0
- package/corpus/templates/content/changelog/2026-10-19-starting-a-comment-puts-the-cursor-in-the-comment-box-ready-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-19-table-row-and-column-options-now-appear-for-the-row-or-colum.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +5 -1
- package/corpus/templates/content/docs/product/capabilities/content.revision.suggestions.md +3 -1
- package/corpus/templates/content/e2e/helpers.ts +10 -0
- package/corpus/templates/content/shared/api.ts +18 -12
- package/corpus/templates/content/shared/database-query.ts +107 -13
- package/corpus/templates/content/shared/suggestion-diff.ts +35 -0
- package/corpus/templates/crm/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/design/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/design/CHANGELOG.md +2 -0
- package/corpus/templates/design/actions/delete-file.ts +1 -4
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +10 -1
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +24 -4
- package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +14 -9
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-modes.ts +23 -2
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +29 -0
- package/corpus/templates/design/changelog/2026-10-19-reply-and-edit-on-a-comment-in-the-sidebar-or-on-a-canvas-pi.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-comments-return-to-the-mode-they-came-from-and-layers-search.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +185 -85
- package/corpus/templates/dispatch/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/dispatch/CHANGELOG.md +4 -0
- package/corpus/templates/dispatch/actions/apply-workspace-connection-setup.ts +4 -0
- package/corpus/templates/dispatch/actions/delete-workspace-connection.ts +4 -0
- package/corpus/templates/dispatch/actions/set-workspace-connection-grant.ts +4 -0
- package/corpus/templates/dispatch/actions/upsert-workspace-connection.ts +4 -0
- package/corpus/templates/dispatch/changelog/2026-10-19-vault-secrets-grants-link-tokens-app-access-and-workspace-co.md +6 -0
- package/corpus/templates/factory/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +105 -33
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +128 -74
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +39 -11
- package/corpus/templates/forms/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/mail/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/mail/.agents/skills/contacts-and-crm/SKILL.md +22 -17
- package/corpus/templates/mail/AGENTS.md +1 -1
- package/corpus/templates/mail/CHANGELOG.md +14 -0
- package/corpus/templates/mail/actions/provider-api-request.ts +3 -3
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +211 -54
- package/corpus/templates/mail/app/hooks/use-inbox-threads.ts +26 -2
- package/corpus/templates/mail/app/i18n/en-US.ts +5 -1
- package/corpus/templates/mail/app/lib/gong-connection.ts +27 -0
- package/corpus/templates/mail/app/lib/thread-cache.ts +110 -9
- package/corpus/templates/mail/app/root.tsx +10 -2
- package/corpus/templates/mail/changelog/2026-10-20-connected-gong-settings-now-open-the-shared-integration-mana.md +6 -0
- package/corpus/templates/mail/changelog/2026-10-20-gong-connection-details-now-match-the-call-data-available-in.md +6 -0
- package/corpus/templates/mail/changelog/2026-10-20-improve-gong-setup-with-a-click-to-connect-flow-and-permissi.md +6 -0
- package/corpus/templates/mail/changelog/2026-10-20-mail-lets-you-retry-when-it-cannot-check-your-gong-access.md +6 -0
- package/corpus/templates/mail/changelog/2026-10-20-mail-thread-cache-stays-isolated-when-mailbox-scope-changes.md +6 -0
- package/corpus/templates/mail/changelog/2026-10-20-the-inbox-and-recently-opened-threads-now-open-instantly-fro.md +6 -0
- package/corpus/templates/mail/server/handlers/emails.ts +9 -0
- package/corpus/templates/plan/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/plan/CHANGELOG.md +4 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +173 -33
- package/corpus/templates/plan/changelog/2026-10-19-opening-a-comment-thread-puts-the-cursor-in-the-reply-box-an.md +6 -0
- package/corpus/templates/slides/.agents/skills/actions/references/action-fields.md +5 -3
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +6 -42
- package/corpus/templates/slides/app/components/editor/FloatingToolbar.tsx +3 -7
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +5 -14
- package/corpus/templates/slides/app/i18n/en-US.ts +0 -2
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +27 -33
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +1 -3
- package/corpus/templates/tasks/.agents/skills/actions/references/action-fields.md +5 -3
- package/package.json +1 -1
|
@@ -20,26 +20,73 @@ import { trimDiffContext, wordDiff } from "./comment-ai-diff";
|
|
|
20
20
|
import { CommentRow } from "./CommentRow";
|
|
21
21
|
import { suggestionLineExcerpt } from "./thread-suggestions";
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*/
|
|
28
|
-
|
|
23
|
+
type ThreadSuggestionProps = {
|
|
24
|
+
/** One suggestion, or every edit of the proposal it belongs to, in Page order. */
|
|
25
|
+
suggestions: ResourceSuggestion[];
|
|
26
|
+
canDecide: boolean;
|
|
27
|
+
/** A decision, or an AI revision in this thread, is still in flight. */
|
|
28
|
+
busy: (suggestion: ResourceSuggestion) => boolean;
|
|
29
|
+
conflict: (suggestion: ResourceSuggestion) => boolean;
|
|
30
|
+
onDecide: (
|
|
31
|
+
suggestion: ResourceSuggestion,
|
|
32
|
+
decision: SuggestionDecision,
|
|
33
|
+
) => void;
|
|
34
|
+
/** Decides every edit of the proposal still pending. */
|
|
35
|
+
onDecideRemaining?: (decision: SuggestionDecision) => void;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function useStatusLabel() {
|
|
39
|
+
const t = useT();
|
|
40
|
+
return (status: ResourceSuggestion["status"]) =>
|
|
41
|
+
status === "accepted"
|
|
42
|
+
? { icon: IconCircleCheck, label: t("comments.accepted") }
|
|
43
|
+
: status === "rejected"
|
|
44
|
+
? { icon: IconCircleX, label: t("comments.rejected") }
|
|
45
|
+
: status === "superseded"
|
|
46
|
+
? { icon: IconArrowBackUp, label: t("comments.suggestionReplaced") }
|
|
47
|
+
: status === "withdrawn"
|
|
48
|
+
? {
|
|
49
|
+
icon: IconArrowBackUp,
|
|
50
|
+
label: t("comments.suggestionWithdrawn"),
|
|
51
|
+
}
|
|
52
|
+
: null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function SuggestionStatus({
|
|
56
|
+
status,
|
|
57
|
+
}: {
|
|
58
|
+
status: ReturnType<ReturnType<typeof useStatusLabel>>;
|
|
59
|
+
}) {
|
|
60
|
+
if (!status) return null;
|
|
61
|
+
return (
|
|
62
|
+
<span
|
|
63
|
+
role="status"
|
|
64
|
+
className="inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground"
|
|
65
|
+
>
|
|
66
|
+
<status.icon size={14} aria-hidden />
|
|
67
|
+
{status.label}
|
|
68
|
+
</span>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** One edit's word diff, with its own Accept and Reject or outcome. */
|
|
73
|
+
function ThreadSuggestionEdit({
|
|
29
74
|
suggestion,
|
|
30
75
|
canDecide,
|
|
31
76
|
busy,
|
|
32
77
|
conflict,
|
|
33
78
|
onDecide,
|
|
79
|
+
showStatus,
|
|
34
80
|
}: {
|
|
35
81
|
suggestion: ResourceSuggestion;
|
|
36
82
|
canDecide: boolean;
|
|
37
|
-
/** A decision, or an AI revision in this thread, is still in flight. */
|
|
38
83
|
busy: boolean;
|
|
39
84
|
conflict: boolean;
|
|
40
85
|
onDecide: (decision: SuggestionDecision) => void;
|
|
86
|
+
showStatus: boolean;
|
|
41
87
|
}) {
|
|
42
88
|
const t = useT();
|
|
89
|
+
const statusLabel = useStatusLabel();
|
|
43
90
|
const excerpt = useMemo(
|
|
44
91
|
() => suggestionLineExcerpt(suggestion.operations),
|
|
45
92
|
[suggestion.operations],
|
|
@@ -50,28 +97,12 @@ export function ThreadSuggestionBody({
|
|
|
50
97
|
[excerpt],
|
|
51
98
|
);
|
|
52
99
|
const pending = suggestion.status === "pending";
|
|
53
|
-
const status =
|
|
54
|
-
suggestion.status === "accepted"
|
|
55
|
-
? { icon: IconCircleCheck, label: t("comments.accepted") }
|
|
56
|
-
: suggestion.status === "rejected"
|
|
57
|
-
? { icon: IconCircleX, label: t("comments.rejected") }
|
|
58
|
-
: suggestion.status === "superseded"
|
|
59
|
-
? { icon: IconArrowBackUp, label: t("comments.suggestionReplaced") }
|
|
60
|
-
: suggestion.status === "withdrawn"
|
|
61
|
-
? {
|
|
62
|
-
icon: IconArrowBackUp,
|
|
63
|
-
label: t("comments.suggestionWithdrawn"),
|
|
64
|
-
}
|
|
65
|
-
: null;
|
|
66
100
|
return (
|
|
67
101
|
<div
|
|
68
|
-
className="
|
|
102
|
+
className="grid grid-cols-1 gap-2"
|
|
69
103
|
data-thread-suggestion={suggestion.id}
|
|
70
104
|
data-thread-suggestion-status={suggestion.status}
|
|
71
105
|
>
|
|
72
|
-
<p className={cn(!pending && "text-muted-foreground")}>
|
|
73
|
-
{suggestion.summary}
|
|
74
|
-
</p>
|
|
75
106
|
{segments.length ? (
|
|
76
107
|
<p
|
|
77
108
|
aria-label={t("comments.suggestedChange")}
|
|
@@ -108,7 +139,7 @@ export function ThreadSuggestionBody({
|
|
|
108
139
|
</p>
|
|
109
140
|
) : null}
|
|
110
141
|
{pending && canDecide ? (
|
|
111
|
-
<div className="flex items-center gap-1.5">
|
|
142
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
112
143
|
<Button
|
|
113
144
|
type="button"
|
|
114
145
|
size="sm"
|
|
@@ -137,27 +168,103 @@ export function ThreadSuggestionBody({
|
|
|
137
168
|
{t("editor.rejectSuggestion")}
|
|
138
169
|
</Button>
|
|
139
170
|
</div>
|
|
140
|
-
) :
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
171
|
+
) : showStatus ? (
|
|
172
|
+
<SuggestionStatus status={statusLabel(suggestion.status)} />
|
|
173
|
+
) : null}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* An AI suggestion shown in place of its receipt reply inside the comment
|
|
180
|
+
* thread that asked for it. Separate changes arrive as one proposal, so the
|
|
181
|
+
* summary is said once above every edit. Deciding changes only the
|
|
182
|
+
* suggestions; the thread stays open until someone resolves it.
|
|
183
|
+
*/
|
|
184
|
+
export function ThreadSuggestionBody({
|
|
185
|
+
suggestions,
|
|
186
|
+
canDecide,
|
|
187
|
+
busy,
|
|
188
|
+
conflict,
|
|
189
|
+
onDecide,
|
|
190
|
+
onDecideRemaining,
|
|
191
|
+
}: ThreadSuggestionProps) {
|
|
192
|
+
const t = useT();
|
|
193
|
+
const statusLabel = useStatusLabel();
|
|
194
|
+
const [first] = suggestions;
|
|
195
|
+
if (!first) return null;
|
|
196
|
+
const pending = suggestions.filter(
|
|
197
|
+
(suggestion) => suggestion.status === "pending",
|
|
198
|
+
);
|
|
199
|
+
// Edits that all ended the same way say so once, under the last of them.
|
|
200
|
+
const sharedStatus =
|
|
201
|
+
suggestions.length > 1 &&
|
|
202
|
+
suggestions.every((suggestion) => suggestion.status === first.status)
|
|
203
|
+
? first.status
|
|
204
|
+
: null;
|
|
205
|
+
return (
|
|
206
|
+
<div
|
|
207
|
+
className="mt-0.5 grid grid-cols-1 gap-2"
|
|
208
|
+
data-thread-suggestion-group={first.proposalId ?? first.id}
|
|
209
|
+
>
|
|
210
|
+
<p className={cn(!pending.length && "text-muted-foreground")}>
|
|
211
|
+
{first.proposalSummary || first.summary}
|
|
212
|
+
</p>
|
|
213
|
+
{suggestions.map((suggestion) => (
|
|
214
|
+
<ThreadSuggestionEdit
|
|
215
|
+
key={suggestion.id}
|
|
216
|
+
suggestion={suggestion}
|
|
217
|
+
canDecide={canDecide}
|
|
218
|
+
busy={busy(suggestion)}
|
|
219
|
+
conflict={conflict(suggestion)}
|
|
220
|
+
onDecide={(decision) => onDecide(suggestion, decision)}
|
|
221
|
+
showStatus={!sharedStatus}
|
|
222
|
+
/>
|
|
223
|
+
))}
|
|
224
|
+
{sharedStatus ? (
|
|
225
|
+
<SuggestionStatus status={statusLabel(sharedStatus)} />
|
|
226
|
+
) : null}
|
|
227
|
+
{canDecide && onDecideRemaining && pending.length > 1 ? (
|
|
228
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
229
|
+
<Button
|
|
230
|
+
type="button"
|
|
231
|
+
size="sm"
|
|
232
|
+
variant="ghost"
|
|
233
|
+
disabled={pending.some(busy) || pending.some(conflict)}
|
|
234
|
+
onClick={(event) => {
|
|
235
|
+
event.stopPropagation();
|
|
236
|
+
onDecideRemaining("accepted");
|
|
237
|
+
}}
|
|
238
|
+
data-suggestion-proposal-decision="accepted"
|
|
239
|
+
>
|
|
240
|
+
{t("comments.acceptRemaining")}
|
|
241
|
+
</Button>
|
|
242
|
+
<Button
|
|
243
|
+
type="button"
|
|
244
|
+
size="sm"
|
|
245
|
+
variant="ghost"
|
|
246
|
+
className="text-muted-foreground"
|
|
247
|
+
disabled={pending.some(busy)}
|
|
248
|
+
onClick={(event) => {
|
|
249
|
+
event.stopPropagation();
|
|
250
|
+
onDecideRemaining("rejected");
|
|
251
|
+
}}
|
|
252
|
+
data-suggestion-proposal-decision="rejected"
|
|
253
|
+
>
|
|
254
|
+
{t("comments.rejectRemaining")}
|
|
255
|
+
</Button>
|
|
256
|
+
</div>
|
|
148
257
|
) : null}
|
|
149
258
|
</div>
|
|
150
259
|
);
|
|
151
260
|
}
|
|
152
261
|
|
|
153
262
|
/** A thread suggestion whose receipt reply is not in the thread. */
|
|
154
|
-
export function ThreadSuggestionRow(
|
|
155
|
-
|
|
156
|
-
)
|
|
263
|
+
export function ThreadSuggestionRow(props: ThreadSuggestionProps) {
|
|
264
|
+
const [first] = props.suggestions;
|
|
265
|
+
if (!first) return null;
|
|
157
266
|
const model =
|
|
158
|
-
typeof
|
|
159
|
-
? props.suggestion.metadata.model
|
|
160
|
-
: null;
|
|
267
|
+
typeof first.metadata?.model === "string" ? first.metadata.model : null;
|
|
161
268
|
return (
|
|
162
269
|
<CommentRow
|
|
163
270
|
avatar={<AgentAvatar model={model} />}
|
|
@@ -167,7 +274,7 @@ export function ThreadSuggestionRow(
|
|
|
167
274
|
model,
|
|
168
275
|
run: {
|
|
169
276
|
effort: null,
|
|
170
|
-
ranAt:
|
|
277
|
+
ranAt: first.createdAt,
|
|
171
278
|
threadId: null,
|
|
172
279
|
canOpen: false,
|
|
173
280
|
},
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
TextSelection,
|
|
68
68
|
type Transaction,
|
|
69
69
|
} from "@tiptap/pm/state";
|
|
70
|
+
import { CellSelection, cellAround } from "@tiptap/pm/tables";
|
|
70
71
|
import { Decoration, DecorationSet, type EditorView } from "@tiptap/pm/view";
|
|
71
72
|
import {
|
|
72
73
|
useEditor,
|
|
@@ -738,6 +739,25 @@ const NotionMarkdownShortcuts = Extension.create({
|
|
|
738
739
|
});
|
|
739
740
|
|
|
740
741
|
const CustomTable = BaseTable.extend({
|
|
742
|
+
addKeyboardShortcuts() {
|
|
743
|
+
return {
|
|
744
|
+
...this.parent?.(),
|
|
745
|
+
// Escape leaves the editor (`contentEditorEscape`), and Tab can't leave a
|
|
746
|
+
// table, so from a cell's text the first Escape only selects the cell.
|
|
747
|
+
Escape: ({ editor }) => {
|
|
748
|
+
const { selection } = editor.state;
|
|
749
|
+
if (selection instanceof CellSelection) return false;
|
|
750
|
+
const $cell = cellAround(selection.$from);
|
|
751
|
+
if (!$cell) return false;
|
|
752
|
+
editor.view.dispatch(
|
|
753
|
+
editor.state.tr.setSelection(
|
|
754
|
+
CellSelection.create(editor.state.doc, $cell.pos),
|
|
755
|
+
),
|
|
756
|
+
);
|
|
757
|
+
return true;
|
|
758
|
+
},
|
|
759
|
+
};
|
|
760
|
+
},
|
|
741
761
|
addAttributes() {
|
|
742
762
|
return {
|
|
743
763
|
...this.parent?.(),
|
|
@@ -835,6 +855,14 @@ const NotionTableHeader = TableHeader.extend({
|
|
|
835
855
|
addAttributes() {
|
|
836
856
|
return { ...this.parent?.(), ...tableAlignmentAttribute };
|
|
837
857
|
},
|
|
858
|
+
// Header cells render as <td>, so copying or pasting a table reads them back
|
|
859
|
+
// from their class. The higher priority puts this rule before tableCell's.
|
|
860
|
+
parseHTML() {
|
|
861
|
+
return [
|
|
862
|
+
{ tag: "td.content-table-header-cell", priority: 60 },
|
|
863
|
+
...(this.parent?.() ?? []),
|
|
864
|
+
];
|
|
865
|
+
},
|
|
838
866
|
renderHTML({ HTMLAttributes }) {
|
|
839
867
|
return [
|
|
840
868
|
"td",
|
|
@@ -907,7 +935,39 @@ function normalizeTableHeaderCells(
|
|
|
907
935
|
return rowChanged ? row.copy(Fragment.fromArray(normalizedCells)) : row;
|
|
908
936
|
});
|
|
909
937
|
|
|
910
|
-
|
|
938
|
+
// Saved tables keep their headers only in these attributes, so update them
|
|
939
|
+
// whenever they no longer produce the header cells, e.g. after a header
|
|
940
|
+
// toggle or after deleting the header row.
|
|
941
|
+
const isHeaderAt = (
|
|
942
|
+
headerRow: boolean,
|
|
943
|
+
headerColumn: boolean,
|
|
944
|
+
rowIndex: number,
|
|
945
|
+
columnIndex: number,
|
|
946
|
+
) => (headerRow && rowIndex === 0) || (headerColumn && columnIndex === 0);
|
|
947
|
+
const savedHeaderRow = table.attrs.headerRow === true;
|
|
948
|
+
const savedHeaderColumn = table.attrs.headerColumn === true;
|
|
949
|
+
const attrsMatchCells = rows.every((row, rowIndex) =>
|
|
950
|
+
getNodeChildren(row).every(
|
|
951
|
+
(_cell, columnIndex) =>
|
|
952
|
+
isHeaderAt(savedHeaderRow, savedHeaderColumn, rowIndex, columnIndex) ===
|
|
953
|
+
isHeaderAt(hasHeaderRow, hasHeaderColumn, rowIndex, columnIndex),
|
|
954
|
+
),
|
|
955
|
+
);
|
|
956
|
+
|
|
957
|
+
if (!changed && attrsMatchCells) return table;
|
|
958
|
+
|
|
959
|
+
const content = changed ? Fragment.fromArray(normalizedRows) : table.content;
|
|
960
|
+
return attrsMatchCells
|
|
961
|
+
? table.copy(content)
|
|
962
|
+
: table.type.create(
|
|
963
|
+
{
|
|
964
|
+
...table.attrs,
|
|
965
|
+
headerRow: hasHeaderRow,
|
|
966
|
+
headerColumn: hasHeaderColumn,
|
|
967
|
+
},
|
|
968
|
+
content,
|
|
969
|
+
table.marks,
|
|
970
|
+
);
|
|
911
971
|
}
|
|
912
972
|
|
|
913
973
|
const normalizeTableHeadersPluginKey = new PluginKey("normalizeTableHeaders");
|
|
@@ -929,11 +989,20 @@ function buildNormalizeTableHeadersTransaction(state: CoreEditor["state"]) {
|
|
|
929
989
|
tableHeaderType,
|
|
930
990
|
);
|
|
931
991
|
if (normalizedTable !== node) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
normalizedTable
|
|
936
|
-
|
|
992
|
+
// When only the header attributes change, keep the cells, and the
|
|
993
|
+
// selection inside them, in place.
|
|
994
|
+
transaction =
|
|
995
|
+
normalizedTable.content === node.content
|
|
996
|
+
? transaction.setNodeMarkup(
|
|
997
|
+
transaction.mapping.map(pos),
|
|
998
|
+
undefined,
|
|
999
|
+
normalizedTable.attrs,
|
|
1000
|
+
)
|
|
1001
|
+
: transaction.replaceWith(
|
|
1002
|
+
transaction.mapping.map(pos),
|
|
1003
|
+
transaction.mapping.map(pos + node.nodeSize),
|
|
1004
|
+
normalizedTable,
|
|
1005
|
+
);
|
|
937
1006
|
changed = true;
|
|
938
1007
|
}
|
|
939
1008
|
|
|
@@ -3351,7 +3420,9 @@ export function VisualEditor({
|
|
|
3351
3420
|
}),
|
|
3352
3421
|
Extension.create({
|
|
3353
3422
|
name: "contentEditorEscape",
|
|
3354
|
-
|
|
3423
|
+
// Last, so editor Escape handlers such as the table's run first. Not 0:
|
|
3424
|
+
// TipTap reads a priority of 0 as unset, which puts this first instead.
|
|
3425
|
+
priority: 1,
|
|
3355
3426
|
addProseMirrorPlugins() {
|
|
3356
3427
|
return [
|
|
3357
3428
|
new Plugin({
|
|
@@ -3397,6 +3468,12 @@ export function VisualEditor({
|
|
|
3397
3468
|
|
|
3398
3469
|
const guardsRef = useRef<UseCollabReconcileResult | null>(null);
|
|
3399
3470
|
const draftEmissionGenerationRef = useRef(0);
|
|
3471
|
+
const pendingDraftEmissionsRef = useRef<Array<() => void>>([]);
|
|
3472
|
+
const drainPendingDraftEmissions = useCallback(() => {
|
|
3473
|
+
const pending = pendingDraftEmissionsRef.current;
|
|
3474
|
+
pendingDraftEmissionsRef.current = [];
|
|
3475
|
+
for (const emit of pending) emit();
|
|
3476
|
+
}, []);
|
|
3400
3477
|
const lastUserEditIntentAtRef = useRef(0);
|
|
3401
3478
|
const hasUserEditIntentRef = useRef(false);
|
|
3402
3479
|
const markUserEditIntent = useCallback(() => {
|
|
@@ -3439,10 +3516,11 @@ export function VisualEditor({
|
|
|
3439
3516
|
if (options?.immediate) return "failed" as const;
|
|
3440
3517
|
if (!guards.registerEmitted(normalized)) return "unchanged" as const;
|
|
3441
3518
|
const generation = draftEmissionGenerationRef.current;
|
|
3442
|
-
|
|
3519
|
+
pendingDraftEmissionsRef.current.push(() => {
|
|
3443
3520
|
if (generation === draftEmissionGenerationRef.current)
|
|
3444
3521
|
onChangeRef.current(normalized);
|
|
3445
|
-
}
|
|
3522
|
+
});
|
|
3523
|
+
setTimeout(drainPendingDraftEmissions, 0);
|
|
3446
3524
|
return "scheduled" as const;
|
|
3447
3525
|
} catch (err: any) {
|
|
3448
3526
|
toast.error(
|
|
@@ -3452,7 +3530,24 @@ export function VisualEditor({
|
|
|
3452
3530
|
return "failed" as const;
|
|
3453
3531
|
}
|
|
3454
3532
|
},
|
|
3455
|
-
[
|
|
3533
|
+
[
|
|
3534
|
+
content,
|
|
3535
|
+
drainPendingDraftEmissions,
|
|
3536
|
+
localFileMode,
|
|
3537
|
+
scheduleLiveBodyParity,
|
|
3538
|
+
t,
|
|
3539
|
+
],
|
|
3540
|
+
);
|
|
3541
|
+
// A remote snapshot is the whole live document, so it already holds local
|
|
3542
|
+
// typing whose deferred report has not run. Reporting that typing first keeps
|
|
3543
|
+
// it a local edit; otherwise the snapshot absorbs it and an older save's
|
|
3544
|
+
// acknowledgment can clear the only journaled copy.
|
|
3545
|
+
const reportRemoteSnapshot = useCallback(
|
|
3546
|
+
(markdown: string) => {
|
|
3547
|
+
drainPendingDraftEmissions();
|
|
3548
|
+
onRemoteSnapshotChange?.(markdown);
|
|
3549
|
+
},
|
|
3550
|
+
[drainPendingDraftEmissions, onRemoteSnapshotChange],
|
|
3456
3551
|
);
|
|
3457
3552
|
onMediaSourceCommittedRef.current = async (editorToPersist, transaction) => {
|
|
3458
3553
|
if (suggestingRef.current) return;
|
|
@@ -4189,7 +4284,9 @@ export function VisualEditor({
|
|
|
4189
4284
|
: collabContentRevision,
|
|
4190
4285
|
requestCollabSync,
|
|
4191
4286
|
onBaseAwareReconcile,
|
|
4192
|
-
onRemoteSnapshotChange
|
|
4287
|
+
onRemoteSnapshotChange: onRemoteSnapshotChange
|
|
4288
|
+
? reportRemoteSnapshot
|
|
4289
|
+
: undefined,
|
|
4193
4290
|
isEditorClean,
|
|
4194
4291
|
requestInitialSeed:
|
|
4195
4292
|
ydoc && editable && documentId ? requestInitialSeed : undefined,
|
|
@@ -42,7 +42,8 @@ function subscribeToNoHover(onChange: () => void) {
|
|
|
42
42
|
return () => media.removeEventListener("change", onChange);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
/** Whether no pointer on this device can hover, as on a phone. */
|
|
46
|
+
export function deviceCannotHover() {
|
|
46
47
|
return (
|
|
47
48
|
typeof window !== "undefined" &&
|
|
48
49
|
typeof window.matchMedia === "function" &&
|