@agent-native/core-corpus 0.216.0 → 0.218.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/session-replay/SKILL.md +61 -1
- package/corpus/templates/analytics/AGENTS.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +3 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +9 -65
- package/corpus/templates/analytics/actions/list-event-catalog.ts +1 -1
- package/corpus/templates/analytics/actions/list-session-outputs.ts +40 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +17 -4
- package/corpus/templates/analytics/actions/view-screen.ts +29 -3
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +38 -167
- package/corpus/templates/analytics/app/i18n/en-US.ts +27 -0
- package/corpus/templates/analytics/app/pages/sessions/EventCatalogPage.tsx +18 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +3 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionOutputs.tsx +197 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsTriagePage.tsx +114 -4
- package/corpus/templates/analytics/changelog/2026-10-15-sessions-can-find-people-who-made-a-slides-deck-but-didn-t-p.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-the-activation-funnel-counts-visitors-who-decline-analytics-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +67 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +28 -22
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +36 -1
- package/corpus/templates/analytics/server/lib/output-outcomes.ts +712 -0
- package/corpus/templates/analytics/server/lib/replay-origins.ts +33 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +20 -0
- package/corpus/templates/analytics/server/lib/session-performance.ts +6 -40
- package/corpus/templates/analytics/server/lib/session-recording-associations.ts +30 -1
- package/corpus/templates/analytics/server/lib/session-replay-triage.ts +99 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +45 -31
- package/corpus/templates/analytics/server/lib/sessions-triage-lab.ts +8 -2
- package/corpus/templates/analytics/server/plugins/db.ts +46 -0
- package/corpus/templates/analytics/shared/output-use.ts +205 -0
- package/corpus/templates/analytics/shared/session-events.ts +6 -0
- package/corpus/templates/assets/CHANGELOG.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +51 -117
- package/corpus/templates/assets/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +34 -101
- package/corpus/templates/brain/app/routes/sources.tsx +1 -1
- package/corpus/templates/brain/vitest.config.ts +7 -0
- package/corpus/templates/calendar/CHANGELOG.md +12 -0
- package/corpus/templates/calendar/actions/create-event.ts +2 -4
- package/corpus/templates/calendar/actions/update-event.ts +35 -6
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-10-16-booking-links-show-localized-visibility-badges.md +6 -0
- package/corpus/templates/calendar/changelog/2026-10-21-solo-events-avoid-notification-approval.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +62 -101
- package/corpus/templates/clips/CHANGELOG.md +7 -20
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +20 -77
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +63 -90
- package/corpus/templates/clips/app/components/sharing/share-test-support.tsx +180 -0
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -584
- package/corpus/templates/clips/changelog/2026-10-16-share-dialogs-make-it-easier-to-see-who-has-access-and-manag.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-21-share-panels-describe-general-access-in-a-sentence.md +6 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -3
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/actions/_browser-document-save-attempt.ts +23 -1
- package/corpus/templates/content/actions/_builder-cms-blob-custody.ts +467 -0
- package/corpus/templates/content/actions/_builder-cms-execution-lease.ts +17 -0
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +5 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +881 -21
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +28 -2
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +109 -11
- package/corpus/templates/content/actions/_builder-docs-client.ts +1 -0
- package/corpus/templates/content/actions/_builder-private-blob.test-fixture.ts +90 -0
- package/corpus/templates/content/actions/_builder-source-execution-guard.ts +48 -0
- package/corpus/templates/content/actions/_content-save-outcomes.ts +5 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +290 -8
- package/corpus/templates/content/actions/_database-utils.ts +93 -7
- package/corpus/templates/content/actions/_database-view-setup.ts +21 -2
- package/corpus/templates/content/actions/_delete-content-space.ts +8 -1
- package/corpus/templates/content/actions/_github-source-freshness.ts +30 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -6
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +110 -26
- package/corpus/templates/content/actions/change-content-database-source-role.ts +51 -7
- package/corpus/templates/content/actions/delete-document.ts +41 -3
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +68 -2
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +33 -2
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +900 -140
- package/corpus/templates/content/actions/get-document.ts +2 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +6 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +155 -13
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +299 -73
- package/corpus/templates/content/actions/set-live-body-switch.ts +45 -0
- package/corpus/templates/content/actions/update-document.ts +139 -20
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +135 -26
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +119 -30
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +56 -13
- package/corpus/templates/content/app/components/editor/SuggestionText.tsx +18 -3
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +89 -22
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +23 -0
- package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database/ListItemLayout.tsx +32 -8
- package/corpus/templates/content/app/components/editor/database/ListItemRow.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +1 -0
- package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +383 -34
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +31 -0
- package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +82 -4
- package/corpus/templates/content/app/global.css +31 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +40 -2
- package/corpus/templates/content/app/hooks/use-documents.ts +14 -0
- package/corpus/templates/content/app/i18n-data.ts +1 -0
- package/corpus/templates/content/changelog/2026-10-16-accepting-a-suggestion-on-a-page-that-changed-since-it-was-s.md +6 -0
- package/corpus/templates/content/changelog/2026-10-17-builder-content-avoids-retrying-a-write-when-builder-accepte.md +6 -0
- package/corpus/templates/content/changelog/2026-10-18-link-a-new-collection-to-a-github-folder-from-its-sources.md +1 -1
- package/corpus/templates/content/changelog/2026-10-20-builder-content-sync-keeps-read-and-write-status-accurate-wh.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-suggested-edits-that-add-remove-split-or-merge-paragraphs-li.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-list-rows-can-show-each-pages-first-lines.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-collection-linked-to-a-big-github-folder-fills-faster-and-p.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.source.adapters.md +29 -0
- package/corpus/templates/content/parity/matrix.md +42 -42
- package/corpus/templates/content/parity/matrix.ts +3 -1
- package/corpus/templates/content/server/db/schema.ts +20 -0
- package/corpus/templates/content/server/lib/content-trash-purge.ts +15 -1
- package/corpus/templates/content/server/lib/live-body-writer.ts +138 -26
- package/corpus/templates/content/server/live-copy/binding.ts +31 -0
- package/corpus/templates/content/server/live-copy/bounded-task.d.ts +6 -0
- package/corpus/templates/content/server/live-copy/exec-db.ts +1 -0
- package/corpus/templates/content/server/live-copy/holds.ts +59 -0
- package/corpus/templates/content/server/live-copy/persist.ts +656 -0
- package/corpus/templates/content/server/live-copy/switch.ts +136 -0
- package/corpus/templates/content/server/live-copy/task-names.ts +4 -0
- package/corpus/templates/content/server/live-copy/tasks.ts +183 -0
- package/corpus/templates/content/server/live-copy/write-cause.ts +85 -0
- package/corpus/templates/content/server/live-copy/write.ts +85 -0
- package/corpus/templates/content/server/plugins/builder-private-payload-cleanup.ts +22 -0
- package/corpus/templates/content/server/plugins/collab.ts +3 -0
- package/corpus/templates/content/server/plugins/db.ts +28 -0
- package/corpus/templates/content/shared/api.ts +30 -1
- package/corpus/templates/content/shared/database-item-layout.ts +54 -22
- package/corpus/templates/content/shared/document-intent-merge.ts +16 -9
- package/corpus/templates/content/shared/og-description.ts +258 -36
- package/corpus/templates/content/shared/suggestion-diff.ts +23 -6
- package/corpus/templates/content/shared/suggestion-formatting.ts +44 -14
- package/corpus/templates/content/shared/suggestion-text.ts +20 -5
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +5 -1
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +25 -4
- package/corpus/templates/design/CHANGELOG.md +5 -0
- package/corpus/templates/design/actions/get-getting-started.ts +53 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +10 -0
- package/corpus/templates/design/app/components/design/bridge/native-shader-runtime.bridge.ts +132 -79
- package/corpus/templates/design/app/components/design/bridge/native-source-provider.ts +268 -130
- package/corpus/templates/design/app/components/design/bridge/native-worker-scene-host.ts +122 -42
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +41 -4
- package/corpus/templates/design/app/components/design/design-canvas/text-content-change-result.ts +46 -12
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +15 -8
- package/corpus/templates/design/app/components/layout/GettingStarted.tsx +50 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +3 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateGrid.tsx +163 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateLibrary.tsx +65 -78
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +6 -2
- package/corpus/templates/design/app/global.css +6 -0
- package/corpus/templates/design/app/i18n/en-US.ts +17 -0
- package/corpus/templates/design/app/lib/canvas-load-outcome.ts +147 -0
- package/corpus/templates/design/app/lib/canvas-outcome-tracking.ts +531 -0
- package/corpus/templates/design/app/lib/canvas-style-kind.ts +50 -0
- package/corpus/templates/design/app/pages/DesignSystems.tsx +1 -1
- package/corpus/templates/design/app/pages/Index.tsx +28 -67
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +86 -29
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +38 -3
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-core.ts +9 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-files-and-saving.ts +2 -0
- package/corpus/templates/design/changelog/2026-10-16-design-pages-use-localized-visibility-badges-and-a-shared-ow.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-a-getting-started-checklist-at-the-bottom-of-the-sidebar-tra.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-templates-now-open-a-read-only-preview-from-the-card-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-collapsed-shader-layers-no-longer-interrupt-other-shaders-on.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-shader-fills-keep-rendering-when-other-screen-content-cannot.md +6 -0
- package/corpus/templates/design/scripts/design-export-validation/export-baseline.json +24 -0
- package/corpus/templates/design/server/lib/getting-started.ts +267 -0
- package/corpus/templates/design/server/plugins/getting-started.ts +5 -0
- package/corpus/templates/design/shared/design-template-presets/analytics-dashboard.ts +127 -0
- package/corpus/templates/design/shared/design-template-presets/design-studio.ts +98 -0
- package/corpus/templates/design/shared/design-template-presets/messaging-app.ts +101 -0
- package/corpus/templates/design/shared/design-template-presets/project-tasks.ts +120 -0
- package/corpus/templates/design/shared/design-template-presets.ts +8 -0
- package/corpus/templates/dispatch/CHANGELOG.md +4 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +75 -0
- package/corpus/templates/dispatch/changelog/2026-10-21-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +34 -100
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +1 -1
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/plan/CHANGELOG.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +34 -109
- package/corpus/templates/plan/changelog/2026-10-16-owned-and-shared-chats-appear-in-separate-history-sections.md +6 -0
- package/corpus/templates/slides/CHANGELOG.md +7 -0
- package/corpus/templates/slides/actions/delete-deck.ts +7 -0
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -1
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-10-16-deck-lists-use-the-shared-ownership-filter-and-visibility-ba.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-21-connected-deck-deletion-requires-approval.md +6 -0
- package/corpus/templates/slides/scripts/edit-fidelity/client-action.ts +61 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +10 -0
- package/package.json +1 -1
- package/corpus/templates/chat/app/lib/sidebar-thread-state.ts +0 -29
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +0 -83
|
@@ -1439,7 +1439,26 @@ function suggestionAnchorRange(
|
|
|
1439
1439
|
const collapsedRange = collapsedDeletionTextblock();
|
|
1440
1440
|
if (collapsedRange) return collapsedRange;
|
|
1441
1441
|
if (sourceMatches) {
|
|
1442
|
-
|
|
1442
|
+
// An empty paragraph has no text to map, so a span that opens or closes
|
|
1443
|
+
// with one maps the text beside it, or the place it starts when that's
|
|
1444
|
+
// all it holds.
|
|
1445
|
+
const emptyLine = "<empty-block/>";
|
|
1446
|
+
let mapFrom = sourceFrom;
|
|
1447
|
+
let mapTo = sourceTo;
|
|
1448
|
+
for (;;) {
|
|
1449
|
+
if (
|
|
1450
|
+
mapTo - mapFrom > emptyLine.length &&
|
|
1451
|
+
source.slice(mapTo - emptyLine.length - 1, mapTo) === `\n${emptyLine}`
|
|
1452
|
+
)
|
|
1453
|
+
mapTo -= emptyLine.length + 1;
|
|
1454
|
+
else if (
|
|
1455
|
+
mapTo - mapFrom > emptyLine.length &&
|
|
1456
|
+
source.startsWith(`${emptyLine}\n`, mapFrom)
|
|
1457
|
+
)
|
|
1458
|
+
mapFrom += emptyLine.length + 1;
|
|
1459
|
+
else break;
|
|
1460
|
+
}
|
|
1461
|
+
const exactRange = sourceRangeToPm(mapFrom, mapTo);
|
|
1443
1462
|
if (exactRange) return exactRange;
|
|
1444
1463
|
}
|
|
1445
1464
|
const mappedSource = suggestionAnchorText(source);
|
|
@@ -1592,11 +1611,18 @@ export function suggestionHighlightSpec(
|
|
|
1592
1611
|
editableText: true,
|
|
1593
1612
|
};
|
|
1594
1613
|
}
|
|
1614
|
+
// Removed syntax with no text, such as indentation, a list marker, or an
|
|
1615
|
+
// empty paragraph, is not in the document text, so it is drawn instead.
|
|
1595
1616
|
const structuralDeletion =
|
|
1596
1617
|
/^\n+$/.test(suggestionAnchorText(suggestion.beforeText)) ||
|
|
1597
1618
|
(beforePresentation &&
|
|
1598
1619
|
beforePresentation.length > 0 &&
|
|
1599
|
-
beforePresentation.every(
|
|
1620
|
+
beforePresentation.every(
|
|
1621
|
+
(node) =>
|
|
1622
|
+
node.type === "indent" ||
|
|
1623
|
+
node.type === "block" ||
|
|
1624
|
+
(node.type === "text" && /^↵+$/.test(node.value)),
|
|
1625
|
+
));
|
|
1600
1626
|
return {
|
|
1601
1627
|
suggestionId: suggestion.id,
|
|
1602
1628
|
kind:
|
|
@@ -4743,9 +4769,17 @@ export function VisualEditor({
|
|
|
4743
4769
|
const apply = (report = true) => {
|
|
4744
4770
|
if (editor.isDestroyed) return;
|
|
4745
4771
|
const specs = suggestions
|
|
4746
|
-
.map((suggestion) =>
|
|
4747
|
-
suggestionHighlightSpec(editor.state.doc, suggestion)
|
|
4748
|
-
|
|
4772
|
+
.map((suggestion) => {
|
|
4773
|
+
const spec = suggestionHighlightSpec(editor.state.doc, suggestion);
|
|
4774
|
+
// While suggesting, a saved suggestion's text outside the document
|
|
4775
|
+
// is somewhere to type beside, not a control to focus.
|
|
4776
|
+
return spec &&
|
|
4777
|
+
suggesting &&
|
|
4778
|
+
editable &&
|
|
4779
|
+
suggestion.presentation === "canonical"
|
|
4780
|
+
? { ...spec, editableBoundary: true }
|
|
4781
|
+
: spec;
|
|
4782
|
+
})
|
|
4749
4783
|
.filter((spec): spec is SuggestionHighlightSpec => spec !== null);
|
|
4750
4784
|
if (report)
|
|
4751
4785
|
onSuggestionAnchorsChange?.(
|
|
@@ -4771,8 +4805,10 @@ export function VisualEditor({
|
|
|
4771
4805
|
};
|
|
4772
4806
|
}, [
|
|
4773
4807
|
activeSuggestionId,
|
|
4808
|
+
editable,
|
|
4774
4809
|
editor,
|
|
4775
4810
|
onSuggestionAnchorsChange,
|
|
4811
|
+
suggesting,
|
|
4776
4812
|
suggestions,
|
|
4777
4813
|
suggestionsSignature,
|
|
4778
4814
|
showCommentIndicators,
|
|
@@ -4796,34 +4832,46 @@ export function VisualEditor({
|
|
|
4796
4832
|
};
|
|
4797
4833
|
}, [editor]);
|
|
4798
4834
|
|
|
4835
|
+
// Callers build the readbacks inline and render again on every report, so
|
|
4836
|
+
// these checks key on the readbacks' fields and report each divergent body
|
|
4837
|
+
// once: keyed on the objects, each report re-runs its check until React
|
|
4838
|
+
// aborts the render.
|
|
4839
|
+
const acceptedReadbackId = acceptedDecisionReadback?.id ?? null;
|
|
4840
|
+
const acceptedReadbackContent = acceptedDecisionReadback?.content ?? null;
|
|
4799
4841
|
useLayoutEffect(() => {
|
|
4800
|
-
if (
|
|
4842
|
+
if (
|
|
4843
|
+
!editor ||
|
|
4844
|
+
editor.isDestroyed ||
|
|
4845
|
+
acceptedReadbackId === null ||
|
|
4846
|
+
acceptedReadbackContent === null
|
|
4847
|
+
)
|
|
4848
|
+
return;
|
|
4801
4849
|
const settlingSuggestion = suggestions.find(
|
|
4802
|
-
(suggestion) => suggestion.id ===
|
|
4850
|
+
(suggestion) => suggestion.id === acceptedReadbackId,
|
|
4803
4851
|
);
|
|
4804
4852
|
if (!settlingSuggestion) return;
|
|
4853
|
+
let reported: string | null = null;
|
|
4805
4854
|
const check = () => {
|
|
4806
4855
|
if (editor.isDestroyed) return;
|
|
4807
4856
|
const actualContent = docToNfm(editor.getJSON() as any);
|
|
4808
4857
|
if (
|
|
4809
4858
|
acceptedSuggestionRendered(
|
|
4810
4859
|
actualContent,
|
|
4811
|
-
|
|
4860
|
+
acceptedReadbackContent,
|
|
4812
4861
|
settlingSuggestion,
|
|
4813
4862
|
)
|
|
4814
4863
|
) {
|
|
4815
|
-
onAcceptedDecisionRendered?.(
|
|
4864
|
+
onAcceptedDecisionRendered?.(acceptedReadbackId);
|
|
4816
4865
|
} else if (
|
|
4866
|
+
actualContent !== reported &&
|
|
4817
4867
|
acceptedSuggestionReadbackOutdated(
|
|
4818
4868
|
actualContent,
|
|
4819
|
-
|
|
4869
|
+
acceptedReadbackContent,
|
|
4820
4870
|
settlingSuggestion,
|
|
4821
4871
|
)
|
|
4822
4872
|
) {
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
actualContent,
|
|
4826
|
-
);
|
|
4873
|
+
reported = actualContent;
|
|
4874
|
+
onAcceptedDecisionReadbackOutdated?.(acceptedReadbackId, actualContent);
|
|
4827
4875
|
}
|
|
4828
4876
|
};
|
|
4829
4877
|
editor.on("transaction", check);
|
|
@@ -4832,27 +4880,44 @@ export function VisualEditor({
|
|
|
4832
4880
|
editor.off("transaction", check);
|
|
4833
4881
|
};
|
|
4834
4882
|
}, [
|
|
4835
|
-
|
|
4883
|
+
acceptedReadbackContent,
|
|
4884
|
+
acceptedReadbackId,
|
|
4836
4885
|
editor,
|
|
4837
4886
|
onAcceptedDecisionRendered,
|
|
4838
4887
|
onAcceptedDecisionReadbackOutdated,
|
|
4839
4888
|
suggestions,
|
|
4840
4889
|
]);
|
|
4841
4890
|
|
|
4891
|
+
const proposalReadbackGeneration =
|
|
4892
|
+
proposalDecisionReadback?.generation ?? null;
|
|
4893
|
+
const proposalReadbackContent = proposalDecisionReadback?.content ?? null;
|
|
4894
|
+
const proposalReadbackBefore =
|
|
4895
|
+
proposalDecisionReadback?.beforeContent ?? null;
|
|
4842
4896
|
useLayoutEffect(() => {
|
|
4843
|
-
if (
|
|
4897
|
+
if (
|
|
4898
|
+
!editor ||
|
|
4899
|
+
editor.isDestroyed ||
|
|
4900
|
+
proposalReadbackGeneration === null ||
|
|
4901
|
+
proposalReadbackContent === null ||
|
|
4902
|
+
proposalReadbackBefore === null
|
|
4903
|
+
)
|
|
4904
|
+
return;
|
|
4905
|
+
let reported: string | null = null;
|
|
4844
4906
|
const check = () => {
|
|
4845
4907
|
if (editor.isDestroyed) return;
|
|
4846
4908
|
const actual = canonicalizeNfm(docToNfm(editor.getJSON() as any));
|
|
4847
|
-
if (actual === canonicalizeNfm(
|
|
4848
|
-
onProposalDecisionRendered?.(
|
|
4909
|
+
if (actual === canonicalizeNfm(proposalReadbackContent))
|
|
4910
|
+
onProposalDecisionRendered?.(proposalReadbackGeneration);
|
|
4849
4911
|
else if (
|
|
4850
|
-
actual !==
|
|
4851
|
-
|
|
4912
|
+
actual !== reported &&
|
|
4913
|
+
actual !== canonicalizeNfm(proposalReadbackBefore)
|
|
4914
|
+
) {
|
|
4915
|
+
reported = actual;
|
|
4852
4916
|
onProposalDecisionReadbackOutdated?.(
|
|
4853
|
-
|
|
4917
|
+
proposalReadbackGeneration,
|
|
4854
4918
|
actual,
|
|
4855
4919
|
);
|
|
4920
|
+
}
|
|
4856
4921
|
};
|
|
4857
4922
|
editor.on("transaction", check);
|
|
4858
4923
|
check();
|
|
@@ -4863,7 +4928,9 @@ export function VisualEditor({
|
|
|
4863
4928
|
editor,
|
|
4864
4929
|
onProposalDecisionReadbackOutdated,
|
|
4865
4930
|
onProposalDecisionRendered,
|
|
4866
|
-
|
|
4931
|
+
proposalReadbackBefore,
|
|
4932
|
+
proposalReadbackContent,
|
|
4933
|
+
proposalReadbackGeneration,
|
|
4867
4934
|
]);
|
|
4868
4935
|
|
|
4869
4936
|
useEffect(() => {
|
|
@@ -1232,6 +1232,18 @@ function DatabaseTable({
|
|
|
1232
1232
|
if (panel !== "source") sourceHandoffActiveRef.current = false;
|
|
1233
1233
|
setSettingsPanel(panel);
|
|
1234
1234
|
};
|
|
1235
|
+
// Opens Sources at one source's own page, as the GitHub status line's
|
|
1236
|
+
// "From the … folder" does; each request has a new id so a repeat opens it.
|
|
1237
|
+
const [sourceNavRequest, setSourceNavRequest] =
|
|
1238
|
+
useState<SourceNavRequest | null>(null);
|
|
1239
|
+
const openGitHubSource = () => {
|
|
1240
|
+
changeDatabaseSettingsPanel("source");
|
|
1241
|
+
setSourceNavRequest((request) => ({
|
|
1242
|
+
id: (request?.id ?? 0) + 1,
|
|
1243
|
+
stack: [{ kind: "github" }],
|
|
1244
|
+
}));
|
|
1245
|
+
setSettingsOpen(true);
|
|
1246
|
+
};
|
|
1235
1247
|
const [savedViewConfig, setSavedViewConfig] =
|
|
1236
1248
|
useState<ContentDatabaseViewConfig>(defaultDatabaseViewConfig());
|
|
1237
1249
|
const [personalQueryDirty, setPersonalQueryDirty] = useState(false);
|
|
@@ -3532,6 +3544,7 @@ function DatabaseTable({
|
|
|
3532
3544
|
documentId={document.id}
|
|
3533
3545
|
canEdit={canEdit}
|
|
3534
3546
|
pageCount={totalItemCount}
|
|
3547
|
+
onOpenSource={canEditWidgetRows ? undefined : openGitHubSource}
|
|
3535
3548
|
/>
|
|
3536
3549
|
{canEdit &&
|
|
3537
3550
|
databaseId &&
|
|
@@ -4082,6 +4095,7 @@ function DatabaseTable({
|
|
|
4082
4095
|
}
|
|
4083
4096
|
sourcePendingOperations={sourcePendingOperations}
|
|
4084
4097
|
preserveSourceNavigationOnClose={preserveSourceNavigationOnClose}
|
|
4098
|
+
sourceNavRequest={sourceNavRequest}
|
|
4085
4099
|
onViewTypeChange={(type) =>
|
|
4086
4100
|
setViewConfig(updateDatabaseViewType(viewConfig, activeView.id, type))
|
|
4087
4101
|
}
|
|
@@ -7927,6 +7941,9 @@ type SourceNavStep =
|
|
|
7927
7941
|
| { kind: "fieldPicker"; sourceId: string; sourceName: string }
|
|
7928
7942
|
| { kind: "github" };
|
|
7929
7943
|
|
|
7944
|
+
/** A request to open Sources at a given page; a new id repeats it. */
|
|
7945
|
+
type SourceNavRequest = { id: number; stack: SourceNavStep[] };
|
|
7946
|
+
|
|
7930
7947
|
function sourceNavTitle(stack: SourceNavStep[]): string {
|
|
7931
7948
|
const top = stack[stack.length - 1];
|
|
7932
7949
|
if (!top) return dbText("sources");
|
|
@@ -8007,6 +8024,7 @@ function DatabaseSettingsPanelSheet({
|
|
|
8007
8024
|
sourceActionPending,
|
|
8008
8025
|
sourcePendingOperations,
|
|
8009
8026
|
preserveSourceNavigationOnClose,
|
|
8027
|
+
sourceNavRequest,
|
|
8010
8028
|
onViewTypeChange,
|
|
8011
8029
|
onWrapCellsChange,
|
|
8012
8030
|
onOpenPagesInChange,
|
|
@@ -8060,6 +8078,7 @@ function DatabaseSettingsPanelSheet({
|
|
|
8060
8078
|
sourceActionPending: boolean;
|
|
8061
8079
|
sourcePendingOperations: DatabaseSourcePendingOperations;
|
|
8062
8080
|
preserveSourceNavigationOnClose: boolean;
|
|
8081
|
+
sourceNavRequest: SourceNavRequest | null;
|
|
8063
8082
|
onViewTypeChange: (type: ContentDatabaseViewType) => void;
|
|
8064
8083
|
onWrapCellsChange: (wrapCells: boolean) => void;
|
|
8065
8084
|
onOpenPagesInChange: (openPagesIn: ContentDatabaseOpenPagesIn) => void;
|
|
@@ -8113,6 +8132,10 @@ function DatabaseSettingsPanelSheet({
|
|
|
8113
8132
|
setSourceNavStack([]);
|
|
8114
8133
|
}
|
|
8115
8134
|
}, [open, panel, preserveSourceNavigationOnClose]);
|
|
8135
|
+
// Runs after the reset above, so a request that opens the sheet keeps its page.
|
|
8136
|
+
useEffect(() => {
|
|
8137
|
+
if (sourceNavRequest) setSourceNavStack(sourceNavRequest.stack);
|
|
8138
|
+
}, [sourceNavRequest]);
|
|
8116
8139
|
|
|
8117
8140
|
const title =
|
|
8118
8141
|
panel === "main"
|
|
@@ -312,11 +312,14 @@ export function GitHubSourceStatusLine({
|
|
|
312
312
|
documentId,
|
|
313
313
|
canEdit,
|
|
314
314
|
pageCount,
|
|
315
|
+
onOpenSource,
|
|
315
316
|
}: {
|
|
316
317
|
source: ContentDatabaseSource | null;
|
|
317
318
|
documentId: string;
|
|
318
319
|
canEdit: boolean;
|
|
319
320
|
pageCount: number;
|
|
321
|
+
/** Opens the folder's page in Sources; without it, the folder is plain text. */
|
|
322
|
+
onOpenSource?: () => void;
|
|
320
323
|
}) {
|
|
321
324
|
const now = useNow();
|
|
322
325
|
const [unlinkOpen, setUnlinkOpen] = useState(false);
|
|
@@ -334,6 +337,7 @@ export function GitHubSourceStatusLine({
|
|
|
334
337
|
documentId={documentId}
|
|
335
338
|
canEdit={canEdit}
|
|
336
339
|
pageCount={pageCount}
|
|
340
|
+
onOpenSource={onOpenSource}
|
|
337
341
|
detailsOpen={detailsOpen}
|
|
338
342
|
onDetailsOpenChange={setDetailsOpen}
|
|
339
343
|
unlinkOpen={unlinkOpen}
|
|
@@ -349,6 +353,7 @@ function GitHubStatusLineContent({
|
|
|
349
353
|
documentId,
|
|
350
354
|
canEdit,
|
|
351
355
|
pageCount,
|
|
356
|
+
onOpenSource,
|
|
352
357
|
detailsOpen,
|
|
353
358
|
onDetailsOpenChange,
|
|
354
359
|
unlinkOpen,
|
|
@@ -360,6 +365,7 @@ function GitHubStatusLineContent({
|
|
|
360
365
|
documentId: string;
|
|
361
366
|
canEdit: boolean;
|
|
362
367
|
pageCount: number;
|
|
368
|
+
onOpenSource?: () => void;
|
|
363
369
|
detailsOpen: boolean;
|
|
364
370
|
onDetailsOpenChange: (open: boolean) => void;
|
|
365
371
|
unlinkOpen: boolean;
|
|
@@ -387,8 +393,27 @@ function GitHubStatusLineContent({
|
|
|
387
393
|
<div className="-m-px overflow-hidden p-px">
|
|
388
394
|
<div className="-ms-3 flex min-w-0 flex-wrap items-center gap-y-1 text-muted-foreground">
|
|
389
395
|
<Dotted>
|
|
390
|
-
|
|
391
|
-
|
|
396
|
+
{onOpenSource ? (
|
|
397
|
+
<button
|
|
398
|
+
type="button"
|
|
399
|
+
onClick={onOpenSource}
|
|
400
|
+
className="inline-flex min-w-0 items-center rounded-sm text-start underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
401
|
+
>
|
|
402
|
+
<IconBrandGithub
|
|
403
|
+
className="me-1.5 size-3.5 shrink-0"
|
|
404
|
+
aria-hidden
|
|
405
|
+
/>
|
|
406
|
+
<FromFolder status={status} />
|
|
407
|
+
</button>
|
|
408
|
+
) : (
|
|
409
|
+
<>
|
|
410
|
+
<IconBrandGithub
|
|
411
|
+
className="me-1.5 size-3.5 shrink-0"
|
|
412
|
+
aria-hidden
|
|
413
|
+
/>
|
|
414
|
+
<FromFolder status={status} />
|
|
415
|
+
</>
|
|
416
|
+
)}
|
|
392
417
|
</Dotted>
|
|
393
418
|
{stops ? null : (
|
|
394
419
|
<Dotted>
|
|
@@ -93,6 +93,7 @@ function PropertyChoices({
|
|
|
93
93
|
selectedIds: savedIds,
|
|
94
94
|
multiple,
|
|
95
95
|
noneLabel,
|
|
96
|
+
otherChoice,
|
|
96
97
|
onChange,
|
|
97
98
|
}: {
|
|
98
99
|
label: string;
|
|
@@ -100,6 +101,8 @@ function PropertyChoices({
|
|
|
100
101
|
selectedIds: string[];
|
|
101
102
|
multiple: boolean;
|
|
102
103
|
noneLabel?: string;
|
|
104
|
+
/** A choice that isn't a property, listed after Nothing (Line 2's page text). */
|
|
105
|
+
otherChoice?: { label: string; selected: boolean; onSelect: () => void };
|
|
103
106
|
onChange: (ids: string[]) => void;
|
|
104
107
|
}) {
|
|
105
108
|
// A saved slot can name a property this menu doesn't offer: one hidden, or
|
|
@@ -107,8 +110,11 @@ function PropertyChoices({
|
|
|
107
110
|
// In Line 3 and End it stays saved for when it's shown again.
|
|
108
111
|
const offeredIds = properties.map((property) => property.definition.id);
|
|
109
112
|
const selectedIds = savedIds.filter((id) => offeredIds.includes(id));
|
|
110
|
-
const rows = [
|
|
113
|
+
const rows: Array<{ id: string; name: string; other?: true }> = [
|
|
111
114
|
...(noneLabel ? [{ id: "", name: noneLabel }] : []),
|
|
115
|
+
...(otherChoice
|
|
116
|
+
? [{ id: "", name: otherChoice.label, other: true as const }]
|
|
117
|
+
: []),
|
|
112
118
|
...properties.map((property) => ({
|
|
113
119
|
id: property.definition.id,
|
|
114
120
|
name: property.definition.name,
|
|
@@ -121,9 +127,11 @@ function PropertyChoices({
|
|
|
121
127
|
className="grid max-h-56 gap-0.5 overflow-y-auto"
|
|
122
128
|
>
|
|
123
129
|
{rows.map((row) => {
|
|
124
|
-
const selected = row.
|
|
125
|
-
?
|
|
126
|
-
:
|
|
130
|
+
const selected = row.other
|
|
131
|
+
? otherChoice!.selected
|
|
132
|
+
: row.id
|
|
133
|
+
? selectedIds.includes(row.id)
|
|
134
|
+
: selectedIds.length === 0 && !otherChoice?.selected;
|
|
127
135
|
const position = row.id ? selectedIds.indexOf(row.id) : -1;
|
|
128
136
|
const full =
|
|
129
137
|
multiple &&
|
|
@@ -132,12 +140,13 @@ function PropertyChoices({
|
|
|
132
140
|
selectedIds.length >= MAX_ITEM_LAYOUT_META_PROPERTIES;
|
|
133
141
|
return (
|
|
134
142
|
<button
|
|
135
|
-
key={row.id || "none"}
|
|
143
|
+
key={row.id || (row.other ? "other" : "none")}
|
|
136
144
|
type="button"
|
|
137
145
|
aria-pressed={selected}
|
|
138
146
|
disabled={full}
|
|
139
147
|
className="flex h-8 items-center gap-2 rounded px-2 text-left text-sm enabled:hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
|
|
140
148
|
onClick={() => {
|
|
149
|
+
if (row.other) return otherChoice!.onSelect();
|
|
141
150
|
if (!multiple) return onChange(row.id ? [row.id] : []);
|
|
142
151
|
onChange(
|
|
143
152
|
toggleContentDatabaseItemLayoutMetaProperty(
|
|
@@ -253,22 +262,37 @@ export function ListItemLayoutSlotEditor({
|
|
|
253
262
|
);
|
|
254
263
|
}
|
|
255
264
|
if (slot === "line2") {
|
|
265
|
+
const pageText = layout.line2.source === "page";
|
|
266
|
+
const { lines } = layout.line2;
|
|
256
267
|
return (
|
|
257
268
|
<div className="grid gap-2">
|
|
258
269
|
<PropertyChoices
|
|
259
270
|
label={label}
|
|
260
271
|
properties={itemLayoutLine2Candidates(properties)}
|
|
261
|
-
selectedIds={
|
|
272
|
+
selectedIds={
|
|
273
|
+
!pageText && layout.line2.propertyId
|
|
274
|
+
? [layout.line2.propertyId]
|
|
275
|
+
: []
|
|
276
|
+
}
|
|
262
277
|
multiple={false}
|
|
263
278
|
noneLabel={dbText("listRowsNothing")}
|
|
279
|
+
otherChoice={{
|
|
280
|
+
label: dbText("listRowsPageText"),
|
|
281
|
+
selected: pageText,
|
|
282
|
+
onSelect: () =>
|
|
283
|
+
onChange({
|
|
284
|
+
...layout,
|
|
285
|
+
line2: { source: "page", propertyId: null, lines },
|
|
286
|
+
}),
|
|
287
|
+
}}
|
|
264
288
|
onChange={([id]) =>
|
|
265
289
|
onChange({
|
|
266
290
|
...layout,
|
|
267
|
-
line2: {
|
|
291
|
+
line2: { propertyId: id ?? null, lines },
|
|
268
292
|
})
|
|
269
293
|
}
|
|
270
294
|
/>
|
|
271
|
-
{layout.line2.propertyId ? (
|
|
295
|
+
{pageText || layout.line2.propertyId ? (
|
|
272
296
|
<Segmented<1 | 2 | 3>
|
|
273
297
|
label={label}
|
|
274
298
|
value={layout.line2.lines}
|
|
@@ -7,7 +7,10 @@ import type {
|
|
|
7
7
|
ContentDatabaseItemLayoutSlot,
|
|
8
8
|
ResolvedContentDatabaseItemLayout,
|
|
9
9
|
} from "@shared/database-item-layout";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
buildListRowExcerpt,
|
|
12
|
+
stripMarkdownForPreview,
|
|
13
|
+
} from "@shared/og-description";
|
|
11
14
|
import {
|
|
12
15
|
isEmptyPropertyValue,
|
|
13
16
|
type DocumentPropertyOptionColor,
|
|
@@ -93,11 +96,29 @@ function line2Text(property: DocumentProperty) {
|
|
|
93
96
|
: value.trim();
|
|
94
97
|
}
|
|
95
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The first lines of a row's page. The list read sends an excerpt, and saving
|
|
101
|
+
* the page's body in this tab rebuilds it. Until a read brings one (right after
|
|
102
|
+
* Page text is picked), a body this tab already holds stands in.
|
|
103
|
+
*/
|
|
104
|
+
function pageExcerpt(item: ContentDatabaseItem) {
|
|
105
|
+
if (item.excerpt !== undefined) return item.excerpt;
|
|
106
|
+
return item.document.content
|
|
107
|
+
? buildListRowExcerpt({
|
|
108
|
+
content: item.document.content,
|
|
109
|
+
title: item.document.title,
|
|
110
|
+
})
|
|
111
|
+
: "";
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
/** The fields a slot shows, which can be set but blank on a given row. */
|
|
97
115
|
function slotFieldNames(
|
|
98
116
|
resolved: ResolvedContentDatabaseItemLayout<DocumentProperty>,
|
|
99
117
|
slot: ContentDatabaseItemLayoutSlot,
|
|
100
118
|
) {
|
|
119
|
+
if (slot === "line2" && resolved.line2.pageText) {
|
|
120
|
+
return [dbText("listRowsPageText")];
|
|
121
|
+
}
|
|
101
122
|
const fields =
|
|
102
123
|
slot === "line2"
|
|
103
124
|
? resolved.line2.property
|
|
@@ -305,7 +326,11 @@ export function DatabaseLayoutListRow({
|
|
|
305
326
|
const line2Property = resolved.line2.property
|
|
306
327
|
? itemValue(item, resolved.line2.property)
|
|
307
328
|
: null;
|
|
308
|
-
const line2 =
|
|
329
|
+
const line2 = resolved.line2.pageText
|
|
330
|
+
? pageExcerpt(item)
|
|
331
|
+
: line2Property
|
|
332
|
+
? line2Text(line2Property)
|
|
333
|
+
: "";
|
|
309
334
|
const filled = (properties: DocumentProperty[]) =>
|
|
310
335
|
properties
|
|
311
336
|
.map((property) => itemValue(item, property))
|
|
@@ -238,6 +238,7 @@ export function builderReviewRowCanCancelPrepared(
|
|
|
238
238
|
) {
|
|
239
239
|
const execution = row.execution;
|
|
240
240
|
if (!execution) return false;
|
|
241
|
+
if (execution.payloadUnavailable) return false;
|
|
241
242
|
if (
|
|
242
243
|
execution.state !== "ready" &&
|
|
243
244
|
execution.state !== "write_disabled" &&
|