@agent-native/core 0.157.3 → 0.157.4

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.
Files changed (152) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  3. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +21 -0
  4. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +40 -1
  5. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  6. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +21 -0
  7. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  8. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +21 -0
  9. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  10. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +21 -0
  11. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
  12. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  13. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  14. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  15. package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +7 -7
  16. package/corpus/templates/clips/actions/approve-recording-access-request.ts +147 -0
  17. package/corpus/templates/clips/actions/request-recording-access.ts +121 -23
  18. package/corpus/templates/clips/actions/view-screen.ts +1 -1
  19. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +34 -53
  20. package/corpus/templates/clips/app/components/player/request-access-dialog.tsx +104 -0
  21. package/corpus/templates/clips/app/components/player/share-dialog.tsx +36 -45
  22. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +3 -6
  23. package/corpus/templates/clips/app/i18n/en-US.ts +26 -1
  24. package/corpus/templates/clips/app/lib/public-meeting.ts +1 -1
  25. package/corpus/templates/clips/app/routes/access-request.approve.tsx +250 -0
  26. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -32
  27. package/corpus/templates/clips/app/routes/share.$shareId.tsx +123 -37
  28. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +41 -1
  29. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -0
  30. package/corpus/templates/clips/server/lib/emails.ts +40 -11
  31. package/corpus/templates/clips/shared/recording-link.ts +32 -1
  32. package/corpus/templates/clips/shared/share-attribution.ts +13 -0
  33. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  34. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +21 -0
  35. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +22 -10
  36. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +2 -1
  37. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +245 -9
  38. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +185 -134
  39. package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +61 -45
  40. package/corpus/templates/content/app/components/editor/extensions/ImageNode.ts +6 -0
  41. package/corpus/templates/content/app/components/editor/image-upload.ts +137 -5
  42. package/corpus/templates/content/app/global.css +8 -0
  43. package/corpus/templates/content/changelog/2026-08-12-image-uploads-now-confirm-the-image-can-be-displayed-before-.md +6 -0
  44. package/corpus/templates/content/changelog/2026-08-14-images-fill-the-page-width-by-default-and-remain-visible-whe.md +6 -0
  45. package/corpus/templates/content/changelog/2026-08-14-images-inserted-from-the-slash-command-stay-saved-after-uplo.md +6 -0
  46. package/corpus/templates/content/changelog/2026-08-14-svg-files-can-be-selected-reliably-from-the-image-picker.md +6 -0
  47. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  48. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +21 -0
  49. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  50. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +21 -0
  51. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  52. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +21 -0
  53. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  54. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +21 -0
  55. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  56. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +21 -0
  57. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  58. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +21 -0
  59. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  60. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +21 -0
  61. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +6 -1
  62. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  63. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +21 -0
  64. package/corpus/templates/plan/app/pages/PlansPage.tsx +25 -30
  65. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  66. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +21 -0
  67. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +2 -1
  68. package/corpus/templates/slides/app/components/editor/ShareDialog.tsx +124 -180
  69. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +1 -0
  70. package/corpus/templates/slides/app/global.css +99 -3
  71. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  72. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  73. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +21 -0
  74. package/dist/chat-threads/schema.d.ts +1 -1
  75. package/dist/cli/code-agent-executor.js +318 -0
  76. package/dist/client/AgentPanel.d.ts +13 -1
  77. package/dist/client/AgentPanel.js +41 -3
  78. package/dist/client/AssistantChat.d.ts +9 -1
  79. package/dist/client/AssistantChat.js +26 -13
  80. package/dist/client/MultiTabAssistantChat.js +18 -5
  81. package/dist/client/agent-chat.d.ts +8 -0
  82. package/dist/client/agent-chat.js +15 -0
  83. package/dist/client/app-chat-sidebar.d.ts +23 -0
  84. package/dist/client/app-chat-sidebar.js +53 -0
  85. package/dist/client/app-providers.js +31 -2
  86. package/dist/client/frame-protocol.d.ts +20 -2
  87. package/dist/client/hooks/index.d.ts +1 -0
  88. package/dist/client/hooks/index.js +1 -0
  89. package/dist/client/sharing/AgentShareSection.d.ts +8 -0
  90. package/dist/client/sharing/AgentShareSection.js +50 -0
  91. package/dist/client/sharing/ShareButton.js +2 -1
  92. package/dist/client/sharing/ShareDialog.d.ts +2 -2
  93. package/dist/client/sharing/ShareDialog.js +21 -29
  94. package/dist/client/sharing/index.d.ts +1 -0
  95. package/dist/client/sharing/index.js +1 -0
  96. package/dist/client/sharing/useShareButtonController.d.ts +1 -0
  97. package/dist/client/sharing/useShareDialogController.d.ts +3 -0
  98. package/dist/client/sharing/useShareDialogController.js +2 -1
  99. package/dist/client/theme.d.ts +21 -0
  100. package/dist/client/theme.js +60 -0
  101. package/dist/client/ui/index.d.ts +1 -1
  102. package/dist/client/ui/index.js +1 -1
  103. package/dist/client/use-session.js +23 -0
  104. package/dist/collab/awareness.d.ts +2 -2
  105. package/dist/collab/struct-routes.d.ts +1 -1
  106. package/dist/dashboard-storage/schema.d.ts +1 -1
  107. package/dist/data-programs/schema.d.ts +1 -1
  108. package/dist/extensions/schema.d.ts +1 -1
  109. package/dist/localization/core-messages/ar-SA.js +6 -0
  110. package/dist/localization/core-messages/de-DE.js +6 -0
  111. package/dist/localization/core-messages/en-US.d.ts +6 -0
  112. package/dist/localization/core-messages/en-US.js +6 -0
  113. package/dist/localization/core-messages/es-ES.js +6 -0
  114. package/dist/localization/core-messages/fr-FR.js +6 -0
  115. package/dist/localization/core-messages/hi-IN.js +6 -0
  116. package/dist/localization/core-messages/ja-JP.js +6 -0
  117. package/dist/localization/core-messages/ko-KR.js +6 -0
  118. package/dist/localization/core-messages/pt-BR.js +6 -0
  119. package/dist/localization/core-messages/zh-CN.js +6 -0
  120. package/dist/localization/core-messages/zh-TW.js +6 -0
  121. package/dist/localization/core-messages.d.ts +6 -0
  122. package/dist/localization/default-messages.d.ts +1 -0
  123. package/dist/localization/default-messages.js +1 -0
  124. package/dist/notifications/routes.d.ts +3 -3
  125. package/dist/progress/routes.d.ts +1 -1
  126. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  127. package/dist/provider-api/actions/provider-api.d.ts +14 -14
  128. package/dist/server/auth.js +8 -5
  129. package/dist/server/identity-sso-store.d.ts +6 -1
  130. package/dist/server/identity-sso-store.js +57 -14
  131. package/dist/server/identity-sso.d.ts +7 -8
  132. package/dist/server/identity-sso.js +15 -12
  133. package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
  134. package/dist/sharing/actions/list-resource-shares.js +1 -0
  135. package/dist/sharing/schema.d.ts +1 -1
  136. package/dist/sharing/schema.js +4 -1
  137. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  138. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  139. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  140. package/dist/templates/default/.agents/skills/sharing/SKILL.md +21 -0
  141. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  142. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  143. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
  144. package/docs/content/cross-app-sso.mdx +24 -17
  145. package/package.json +2 -2
  146. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  147. package/src/templates/chat/.agents/skills/sharing/SKILL.md +21 -0
  148. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  149. package/src/templates/default/.agents/skills/sharing/SKILL.md +21 -0
  150. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  151. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +5 -0
  152. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +21 -0
@@ -10,6 +10,7 @@ import {
10
10
  useBuilderConnectFlow,
11
11
  useBuilderStatus,
12
12
  } from "@agent-native/core/client/settings";
13
+ import { DataGrid, type DataGridColumn } from "@agent-native/toolkit/data-grid";
13
14
  import {
14
15
  CONTENT_DATABASE_PERSONAL_VIEW_OVERRIDES_VERSION,
15
16
  type BuilderCmsModelSummary,
@@ -4904,6 +4905,16 @@ function DatabaseItemPreview({
4904
4905
  if (controller) scheduleDraftWrite(controller);
4905
4906
  }
4906
4907
 
4908
+ async function handleContentSaveNow(nextContent: string) {
4909
+ setLocalContent(nextContent);
4910
+ if (!previewCanEdit || !document) return false;
4911
+ const controller = saveControllerRef.current;
4912
+ if (!controller) return false;
4913
+ controller.changeContent(nextContent);
4914
+ await controller.flush();
4915
+ return controller.lastSaved.content === nextContent;
4916
+ }
4917
+
4907
4918
  function keepLocalBodyDraft() {
4908
4919
  if (!activeBodyDraftConflict) return;
4909
4920
  const controller = peekPreviewDocumentSaveController(documentId);
@@ -5222,6 +5233,7 @@ function DatabaseItemPreview({
5222
5233
  documentId={previewDocument.id}
5223
5234
  content={localContent}
5224
5235
  onChange={handleContentChange}
5236
+ onSaveContent={handleContentSaveNow}
5225
5237
  ydoc={null}
5226
5238
  editable={previewCanEdit}
5227
5239
  />
@@ -5535,6 +5547,36 @@ function DatabaseTableView({
5535
5547
  const actionColumnWidth = cleanDefaultTable
5536
5548
  ? EMPTY_DEFAULT_ADD_PROPERTY_COLUMN_WIDTH
5537
5549
  : ACTION_COLUMN_WIDTH;
5550
+ const dataGridColumns = useMemo<DataGridColumn<ContentDatabaseItem>[]>(
5551
+ () => [
5552
+ {
5553
+ id: "name",
5554
+ width: DEFAULT_NAME_COLUMN_WIDTH,
5555
+ minWidth: MIN_COLUMN_WIDTH,
5556
+ maxWidth: MAX_COLUMN_WIDTH,
5557
+ resizable: false,
5558
+ },
5559
+ ...properties.map((property) => ({
5560
+ id: property.definition.id,
5561
+ width: DEFAULT_PROPERTY_COLUMN_WIDTH,
5562
+ minWidth: MIN_COLUMN_WIDTH,
5563
+ maxWidth: MAX_COLUMN_WIDTH,
5564
+ resizable: false,
5565
+ })),
5566
+ ...(canEdit
5567
+ ? [
5568
+ {
5569
+ id: "actions",
5570
+ width: actionColumnWidth,
5571
+ minWidth: actionColumnWidth,
5572
+ maxWidth: actionColumnWidth,
5573
+ resizable: false,
5574
+ },
5575
+ ]
5576
+ : []),
5577
+ ],
5578
+ [actionColumnWidth, canEdit, properties],
5579
+ );
5538
5580
  const rowDraggingEnabled =
5539
5581
  canEdit &&
5540
5582
  rowsAreManuallyOrdered &&
@@ -5884,12 +5926,18 @@ function DatabaseTableView({
5884
5926
  }}
5885
5927
  />
5886
5928
  ) : null}
5887
- <div
5888
- data-database-scroll-surface="table"
5889
- tabIndex={0}
5890
- className="w-full min-w-0 max-w-full overflow-x-auto overscroll-x-contain"
5891
- >
5892
- <div className="w-max min-w-full min-w-[720px]">
5929
+ {/* DataGrid preserves the table contract: data-database-scroll-surface="table", tabIndex={0}, and min-w-0 max-w-full overflow-x-auto. */}
5930
+ <DataGrid
5931
+ rows={items}
5932
+ columns={dataGridColumns}
5933
+ getRowId={(item) => item.id}
5934
+ columnWidths={columnWidths}
5935
+ contentClassName="min-w-[720px]"
5936
+ scrollContainerProps={{
5937
+ "data-database-scroll-surface": "table",
5938
+ tabIndex: 0,
5939
+ }}
5940
+ renderHeader={() => (
5893
5941
  <div
5894
5942
  className="grid border-y border-border/35 text-xs font-medium text-muted-foreground/80"
5895
5943
  style={{
@@ -5971,146 +6019,149 @@ function DatabaseTableView({
5971
6019
  </div>
5972
6020
  ) : null}
5973
6021
  </div>
5974
-
5975
- {databaseTableShouldShowBlockingLoader(isLoading, items.length) ? (
5976
- <div className="flex h-16 items-center gap-2 border-t border-border px-2 text-sm text-muted-foreground">
5977
- <Spinner className="size-4" />
5978
- {dbText("loadingDatabase")}
5979
- </div>
5980
- ) : (
5981
- <>
5982
- {databaseViewHasNoMatchingPages(
5983
- items.length,
5984
- hasSearch,
5985
- activeFilters.length,
5986
- ) ? (
5987
- <DatabaseNoMatchingPages
5988
- className="border-t border-border"
5989
- label={dbText("noRowsMatchThisView")}
5990
- onClear={onClearResultConstraints}
5991
- />
5992
- ) : null}
5993
- {grouped
5994
- ? groups.map((group) => (
5995
- <DatabaseGroupedTableSection
5996
- key={group.id}
5997
- group={group}
6022
+ )}
6023
+ renderBody={() => (
6024
+ <>
6025
+ {databaseTableShouldShowBlockingLoader(isLoading, items.length) ? (
6026
+ <div className="flex h-16 items-center gap-2 border-t border-border px-2 text-sm text-muted-foreground">
6027
+ <Spinner className="size-4" />
6028
+ {dbText("loadingDatabase")}
6029
+ </div>
6030
+ ) : (
6031
+ <>
6032
+ {databaseViewHasNoMatchingPages(
6033
+ items.length,
6034
+ hasSearch,
6035
+ activeFilters.length,
6036
+ ) ? (
6037
+ <DatabaseNoMatchingPages
6038
+ className="border-t border-border"
6039
+ label={dbText("noRowsMatchThisView")}
6040
+ onClear={onClearResultConstraints}
6041
+ />
6042
+ ) : null}
6043
+ {grouped
6044
+ ? groups.map((group) => (
6045
+ <DatabaseGroupedTableSection
6046
+ key={group.id}
6047
+ group={group}
6048
+ properties={properties}
6049
+ columnWidths={columnWidths}
6050
+ databaseDocumentId={databaseDocumentId}
6051
+ workspaceCatalog={isWorkspaceCatalog}
6052
+ workspaceCreationPropertyValues={
6053
+ workspaceCreationPropertyValues
6054
+ }
6055
+ canEdit={canEdit}
6056
+ selectedIdSet={selectedIdSet}
6057
+ wrapCells={wrapCells}
6058
+ rowDensity={rowDensity}
6059
+ isCreating={isCreating}
6060
+ newRowLabel={newRowLabel}
6061
+ focusedTitleDocumentId={focusedTitleDocumentId}
6062
+ collapsed={databaseGroupIsCollapsed(
6063
+ collapsedGroupIds,
6064
+ group.id,
6065
+ )}
6066
+ onCreateRow={onCreateGroupedRow}
6067
+ onTitleFocusHandled={onTitleFocusHandled}
6068
+ onCollapsedChange={(collapsed) =>
6069
+ onGroupCollapsedChange(group.id, collapsed)
6070
+ }
6071
+ onToggleCheckbox={toggleCheckboxCell}
6072
+ onToggleRowSelection={onToggleRowSelection}
6073
+ onPreview={onPreview}
6074
+ onDeletedPreviewItem={onDeletedPreviewItem}
6075
+ onOpenPage={onOpenPage}
6076
+ />
6077
+ ))
6078
+ : items.map((item, index) => (
6079
+ <DatabaseTableRow
6080
+ key={item.id}
6081
+ item={item}
6082
+ databaseDocumentId={databaseDocumentId}
6083
+ workspaceCatalog={isWorkspaceCatalog}
6084
+ properties={properties}
6085
+ columnWidths={columnWidths}
6086
+ canEdit={canEdit}
6087
+ rowIndex={index}
6088
+ canReorder={rowsAreManuallyOrdered}
6089
+ canDragRow={rowDraggingEnabled}
6090
+ canMoveUp={rowsAreManuallyOrdered && index > 0}
6091
+ canMoveDown={
6092
+ rowsAreManuallyOrdered && index < items.length - 1
6093
+ }
6094
+ selected={selectedIdSet.has(item.id)}
6095
+ isDragging={draggedItemId === item.id}
6096
+ isDropTarget={
6097
+ !!draggedItemId &&
6098
+ dropTargetItemId === item.id &&
6099
+ draggedItemId !== item.id
6100
+ }
6101
+ startEditingTitle={
6102
+ focusedTitleDocumentId === item.document.id
6103
+ }
6104
+ onDragHandlePointerDown={(event) =>
6105
+ startRowDrag(item.id, event)
6106
+ }
6107
+ onToggleCheckbox={(property) =>
6108
+ void toggleCheckboxCell(item, property)
6109
+ }
6110
+ wrapCells={wrapCells}
6111
+ rowDensity={rowDensity}
6112
+ onToggleSelected={() => onToggleRowSelection(item.id)}
6113
+ onPreviewItem={onPreview}
6114
+ onDeletedPreviewItem={onDeletedPreviewItem}
6115
+ onTitleEditStarted={onTitleFocusHandled}
6116
+ onPreview={() => onPreview(item)}
6117
+ onOpenPage={() => onOpenPage(item)}
6118
+ />
6119
+ ))}
6120
+ {canEdit && !grouped ? (
6121
+ isWorkspaceCatalog ? (
6122
+ <WorkspaceSourceMenuRow
6123
+ label={newRowLabel}
5998
6124
  properties={properties}
5999
6125
  columnWidths={columnWidths}
6000
- databaseDocumentId={databaseDocumentId}
6001
- workspaceCatalog={isWorkspaceCatalog}
6002
- workspaceCreationPropertyValues={
6003
- workspaceCreationPropertyValues
6004
- }
6005
- canEdit={canEdit}
6006
- selectedIdSet={selectedIdSet}
6007
- wrapCells={wrapCells}
6008
6126
  rowDensity={rowDensity}
6009
- isCreating={isCreating}
6010
- newRowLabel={newRowLabel}
6011
- focusedTitleDocumentId={focusedTitleDocumentId}
6012
- collapsed={databaseGroupIsCollapsed(
6013
- collapsedGroupIds,
6014
- group.id,
6015
- )}
6016
- onCreateRow={onCreateGroupedRow}
6017
- onTitleFocusHandled={onTitleFocusHandled}
6018
- onCollapsedChange={(collapsed) =>
6019
- onGroupCollapsedChange(group.id, collapsed)
6020
- }
6021
- onToggleCheckbox={toggleCheckboxCell}
6022
- onToggleRowSelection={onToggleRowSelection}
6023
- onPreview={onPreview}
6024
- onDeletedPreviewItem={onDeletedPreviewItem}
6025
- onOpenPage={onOpenPage}
6127
+ propertyValues={workspaceCreationPropertyValues}
6128
+ actionColumnWidth={actionColumnWidth}
6026
6129
  />
6027
- ))
6028
- : items.map((item, index) => (
6029
- <DatabaseTableRow
6030
- key={item.id}
6031
- item={item}
6032
- databaseDocumentId={databaseDocumentId}
6033
- workspaceCatalog={isWorkspaceCatalog}
6130
+ ) : (
6131
+ <NewDatabaseRow
6132
+ label={newRowLabel}
6034
6133
  properties={properties}
6035
6134
  columnWidths={columnWidths}
6036
- canEdit={canEdit}
6037
- rowIndex={index}
6038
- canReorder={rowsAreManuallyOrdered}
6039
- canDragRow={rowDraggingEnabled}
6040
- canMoveUp={rowsAreManuallyOrdered && index > 0}
6041
- canMoveDown={
6042
- rowsAreManuallyOrdered && index < items.length - 1
6043
- }
6044
- selected={selectedIdSet.has(item.id)}
6045
- isDragging={draggedItemId === item.id}
6046
- isDropTarget={
6047
- !!draggedItemId &&
6048
- dropTargetItemId === item.id &&
6049
- draggedItemId !== item.id
6050
- }
6051
- startEditingTitle={
6052
- focusedTitleDocumentId === item.document.id
6053
- }
6054
- onDragHandlePointerDown={(event) =>
6055
- startRowDrag(item.id, event)
6056
- }
6057
- onToggleCheckbox={(property) =>
6058
- void toggleCheckboxCell(item, property)
6059
- }
6060
- wrapCells={wrapCells}
6061
6135
  rowDensity={rowDensity}
6062
- onToggleSelected={() => onToggleRowSelection(item.id)}
6063
- onPreviewItem={onPreview}
6064
- onDeletedPreviewItem={onDeletedPreviewItem}
6065
- onTitleEditStarted={onTitleFocusHandled}
6066
- onPreview={() => onPreview(item)}
6067
- onOpenPage={() => onOpenPage(item)}
6136
+ disabled={isCreating}
6137
+ isPending={isCreating}
6138
+ onCreate={onCreateRow}
6139
+ actionColumnWidth={actionColumnWidth}
6068
6140
  />
6069
- ))}
6070
- {canEdit && !grouped ? (
6071
- isWorkspaceCatalog ? (
6072
- <WorkspaceSourceMenuRow
6073
- label={newRowLabel}
6074
- properties={properties}
6075
- columnWidths={columnWidths}
6076
- rowDensity={rowDensity}
6077
- propertyValues={workspaceCreationPropertyValues}
6078
- actionColumnWidth={actionColumnWidth}
6079
- />
6080
- ) : (
6081
- <NewDatabaseRow
6082
- label={newRowLabel}
6083
- properties={properties}
6084
- columnWidths={columnWidths}
6085
- rowDensity={rowDensity}
6086
- disabled={isCreating}
6087
- isPending={isCreating}
6088
- onCreate={onCreateRow}
6141
+ )
6142
+ ) : null}
6143
+ {cleanDefaultTable ? (
6144
+ <DatabaseBlankDefaultRows
6145
+ rowCount={EMPTY_DEFAULT_BLANK_ROW_COUNT}
6089
6146
  actionColumnWidth={actionColumnWidth}
6090
6147
  />
6091
- )
6092
- ) : null}
6093
- {cleanDefaultTable ? (
6094
- <DatabaseBlankDefaultRows
6095
- rowCount={EMPTY_DEFAULT_BLANK_ROW_COUNT}
6148
+ ) : null}
6149
+ <DatabaseTableFooter
6150
+ properties={properties}
6151
+ items={items}
6152
+ totalCount={totalCount}
6153
+ constrained={constrained}
6154
+ columnWidths={columnWidths}
6155
+ canEdit={canEdit}
6156
+ calculations={calculations}
6096
6157
  actionColumnWidth={actionColumnWidth}
6158
+ onCalculationChange={onCalculationChange}
6097
6159
  />
6098
- ) : null}
6099
- <DatabaseTableFooter
6100
- properties={properties}
6101
- items={items}
6102
- totalCount={totalCount}
6103
- constrained={constrained}
6104
- columnWidths={columnWidths}
6105
- canEdit={canEdit}
6106
- calculations={calculations}
6107
- actionColumnWidth={actionColumnWidth}
6108
- onCalculationChange={onCalculationChange}
6109
- />
6110
- </>
6111
- )}
6112
- </div>
6113
- </div>
6160
+ </>
6161
+ )}
6162
+ </>
6163
+ )}
6164
+ />
6114
6165
  <AlertDialog
6115
6166
  open={
6116
6167
  !removesFavoriteMembership &&
@@ -22,7 +22,6 @@ import {
22
22
  } from "@tabler/icons-react";
23
23
  import { NodeViewWrapper, type NodeViewProps } from "@tiptap/react";
24
24
  import {
25
- type ChangeEvent,
26
25
  type FormEvent,
27
26
  type PointerEvent as ReactPointerEvent,
28
27
  useEffect,
@@ -52,7 +51,7 @@ import {
52
51
  TooltipTrigger,
53
52
  } from "@/components/ui/tooltip";
54
53
 
55
- import { imageUploadErrorMessage, uploadImageFile } from "../image-upload";
54
+ import { createImagePickerId } from "../image-upload";
56
55
  import type { ContentImageOptions } from "./ImageNode";
57
56
 
58
57
  type ImageSourceTab = "upload" | "assets" | "link";
@@ -69,7 +68,6 @@ const MIN_IMAGE_WIDTH = 160;
69
68
  const MAX_AGENT_IMAGE_DIMENSION = 1600;
70
69
  const ALT_TEXT_CONTEXT_WORD_LIMIT = 250;
71
70
  const DEFAULT_ASSETS_PICKER_URL = "https://assets.agent-native.com/picker";
72
-
73
71
  interface PickedAssetImagePayload {
74
72
  url?: unknown;
75
73
  previewUrl?: unknown;
@@ -515,7 +513,6 @@ export function ImageBlock({
515
513
  const [moreMenuOpen, setMoreMenuOpen] = useState(false);
516
514
  const [isGeneratingAlt, setIsGeneratingAlt] = useState(false);
517
515
  const [imageLoadFailed, setImageLoadFailed] = useState(false);
518
- const fileInputRef = useRef<HTMLInputElement>(null);
519
516
  const altInputRef = useRef<HTMLInputElement>(null);
520
517
  const emptyBlockRef = useRef<HTMLDivElement>(null);
521
518
  const lightboxImageRef = useRef<HTMLImageElement>(null);
@@ -524,7 +521,9 @@ export function ImageBlock({
524
521
  const isEditable = editor.isEditable;
525
522
  const src = node.attrs.src as string;
526
523
  const alt = (node.attrs.alt as string) || "";
527
- const isUploading = Boolean(node.attrs.uploadId);
524
+ const isUploading = String(node.attrs.uploadId ?? "").startsWith(
525
+ "image-upload-",
526
+ );
528
527
  const width = normalizedImageWidth(node.attrs.width);
529
528
  const activeWidth = dragWidth ?? width;
530
529
  const controlsVisible = isEditable && (isHovered || selected);
@@ -546,6 +545,12 @@ export function ImageBlock({
546
545
  ) {
547
546
  return;
548
547
  }
548
+ if (
549
+ !src &&
550
+ String(node.attrs.uploadId ?? "").startsWith("image-picker-")
551
+ ) {
552
+ updateAttributes({ uploadId: null });
553
+ }
549
554
  setSourcePanelOpen(false);
550
555
  setSourcePanelDismissed(true);
551
556
  }
@@ -553,7 +558,7 @@ export function ImageBlock({
553
558
  document.addEventListener("pointerdown", handlePointerDown, true);
554
559
  return () =>
555
560
  document.removeEventListener("pointerdown", handlePointerDown, true);
556
- }, [selected, sourcePanelOpen]);
561
+ }, [node.attrs.uploadId, selected, sourcePanelOpen, src, updateAttributes]);
557
562
 
558
563
  function handleComment() {
559
564
  if (!options.onImageComment) return;
@@ -761,20 +766,25 @@ export function ImageBlock({
761
766
  };
762
767
  }, [updateAttributes]);
763
768
 
764
- async function handleImageFilePicked(event: ChangeEvent<HTMLInputElement>) {
765
- const file = event.currentTarget.files?.[0];
766
- event.currentTarget.value = "";
767
- if (!file) return;
769
+ function restoreEmptyPlaceholderSelection() {
770
+ if (src || typeof getPos !== "function") return;
771
+ const position = getPos();
772
+ if (typeof position !== "number") return;
773
+ editor.chain().focus().setNodeSelection(position).run();
774
+ }
768
775
 
769
- const toastId = toast.loading(t("editor.media.uploadingImage"));
770
- try {
771
- const nextSrc = await uploadImageFile(file);
772
- updateAttributes({ src: nextSrc });
773
- setSourcePanelOpen(false);
774
- toast.success(t("editor.media.imageAdded"), { id: toastId });
775
- } catch (error) {
776
- toast.error(imageUploadErrorMessage(error), { id: toastId });
777
- }
776
+ function handleImageFileSelectionStart() {
777
+ if (isUploading) return;
778
+ if (typeof getPos !== "function") return;
779
+ const position = getPos();
780
+ if (typeof position !== "number") return;
781
+ const pickerId = String(node.attrs.uploadId || createImagePickerId());
782
+ if (!node.attrs.uploadId) updateAttributes({ uploadId: pickerId });
783
+ options.onImageFilePickerRequest?.({
784
+ pickerId,
785
+ position,
786
+ attrs: { ...node.attrs, uploadId: pickerId },
787
+ });
778
788
  }
779
789
 
780
790
  function handleEmbedLink(event: FormEvent<HTMLFormElement>) {
@@ -792,7 +802,7 @@ export function ImageBlock({
792
802
  return;
793
803
  }
794
804
 
795
- updateAttributes({ src: nextSrc, alt });
805
+ updateAttributes({ src: nextSrc, alt, uploadId: null });
796
806
  setImageUrl("");
797
807
  setSourcePanelOpen(false);
798
808
  }
@@ -811,6 +821,10 @@ export function ImageBlock({
811
821
  function handleAssetsPickerMessage(name: string, payload: unknown) {
812
822
  if (name === "close") {
813
823
  setAssetsPickerOpen(false);
824
+ if (!src) {
825
+ updateAttributes({ uploadId: null });
826
+ restoreEmptyPlaceholderSelection();
827
+ }
814
828
  return;
815
829
  }
816
830
 
@@ -824,16 +838,25 @@ export function ImageBlock({
824
838
  updateAttributes({
825
839
  src: nextSrc,
826
840
  alt: pickedAssetImageAlt(payload) ?? alt,
841
+ uploadId: null,
827
842
  });
828
843
  setAssetsPickerOpen(false);
829
844
  toast.success(t("editor.media.imageAdded"));
830
845
  }
831
846
 
847
+ function handleAssetsPickerOpenChange(open: boolean) {
848
+ setAssetsPickerOpen(open);
849
+ if (!open && !src) {
850
+ updateAttributes({ uploadId: null });
851
+ restoreEmptyPlaceholderSelection();
852
+ }
853
+ }
854
+
832
855
  function renderAssetsPickerDialog() {
833
856
  return (
834
857
  <AssetsPickerDialog
835
858
  open={assetsPickerOpen}
836
- onOpenChange={setAssetsPickerOpen}
859
+ onOpenChange={handleAssetsPickerOpenChange}
837
860
  url={assetsPickerUrl()}
838
861
  title={t("editor.media.assets")}
839
862
  embeddedTitle={t("editor.media.assetsImagePicker")}
@@ -856,6 +879,7 @@ export function ImageBlock({
856
879
  type="button"
857
880
  role="tab"
858
881
  aria-selected={sourceTab === "upload"}
882
+ disabled={isUploading}
859
883
  className="media-source-panel__tab"
860
884
  onClick={() => setSourceTab("upload")}
861
885
  >
@@ -865,6 +889,7 @@ export function ImageBlock({
865
889
  type="button"
866
890
  role="tab"
867
891
  aria-selected={sourceTab === "assets"}
892
+ disabled={isUploading}
868
893
  className="media-source-panel__tab"
869
894
  onClick={() => setSourceTab("assets")}
870
895
  >
@@ -874,6 +899,7 @@ export function ImageBlock({
874
899
  type="button"
875
900
  role="tab"
876
901
  aria-selected={sourceTab === "link"}
902
+ disabled={isUploading}
877
903
  className="media-source-panel__tab"
878
904
  onClick={() => setSourceTab("link")}
879
905
  >
@@ -887,14 +913,20 @@ export function ImageBlock({
887
913
  type="button"
888
914
  variant="outline"
889
915
  className="w-full"
890
- onClick={() => fileInputRef.current?.click()}
916
+ disabled={isUploading}
917
+ onClick={handleImageFileSelectionStart}
891
918
  >
892
919
  {t("editor.media.uploadFile")}
893
920
  </Button>
894
921
  </div>
895
922
  ) : sourceTab === "assets" ? (
896
923
  <div className="media-source-panel__body">
897
- <Button type="button" className="w-full" onClick={openAssetsPicker}>
924
+ <Button
925
+ type="button"
926
+ className="w-full"
927
+ disabled={isUploading}
928
+ onClick={openAssetsPicker}
929
+ >
898
930
  {t("editor.media.chooseFromAssets")}
899
931
  </Button>
900
932
  </div>
@@ -907,7 +939,7 @@ export function ImageBlock({
907
939
  onChange={(event) => setImageUrl(event.target.value)}
908
940
  placeholder={t("editor.media.pasteImageLink")}
909
941
  />
910
- <Button type="submit" className="w-full">
942
+ <Button type="submit" className="w-full" disabled={isUploading}>
911
943
  {replace
912
944
  ? t("editor.media.replaceImage")
913
945
  : t("editor.media.embedImage")}
@@ -955,16 +987,6 @@ export function ImageBlock({
955
987
  </span>
956
988
  </button>
957
989
 
958
- <input
959
- ref={fileInputRef}
960
- type="file"
961
- accept="image/*"
962
- className="hidden"
963
- tabIndex={-1}
964
- aria-hidden="true"
965
- onChange={handleImageFilePicked}
966
- />
967
-
968
990
  {showSourcePanel ? renderSourcePanel() : null}
969
991
  {renderAssetsPickerDialog()}
970
992
  </div>
@@ -973,7 +995,11 @@ export function ImageBlock({
973
995
  }
974
996
 
975
997
  return (
976
- <NodeViewWrapper className="media-block-wrapper" data-drag-handle>
998
+ <NodeViewWrapper
999
+ className="media-block-wrapper"
1000
+ data-drag-handle
1001
+ data-image-upload-id={node.attrs.uploadId || undefined}
1002
+ >
977
1003
  <div
978
1004
  ref={mediaBlockRef}
979
1005
  className={`media-block ${selected ? "media-block--selected" : ""}`}
@@ -1017,16 +1043,6 @@ export function ImageBlock({
1017
1043
  />
1018
1044
  )}
1019
1045
 
1020
- <input
1021
- ref={fileInputRef}
1022
- type="file"
1023
- accept="image/*"
1024
- className="hidden"
1025
- tabIndex={-1}
1026
- aria-hidden="true"
1027
- onChange={handleImageFilePicked}
1028
- />
1029
-
1030
1046
  {isEditable && (alt.trim() || altPopoverOpen) ? (
1031
1047
  <Popover open={altPopoverOpen} onOpenChange={setAltPopoverOpen}>
1032
1048
  <Tooltip delayDuration={350}>
@@ -7,6 +7,11 @@ import { ImageBlock } from "./ImageBlock";
7
7
  export interface ContentImageOptions extends ImageOptions {
8
8
  documentId?: string;
9
9
  onImageComment?: (quotedText: string, offsetTop: number) => void;
10
+ onImageFilePickerRequest?: (request: {
11
+ pickerId: string;
12
+ position: number;
13
+ attrs: Record<string, unknown>;
14
+ }) => void;
10
15
  }
11
16
 
12
17
  function normalizedImageWidth(value: unknown): number | null {
@@ -65,6 +70,7 @@ export const ImageNode = Image.extend<ContentImageOptions>({
65
70
  ...this.parent!(),
66
71
  documentId: undefined,
67
72
  onImageComment: undefined,
73
+ onImageFilePickerRequest: undefined,
68
74
  };
69
75
  },
70
76