@agent-native/core 0.92.7 → 0.92.9
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/core/CHANGELOG.md +18 -0
- package/corpus/core/docs/content/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/pure-agent-apps.mdx +22 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builtin.ts +1 -1
- package/corpus/core/src/agent/model-config.ts +30 -30
- package/corpus/core/src/agent/production-agent.ts +129 -7
- package/corpus/core/src/cli/design-connect.ts +438 -83
- package/corpus/core/src/cli/recap.ts +17 -3
- package/corpus/core/src/client/AgentPanel.tsx +8 -1
- package/corpus/core/src/client/agent-chat-adapter.ts +12 -7
- package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
- package/corpus/core/src/client/index.ts +4 -0
- package/corpus/core/src/client/org/TeamPage.tsx +41 -26
- package/corpus/core/src/client/use-action.ts +113 -1
- package/corpus/core/src/db/client.ts +12 -2
- package/corpus/core/src/db/create-get-db.ts +4 -1
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
- package/corpus/core/src/server/ssr-handler.ts +7 -0
- package/corpus/core/src/server/transcribe-voice.ts +1 -1
- package/corpus/core/src/usage/store.ts +13 -4
- package/corpus/core/src/vite/client.ts +38 -1
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/get-data-program.ts +78 -0
- package/corpus/templates/analytics/actions/list-data-programs.ts +49 -0
- package/corpus/templates/analytics/app/global.css +11 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +163 -17
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +20 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +96 -3
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +61 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +40 -2
- package/corpus/templates/analytics/changelog/2026-07-09-analytics-no-longer-forgets-successful-data-queries-when-a-l.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-keep-consistent-spacing-when-they-stack-ver.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-tables-and-extensions-can-be-selected-and-d.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-long-running-analytics-requests-now-recover-automatically-wh.md +6 -0
- package/corpus/templates/analytics/server/db/index.ts +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +1 -7
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +102 -15
- package/corpus/templates/content/app/hooks/use-content-database.ts +52 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +50 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/content/app/i18n-data.ts +28 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-warnings-no-longer-flash-during-normal-synce.md +6 -0
- package/corpus/templates/content/changelog/2026-07-09-property-menus-and-delete-confirmations-now-open-visibly-and.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +130 -28
- package/corpus/templates/design/actions/add-breakpoint.ts +48 -68
- package/corpus/templates/design/actions/add-localhost-screens.ts +496 -61
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +2 -18
- package/corpus/templates/design/actions/apply-design-token-edit.ts +51 -82
- package/corpus/templates/design/actions/apply-tweaks.ts +63 -41
- package/corpus/templates/design/actions/capture-design-state.ts +2 -2
- package/corpus/templates/design/actions/connect-localhost.ts +58 -12
- package/corpus/templates/design/actions/create-component.ts +2 -18
- package/corpus/templates/design/actions/create-design-branch.ts +38 -18
- package/corpus/templates/design/actions/create-fusion-app.ts +15 -11
- package/corpus/templates/design/actions/delete-file.ts +19 -34
- package/corpus/templates/design/actions/deploy-design-preview.ts +59 -27
- package/corpus/templates/design/actions/deploy-fusion-app.ts +22 -15
- package/corpus/templates/design/actions/export-pdf.ts +2 -1
- package/corpus/templates/design/actions/export-zip.ts +9 -3
- package/corpus/templates/design/actions/generate-design.ts +107 -70
- package/corpus/templates/design/actions/get-component-details.ts +2 -18
- package/corpus/templates/design/actions/get-design-branch-diff.ts +2 -3
- package/corpus/templates/design/actions/get-design-surface-index.ts +2 -18
- package/corpus/templates/design/actions/get-design.ts +2 -1
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +7 -1
- package/corpus/templates/design/actions/import-design-tokens.ts +114 -76
- package/corpus/templates/design/actions/index-components.ts +2 -18
- package/corpus/templates/design/actions/list-design-source-capabilities.ts +23 -28
- package/corpus/templates/design/actions/list-local-files.ts +9 -2
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +82 -98
- package/corpus/templates/design/actions/open-component-source.ts +2 -18
- package/corpus/templates/design/actions/open-visual-edit.ts +19 -1
- package/corpus/templates/design/actions/present-design-variants.ts +70 -70
- package/corpus/templates/design/actions/preview-component-prop-edit.ts +4 -14
- package/corpus/templates/design/actions/read-local-file.ts +9 -2
- package/corpus/templates/design/actions/remove-breakpoint.ts +40 -61
- package/corpus/templates/design/actions/rename-screen.ts +425 -0
- package/corpus/templates/design/actions/request-localhost-write-consent.ts +12 -2
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +9 -2
- package/corpus/templates/design/actions/sync-fusion-app.ts +56 -39
- package/corpus/templates/design/actions/update-design.ts +376 -61
- package/corpus/templates/design/actions/update-file.ts +455 -188
- package/corpus/templates/design/actions/write-local-file.ts +10 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +685 -608
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +43 -15
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +576 -2015
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +62 -14
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +263 -25
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +34 -0
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +40 -0
- package/corpus/templates/design/app/components/design/design-canvas/creation.ts +47 -0
- package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +27 -0
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +62 -0
- package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +137 -0
- package/corpus/templates/design/app/components/design/design-canvas/file-drop.ts +10 -0
- package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +23 -0
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +23 -0
- package/corpus/templates/design/app/components/design/design-canvas/iframe-pan.ts +177 -0
- package/corpus/templates/design/app/components/design/design-canvas/motion-types.ts +7 -0
- package/corpus/templates/design/app/components/design/design-canvas/pending-text-edit.ts +62 -0
- package/corpus/templates/design/app/components/design/index.ts +2 -2
- package/corpus/templates/design/app/components/design/multi-screen/canvas-tools.ts +100 -0
- package/corpus/templates/design/app/components/design/multi-screen/coordinate-transforms.ts +81 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +23 -13
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +238 -19
- package/corpus/templates/design/app/components/design/multi-screen/draft-primitives.ts +424 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +341 -0
- package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +52 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +62 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +283 -0
- package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +272 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +5 -1
- package/corpus/templates/design/app/components/design/multi-screen/wheel-gesture-state.ts +12 -0
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +325 -84
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +15 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +119 -47
- package/corpus/templates/design/app/i18n/zh-TW.ts +9 -0
- package/corpus/templates/design/app/i18n-data.ts +223 -0
- package/corpus/templates/design/app/lib/design-save-outbox.ts +379 -0
- package/corpus/templates/design/app/lib/png-clipboard.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +229 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +918 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +43 -0
- package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +336 -0
- package/corpus/templates/design/app/pages/design-editor/data-operations.ts +270 -0
- package/corpus/templates/design/app/pages/design-editor/dom-guards.ts +24 -0
- package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +11 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +20 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +408 -0
- package/corpus/templates/design/app/pages/design-editor/export-capture.ts +115 -0
- package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +93 -0
- package/corpus/templates/design/app/pages/design-editor/history.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +185 -0
- package/corpus/templates/design/app/pages/design-editor/motion-state.ts +309 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +438 -0
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +510 -0
- package/corpus/templates/design/app/pages/design-editor/portable-style.ts +115 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +337 -0
- package/corpus/templates/design/app/pages/design-editor/style-utils.ts +5 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +92 -0
- package/corpus/templates/design/app/pages/design-editor/tweak-save.ts +87 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +36 -0
- package/corpus/templates/design/app/routes/design.$id.tsx +11 -1
- package/corpus/templates/design/changelog/2026-07-09-design-edits-canvas-positions-tools-and-tab-context-now-pers.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-figma-style-shortcuts-drawing-annotations-and-cross-screen-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hand-and-scale-tools-now-keep-their-active-toolbar-identity-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-large-multi-screen-designs-now-stay-responsive-during-long-c.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-drags-now-land-exactly-where-the-insertion-indicator-s.md +6 -0
- package/corpus/templates/design/server/db/index.ts +2 -52
- package/corpus/templates/design/server/db/schema.ts +16 -0
- package/corpus/templates/design/server/lib/design-data-access.ts +70 -0
- package/corpus/templates/design/server/lib/design-data-mutation.ts +249 -0
- package/corpus/templates/design/server/lib/fusion-screens.ts +89 -76
- package/corpus/templates/design/server/lib/import-design-files.ts +76 -35
- package/corpus/templates/design/server/lib/verify-write-grant.ts +7 -2
- package/corpus/templates/design/server/plugins/db.ts +19 -0
- package/corpus/templates/design/server/source-workspace.ts +12 -13
- package/corpus/templates/design/shared/resolve-tweaks.ts +15 -0
- package/corpus/templates/design/shared/screen-rename.ts +42 -0
- package/corpus/templates/design/shared/source-mode.ts +84 -4
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builtin.js +1 -1
- package/dist/agent/engine/builtin.js.map +1 -1
- package/dist/agent/model-config.d.ts +9 -9
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +30 -30
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts +60 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +106 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/design-connect.d.ts +30 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +359 -75
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +13 -3
- package/dist/cli/recap.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +10 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/TiptapComposer.js +1 -1
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +6 -5
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/use-action.d.ts +32 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +68 -1
- package/dist/client/use-action.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +7 -2
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +2 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +7 -0
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/server/transcribe-voice.js +1 -1
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +13 -4
- package/dist/usage/store.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +36 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
- package/docs/content/pr-visual-recap.mdx +3 -3
- package/docs/content/pure-agent-apps.mdx +22 -0
- package/package.json +2 -2
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
CreateDatabaseRequest,
|
|
19
19
|
DatabaseItemsBatchRequest,
|
|
20
20
|
DisconnectContentDatabaseSourceRequest,
|
|
21
|
+
DocumentPropertiesResponse,
|
|
21
22
|
ExecuteBuilderSourceBatchRequest,
|
|
22
23
|
ExecuteBuilderSourceBatchResponse,
|
|
23
24
|
DuplicateDatabaseItemRequest,
|
|
@@ -131,6 +132,57 @@ export function applyDocumentPropertyValueToDatabaseResponse(
|
|
|
131
132
|
return changed ? { ...current, items } : current;
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
export function applyDocumentPropertiesToDatabaseResponse(
|
|
136
|
+
current: ContentDatabaseResponse | undefined,
|
|
137
|
+
response: Pick<DocumentPropertiesResponse, "databaseId" | "properties">,
|
|
138
|
+
): ContentDatabaseResponse | undefined {
|
|
139
|
+
if (!current) return current;
|
|
140
|
+
if (response.databaseId && current.database.id !== response.databaseId) {
|
|
141
|
+
return current;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const sortedProperties = [...response.properties].sort(
|
|
145
|
+
(a, b) => a.definition.position - b.definition.position,
|
|
146
|
+
);
|
|
147
|
+
const propertyById = new Map(
|
|
148
|
+
sortedProperties.map((property) => [property.definition.id, property]),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
...current,
|
|
153
|
+
properties: sortedProperties,
|
|
154
|
+
items: current.items.map((item) => ({
|
|
155
|
+
...item,
|
|
156
|
+
properties: item.properties
|
|
157
|
+
.filter((property) => propertyById.has(property.definition.id))
|
|
158
|
+
.map((property) => ({
|
|
159
|
+
...propertyById.get(property.definition.id)!,
|
|
160
|
+
value: property.value,
|
|
161
|
+
})),
|
|
162
|
+
})),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function removeDocumentPropertyFromDatabaseResponse(
|
|
167
|
+
current: ContentDatabaseResponse | undefined,
|
|
168
|
+
propertyId: string,
|
|
169
|
+
): ContentDatabaseResponse | undefined {
|
|
170
|
+
if (!current) return current;
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
...current,
|
|
174
|
+
properties: current.properties.filter(
|
|
175
|
+
(property) => property.definition.id !== propertyId,
|
|
176
|
+
),
|
|
177
|
+
items: current.items.map((item) => ({
|
|
178
|
+
...item,
|
|
179
|
+
properties: item.properties.filter(
|
|
180
|
+
(property) => property.definition.id !== propertyId,
|
|
181
|
+
),
|
|
182
|
+
})),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
134
186
|
// `get-content-database` returns a union at runtime: the full response, or an
|
|
135
187
|
// unavailable payload (`{ available: false, reason: "deleted" | "not_found" }`)
|
|
136
188
|
// with no `database` field. Consumers typed against ContentDatabaseResponse
|
|
@@ -12,9 +12,11 @@ import type {
|
|
|
12
12
|
import { useQueryClient } from "@tanstack/react-query";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
+
applyDocumentPropertiesToDatabaseResponse,
|
|
15
16
|
applyDocumentPropertyValueToDatabaseResponse,
|
|
16
17
|
contentDatabaseQueryFilter,
|
|
17
18
|
contentDatabaseQueryKey,
|
|
19
|
+
removeDocumentPropertyFromDatabaseResponse,
|
|
18
20
|
} from "./use-content-database";
|
|
19
21
|
|
|
20
22
|
export function useDocumentProperties(documentId: string | null) {
|
|
@@ -37,7 +39,12 @@ export function useConfigureDocumentProperty(
|
|
|
37
39
|
DocumentPropertiesResponse,
|
|
38
40
|
ConfigureDocumentPropertyRequest
|
|
39
41
|
>("configure-document-property", {
|
|
40
|
-
|
|
42
|
+
skipActionQueryInvalidation: true,
|
|
43
|
+
onSuccess: (data) => {
|
|
44
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
45
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
46
|
+
(current) => applyDocumentPropertiesToDatabaseResponse(current, data),
|
|
47
|
+
);
|
|
41
48
|
queryClient.invalidateQueries({
|
|
42
49
|
queryKey: ["action", "list-document-properties", { documentId }],
|
|
43
50
|
});
|
|
@@ -45,7 +52,7 @@ export function useConfigureDocumentProperty(
|
|
|
45
52
|
queryKey: ["action", "get-document", { id: documentId }],
|
|
46
53
|
});
|
|
47
54
|
queryClient.invalidateQueries({
|
|
48
|
-
|
|
55
|
+
...contentDatabaseQueryFilter(databaseDocumentId),
|
|
49
56
|
});
|
|
50
57
|
},
|
|
51
58
|
});
|
|
@@ -135,7 +142,12 @@ export function useDuplicateDocumentProperty(
|
|
|
135
142
|
DocumentPropertiesResponse,
|
|
136
143
|
DuplicateDocumentPropertyRequest
|
|
137
144
|
>("duplicate-document-property", {
|
|
138
|
-
|
|
145
|
+
skipActionQueryInvalidation: true,
|
|
146
|
+
onSuccess: (data) => {
|
|
147
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
148
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
149
|
+
(current) => applyDocumentPropertiesToDatabaseResponse(current, data),
|
|
150
|
+
);
|
|
139
151
|
queryClient.invalidateQueries({
|
|
140
152
|
queryKey: ["action", "list-document-properties", { documentId }],
|
|
141
153
|
});
|
|
@@ -143,7 +155,7 @@ export function useDuplicateDocumentProperty(
|
|
|
143
155
|
queryKey: ["action", "get-document", { id: documentId }],
|
|
144
156
|
});
|
|
145
157
|
queryClient.invalidateQueries({
|
|
146
|
-
|
|
158
|
+
...contentDatabaseQueryFilter(databaseDocumentId),
|
|
147
159
|
});
|
|
148
160
|
},
|
|
149
161
|
});
|
|
@@ -181,7 +193,39 @@ export function useDeleteDocumentProperty(
|
|
|
181
193
|
DocumentPropertiesResponse,
|
|
182
194
|
DeleteDocumentPropertyRequest
|
|
183
195
|
>("delete-document-property", {
|
|
184
|
-
|
|
196
|
+
skipActionQueryInvalidation: true,
|
|
197
|
+
onMutate: async (variables) => {
|
|
198
|
+
await queryClient.cancelQueries(
|
|
199
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
200
|
+
);
|
|
201
|
+
const previous = queryClient.getQueriesData<ContentDatabaseResponse>(
|
|
202
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
203
|
+
);
|
|
204
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
205
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
206
|
+
(current) =>
|
|
207
|
+
removeDocumentPropertyFromDatabaseResponse(
|
|
208
|
+
current,
|
|
209
|
+
variables.propertyId,
|
|
210
|
+
),
|
|
211
|
+
);
|
|
212
|
+
return { previous };
|
|
213
|
+
},
|
|
214
|
+
onError: (_error, _variables, context) => {
|
|
215
|
+
const rollback = context as
|
|
216
|
+
| {
|
|
217
|
+
previous?: Array<[readonly unknown[], unknown]>;
|
|
218
|
+
}
|
|
219
|
+
| undefined;
|
|
220
|
+
for (const [queryKey, data] of rollback?.previous ?? []) {
|
|
221
|
+
queryClient.setQueryData(queryKey, data);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
onSuccess: (data) => {
|
|
225
|
+
queryClient.setQueriesData<ContentDatabaseResponse>(
|
|
226
|
+
contentDatabaseQueryFilter(databaseDocumentId),
|
|
227
|
+
(current) => applyDocumentPropertiesToDatabaseResponse(current, data),
|
|
228
|
+
);
|
|
185
229
|
queryClient.invalidateQueries({
|
|
186
230
|
queryKey: ["action", "list-document-properties", { documentId }],
|
|
187
231
|
});
|
|
@@ -189,7 +233,7 @@ export function useDeleteDocumentProperty(
|
|
|
189
233
|
queryKey: ["action", "get-document", { id: documentId }],
|
|
190
234
|
});
|
|
191
235
|
queryClient.invalidateQueries({
|
|
192
|
-
|
|
236
|
+
...contentDatabaseQueryFilter(databaseDocumentId),
|
|
193
237
|
});
|
|
194
238
|
},
|
|
195
239
|
});
|
|
@@ -307,6 +307,8 @@ const messages = {
|
|
|
307
307
|
deleteProperty: "刪除屬性",
|
|
308
308
|
deletePropertyDescription:
|
|
309
309
|
'這將從該工作區中的每個檔案中刪除"{{name}}"及其值。',
|
|
310
|
+
deletePropertyDescriptionPrefix: '這將從該工作區中的每個檔案中刪除"',
|
|
311
|
+
deletePropertyDescriptionSuffix: '"及其值。',
|
|
310
312
|
deletePropertyQuestion: "刪除屬性?",
|
|
311
313
|
duplicateProperty: "重複的屬性",
|
|
312
314
|
editEndDate: "編輯 {{name}} 結束日期",
|
|
@@ -1958,6 +1958,9 @@ const editorPropertiesMessages = {
|
|
|
1958
1958
|
deleteProperty: "Delete property",
|
|
1959
1959
|
deletePropertyDescription:
|
|
1960
1960
|
'This removes "{{name}}" and its values from every document in this workspace.',
|
|
1961
|
+
deletePropertyDescriptionPrefix: 'This removes "',
|
|
1962
|
+
deletePropertyDescriptionSuffix:
|
|
1963
|
+
'" and its values from every document in this workspace.',
|
|
1961
1964
|
deletePropertyQuestion: "Delete property?",
|
|
1962
1965
|
duplicateProperty: "Duplicate property",
|
|
1963
1966
|
editEndDate: "Edit {{name}} end date",
|
|
@@ -4978,6 +4981,8 @@ const editorMessagesByLocale = {
|
|
|
4978
4981
|
deleteProperty: "删除属性",
|
|
4979
4982
|
deletePropertyDescription:
|
|
4980
4983
|
'这将从该工作区中的每个文档中删除"{{name}}"及其值。',
|
|
4984
|
+
deletePropertyDescriptionPrefix: '这将从该工作区中的每个文档中删除"',
|
|
4985
|
+
deletePropertyDescriptionSuffix: '"及其值。',
|
|
4981
4986
|
deletePropertyQuestion: "删除属性?",
|
|
4982
4987
|
duplicateProperty: "重复的属性",
|
|
4983
4988
|
editEndDate: "编辑 {{name}} 结束日期",
|
|
@@ -5304,6 +5309,9 @@ const editorMessagesByLocale = {
|
|
|
5304
5309
|
deleteProperty: "Eliminar propiedad",
|
|
5305
5310
|
deletePropertyDescription:
|
|
5306
5311
|
'Esto elimina "{{name}}" y sus valores de todos los documentos de este espacio de trabajo.',
|
|
5312
|
+
deletePropertyDescriptionPrefix: 'Esto elimina "',
|
|
5313
|
+
deletePropertyDescriptionSuffix:
|
|
5314
|
+
'" y sus valores de todos los documentos de este espacio de trabajo.',
|
|
5307
5315
|
deletePropertyQuestion: "¿Eliminar propiedad?",
|
|
5308
5316
|
duplicateProperty: "Propiedad duplicada",
|
|
5309
5317
|
editEndDate: "Editar fecha de finalización de {{name}}",
|
|
@@ -5641,6 +5649,9 @@ const editorMessagesByLocale = {
|
|
|
5641
5649
|
deleteProperty: "Supprimer la propriété",
|
|
5642
5650
|
deletePropertyDescription:
|
|
5643
5651
|
"Cela supprime « {{name}} » et ses valeurs de chaque document de cet espace de travail.",
|
|
5652
|
+
deletePropertyDescriptionPrefix: "Cela supprime « ",
|
|
5653
|
+
deletePropertyDescriptionSuffix:
|
|
5654
|
+
" » et ses valeurs de chaque document de cet espace de travail.",
|
|
5644
5655
|
deletePropertyQuestion: "Supprimer la propriété ?",
|
|
5645
5656
|
duplicateProperty: "Propriété en double",
|
|
5646
5657
|
editEndDate: "Modifier la date de fin de {{name}}",
|
|
@@ -5978,6 +5989,9 @@ const editorMessagesByLocale = {
|
|
|
5978
5989
|
deleteProperty: "Eigenschaft löschen",
|
|
5979
5990
|
deletePropertyDescription:
|
|
5980
5991
|
'Dadurch werden „{{name}}" und seine Werte aus jedem Dokument in diesem Arbeitsbereich entfernt.',
|
|
5992
|
+
deletePropertyDescriptionPrefix: "Dadurch werden „",
|
|
5993
|
+
deletePropertyDescriptionSuffix:
|
|
5994
|
+
'" und seine Werte aus jedem Dokument in diesem Arbeitsbereich entfernt.',
|
|
5981
5995
|
deletePropertyQuestion: "Eigenschaft löschen?",
|
|
5982
5996
|
duplicateProperty: "Doppelte Eigenschaft",
|
|
5983
5997
|
editEndDate: "{{name}}-Enddatum bearbeiten",
|
|
@@ -6315,6 +6329,9 @@ const editorMessagesByLocale = {
|
|
|
6315
6329
|
deleteProperty: "プロパティの削除",
|
|
6316
6330
|
deletePropertyDescription:
|
|
6317
6331
|
"これにより、このワークスペース内のすべてのドキュメントから「{{name}}」とその値が削除されます。",
|
|
6332
|
+
deletePropertyDescriptionPrefix:
|
|
6333
|
+
"これにより、このワークスペース内のすべてのドキュメントから「",
|
|
6334
|
+
deletePropertyDescriptionSuffix: "」とその値が削除されます。",
|
|
6318
6335
|
deletePropertyQuestion: "プロパティを削除しますか?",
|
|
6319
6336
|
duplicateProperty: "重複したプロパティ",
|
|
6320
6337
|
editEndDate: "{{name}} の終了日を編集",
|
|
@@ -6645,6 +6662,9 @@ const editorMessagesByLocale = {
|
|
|
6645
6662
|
deleteProperty: "속성 삭제",
|
|
6646
6663
|
deletePropertyDescription:
|
|
6647
6664
|
'이렇게 하면 이 작업공간의 모든 문서에서 "{{name}}"와 해당 값이 제거됩니다.',
|
|
6665
|
+
deletePropertyDescriptionPrefix:
|
|
6666
|
+
'이렇게 하면 이 작업공간의 모든 문서에서 "',
|
|
6667
|
+
deletePropertyDescriptionSuffix: '"와 해당 값이 제거됩니다.',
|
|
6648
6668
|
deletePropertyQuestion: "속성을 삭제하시겠습니까?",
|
|
6649
6669
|
duplicateProperty: "중복된 속성",
|
|
6650
6670
|
editEndDate: "{{name}} 종료일 수정",
|
|
@@ -6978,6 +6998,9 @@ const editorMessagesByLocale = {
|
|
|
6978
6998
|
deleteProperty: "Excluir propriedade",
|
|
6979
6999
|
deletePropertyDescription:
|
|
6980
7000
|
'Isso remove "{{name}}" e seus valores de todos os documentos nesta área de trabalho.',
|
|
7001
|
+
deletePropertyDescriptionPrefix: 'Isso remove "',
|
|
7002
|
+
deletePropertyDescriptionSuffix:
|
|
7003
|
+
'" e seus valores de todos os documentos nesta área de trabalho.',
|
|
6981
7004
|
deletePropertyQuestion: "Excluir propriedade?",
|
|
6982
7005
|
duplicateProperty: "Propriedade duplicada",
|
|
6983
7006
|
editEndDate: "Editar data de término do {{name}}",
|
|
@@ -7311,6 +7334,8 @@ const editorMessagesByLocale = {
|
|
|
7311
7334
|
deleteProperty: "संपत्ति हटाएं",
|
|
7312
7335
|
deletePropertyDescription:
|
|
7313
7336
|
'यह इस कार्यक्षेत्र के प्रत्येक दस्तावेज़ से "{{name}}" और उसके मानों को हटा देता है।',
|
|
7337
|
+
deletePropertyDescriptionPrefix: 'यह इस कार्यक्षेत्र के प्रत्येक दस्तावेज़ से "',
|
|
7338
|
+
deletePropertyDescriptionSuffix: '" और उसके मानों को हटा देता है।',
|
|
7314
7339
|
deletePropertyQuestion: "संपत्ति हटाएं?",
|
|
7315
7340
|
duplicateProperty: "डुप्लिकेट संपत्ति",
|
|
7316
7341
|
editEndDate: "{{name}} समाप्ति तिथि संपादित करें",
|
|
@@ -7638,6 +7663,9 @@ const editorMessagesByLocale = {
|
|
|
7638
7663
|
deleteProperty: "حذف الممتلكات",
|
|
7639
7664
|
deletePropertyDescription:
|
|
7640
7665
|
'يؤدي هذا إلى إزالة "{{name}}" وقيمه من كل مستند في مساحة العمل هذه.',
|
|
7666
|
+
deletePropertyDescriptionPrefix: 'يؤدي هذا إلى إزالة "',
|
|
7667
|
+
deletePropertyDescriptionSuffix:
|
|
7668
|
+
'" وقيمه من كل مستند في مساحة العمل هذه.',
|
|
7641
7669
|
deletePropertyQuestion: "هل تريد حذف الخاصية؟",
|
|
7642
7670
|
duplicateProperty: "خاصية مكررة",
|
|
7643
7671
|
editEndDate: "تحرير تاريخ انتهاء {{name}}",
|
|
@@ -1355,36 +1355,138 @@ export async function refreshDocumentSyncStatus(
|
|
|
1355
1355
|
return status;
|
|
1356
1356
|
}
|
|
1357
1357
|
// Both sides changed since last sync — mark as conflict so the user can
|
|
1358
|
-
// pick which side wins.
|
|
1359
|
-
//
|
|
1360
|
-
//
|
|
1358
|
+
// pick which side wins. Take the same per-document claim used by pull/push
|
|
1359
|
+
// before persisting that state: a save-triggered push can be between its
|
|
1360
|
+
// remote write and baseline update here, making both sides look changed
|
|
1361
|
+
// for a few hundred milliseconds. If that push owns the claim, let it
|
|
1362
|
+
// finish instead of flashing a conflict that it immediately clears.
|
|
1361
1363
|
if (status.localChanged && status.remoteChanged) {
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
state: "conflict",
|
|
1369
|
-
lastSyncedAt: link.lastSyncedAt,
|
|
1370
|
-
lastPulledRemoteUpdatedAt: link.lastPulledRemoteUpdatedAt,
|
|
1371
|
-
lastPushedLocalUpdatedAt: link.lastPushedLocalUpdatedAt,
|
|
1372
|
-
lastKnownRemoteUpdatedAt: status.lastKnownRemoteUpdatedAt,
|
|
1373
|
-
lastSyncedContentHash: link.lastSyncedContentHash,
|
|
1374
|
-
lastError: null,
|
|
1375
|
-
warnings: parseWarnings(link),
|
|
1376
|
-
hasConflict: true,
|
|
1377
|
-
});
|
|
1364
|
+
if (!(await tryClaimSyncLink(documentId, owner))) return status;
|
|
1365
|
+
try {
|
|
1366
|
+
// The competing push may have finished after the status snapshot but
|
|
1367
|
+
// before this poll acquired the claim. Re-read the local/link state
|
|
1368
|
+
// under the claim so stale change flags cannot recreate the conflict
|
|
1369
|
+
// immediately after that push resolved it.
|
|
1378
1370
|
const document = await getDocument(documentId, owner);
|
|
1379
|
-
const
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1371
|
+
const link = await getSyncLink(documentId, owner);
|
|
1372
|
+
if (link) {
|
|
1373
|
+
const claimedStatus = buildStatus({
|
|
1374
|
+
connected: true,
|
|
1375
|
+
documentId,
|
|
1376
|
+
link,
|
|
1377
|
+
remoteUpdatedAt: status.lastKnownRemoteUpdatedAt,
|
|
1378
|
+
documentUpdatedAt: document.updatedAt,
|
|
1379
|
+
documentContent: document.content,
|
|
1380
|
+
});
|
|
1381
|
+
if (!claimedStatus.localChanged || !claimedStatus.remoteChanged) {
|
|
1382
|
+
return claimedStatus;
|
|
1383
|
+
}
|
|
1384
|
+
let conflictDocument = document;
|
|
1385
|
+
|
|
1386
|
+
// Notion timestamps are only a cheap candidate signal. Confirm the
|
|
1387
|
+
// remote content against the authoritative hash baseline before
|
|
1388
|
+
// persisting a conflict; our own completed push (or any metadata-only
|
|
1389
|
+
// timestamp bump) can otherwise look like a remote content edit.
|
|
1390
|
+
if (link.lastSyncedContentHash) {
|
|
1391
|
+
const connection = await getNotionConnectionForOwner(owner);
|
|
1392
|
+
if (!connection) return claimedStatus;
|
|
1393
|
+
|
|
1394
|
+
let remotePageContent: Awaited<
|
|
1395
|
+
ReturnType<typeof readNotionPageAsDocument>
|
|
1396
|
+
>;
|
|
1397
|
+
try {
|
|
1398
|
+
remotePageContent = await readNotionPageAsDocument(
|
|
1399
|
+
connection.accessToken,
|
|
1400
|
+
link.remotePageId,
|
|
1401
|
+
);
|
|
1402
|
+
} catch {
|
|
1403
|
+
// Fail closed: an unverified timestamp bump is not enough to
|
|
1404
|
+
// interrupt editing with a conflict warning.
|
|
1405
|
+
return claimedStatus;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// Local saves do not take the Notion sync claim, so the editor can
|
|
1409
|
+
// keep writing while the remote content request is in flight.
|
|
1410
|
+
// Classify the conflict against the latest local row.
|
|
1411
|
+
const verifiedDocument = await getDocument(documentId, owner);
|
|
1412
|
+
conflictDocument = verifiedDocument;
|
|
1413
|
+
const baselineHash = link.lastSyncedContentHash;
|
|
1414
|
+
const localHash = hashContent(verifiedDocument.content);
|
|
1415
|
+
const remoteHash = hashContent(remotePageContent.content);
|
|
1416
|
+
const localHashChanged = localHash !== baselineHash;
|
|
1417
|
+
const remoteHashChanged = remoteHash !== baselineHash;
|
|
1418
|
+
|
|
1419
|
+
if (localHash === remoteHash) {
|
|
1420
|
+
await upsertSyncLink({
|
|
1421
|
+
owner,
|
|
1422
|
+
documentId,
|
|
1423
|
+
remotePageId: link.remotePageId,
|
|
1424
|
+
state: "linked",
|
|
1425
|
+
lastSyncedAt: nowIso(),
|
|
1426
|
+
lastPulledRemoteUpdatedAt: remotePageContent.lastEditedTime,
|
|
1427
|
+
lastPushedLocalUpdatedAt: verifiedDocument.updatedAt,
|
|
1428
|
+
lastKnownRemoteUpdatedAt: remotePageContent.lastEditedTime,
|
|
1429
|
+
lastSyncedContentHash: localHash,
|
|
1430
|
+
lastError: null,
|
|
1431
|
+
warnings: remotePageContent.warnings,
|
|
1432
|
+
hasConflict: false,
|
|
1433
|
+
});
|
|
1434
|
+
const convergedLink = await getSyncLink(documentId, owner);
|
|
1435
|
+
return buildStatus({
|
|
1436
|
+
connected: true,
|
|
1437
|
+
documentId,
|
|
1438
|
+
link: convergedLink,
|
|
1439
|
+
remoteUpdatedAt: remotePageContent.lastEditedTime,
|
|
1440
|
+
documentUpdatedAt: verifiedDocument.updatedAt,
|
|
1441
|
+
documentContent: verifiedDocument.content,
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
if (!localHashChanged || !remoteHashChanged) {
|
|
1446
|
+
if (options?.autoSync && localHashChanged) {
|
|
1447
|
+
return pushDocumentToNotion(owner, documentId, false, {
|
|
1448
|
+
skipClaim: true,
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
if (options?.autoSync && remoteHashChanged) {
|
|
1452
|
+
return pullDocumentFromNotion(owner, documentId, false, {
|
|
1453
|
+
skipClaim: true,
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
return {
|
|
1457
|
+
...claimedStatus,
|
|
1458
|
+
localChanged: localHashChanged,
|
|
1459
|
+
remoteChanged: remoteHashChanged,
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
await upsertSyncLink({
|
|
1465
|
+
owner,
|
|
1466
|
+
documentId,
|
|
1467
|
+
remotePageId: link.remotePageId,
|
|
1468
|
+
state: "conflict",
|
|
1469
|
+
lastSyncedAt: link.lastSyncedAt,
|
|
1470
|
+
lastPulledRemoteUpdatedAt: link.lastPulledRemoteUpdatedAt,
|
|
1471
|
+
lastPushedLocalUpdatedAt: link.lastPushedLocalUpdatedAt,
|
|
1472
|
+
lastKnownRemoteUpdatedAt: status.lastKnownRemoteUpdatedAt,
|
|
1473
|
+
lastSyncedContentHash: link.lastSyncedContentHash,
|
|
1474
|
+
lastError: null,
|
|
1475
|
+
warnings: parseWarnings(link),
|
|
1476
|
+
hasConflict: true,
|
|
1477
|
+
});
|
|
1478
|
+
const updatedLink = await getSyncLink(documentId, owner);
|
|
1479
|
+
return buildStatus({
|
|
1480
|
+
connected: true,
|
|
1481
|
+
documentId,
|
|
1482
|
+
link: updatedLink,
|
|
1483
|
+
remoteUpdatedAt: status.lastKnownRemoteUpdatedAt,
|
|
1484
|
+
documentUpdatedAt: conflictDocument.updatedAt,
|
|
1485
|
+
documentContent: conflictDocument.content,
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
} finally {
|
|
1489
|
+
await releaseSyncLink(documentId, owner);
|
|
1388
1490
|
}
|
|
1389
1491
|
}
|
|
1390
1492
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
3
|
-
import { eq } from "drizzle-orm";
|
|
4
3
|
import { nanoid } from "nanoid";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
|
|
7
|
-
import { getDb, schema } from "../server/db/index.js";
|
|
8
6
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
7
|
+
import {
|
|
8
|
+
mutateDesignData,
|
|
9
|
+
type DesignDataRecord,
|
|
10
|
+
} from "../server/lib/design-data-mutation.js";
|
|
9
11
|
import type {
|
|
10
12
|
BreakpointDefinition,
|
|
11
13
|
BreakpointSet,
|
|
@@ -22,41 +24,17 @@ import { widthToPrefix } from "../shared/responsive-classes.js";
|
|
|
22
24
|
* `design_breakpoint_set` table keyed by (design_id, file_id) and migrate
|
|
23
25
|
* this in-data storage to it.
|
|
24
26
|
*/
|
|
25
|
-
function readBreakpointSet(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return { id: nanoid(), breakpoints: [] };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function writeBreakpointSet(
|
|
40
|
-
designData: string | null,
|
|
41
|
-
set: BreakpointSet,
|
|
42
|
-
now: string,
|
|
43
|
-
): string {
|
|
44
|
-
let prev: Record<string, unknown> = {};
|
|
45
|
-
if (designData) {
|
|
46
|
-
try {
|
|
47
|
-
const parsed = JSON.parse(designData);
|
|
48
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
49
|
-
prev = parsed;
|
|
50
|
-
}
|
|
51
|
-
} catch {
|
|
52
|
-
// ignore
|
|
53
|
-
}
|
|
27
|
+
function readBreakpointSet(
|
|
28
|
+
designData: DesignDataRecord,
|
|
29
|
+
fallbackId: string,
|
|
30
|
+
): BreakpointSet {
|
|
31
|
+
if (
|
|
32
|
+
designData.breakpointSet &&
|
|
33
|
+
typeof designData.breakpointSet === "object"
|
|
34
|
+
) {
|
|
35
|
+
return designData.breakpointSet as BreakpointSet;
|
|
54
36
|
}
|
|
55
|
-
return
|
|
56
|
-
...prev,
|
|
57
|
-
breakpointSet: set,
|
|
58
|
-
breakpointSetUpdatedAt: now,
|
|
59
|
-
});
|
|
37
|
+
return { id: fallbackId, breakpoints: [] };
|
|
60
38
|
}
|
|
61
39
|
|
|
62
40
|
export default defineAction({
|
|
@@ -95,29 +73,9 @@ export default defineAction({
|
|
|
95
73
|
run: async ({ designId, label, widthPx, id: providedId }) => {
|
|
96
74
|
await assertAccess("design", designId, "editor");
|
|
97
75
|
|
|
98
|
-
const db = getDb();
|
|
99
|
-
const [design] = await db
|
|
100
|
-
.select({ data: schema.designs.data })
|
|
101
|
-
.from(schema.designs)
|
|
102
|
-
.where(eq(schema.designs.id, designId))
|
|
103
|
-
.limit(1);
|
|
104
|
-
|
|
105
|
-
if (!design) throw new Error(`Design '${designId}' not found.`);
|
|
106
|
-
|
|
107
|
-
const set = readBreakpointSet(design.data);
|
|
108
|
-
|
|
109
|
-
// Ignore duplicate widths.
|
|
110
|
-
if (set.breakpoints.some((bp) => bp.widthPx === widthPx)) {
|
|
111
|
-
return {
|
|
112
|
-
ignored: true,
|
|
113
|
-
reason: `A breakpoint with width ${widthPx}px already exists.`,
|
|
114
|
-
breakpointSet: set,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
76
|
const breakpointId = providedId ?? nanoid();
|
|
77
|
+
const breakpointSetId = nanoid();
|
|
119
78
|
const prefix = widthToPrefix(widthPx);
|
|
120
|
-
|
|
121
79
|
const newBreakpoint: BreakpointDefinition = {
|
|
122
80
|
id: breakpointId,
|
|
123
81
|
label,
|
|
@@ -125,21 +83,43 @@ export default defineAction({
|
|
|
125
83
|
prefix,
|
|
126
84
|
};
|
|
127
85
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
(
|
|
86
|
+
const persisted = await mutateDesignData({
|
|
87
|
+
designId,
|
|
88
|
+
mutate: (current, { updatedAt }) => {
|
|
89
|
+
const set = readBreakpointSet(current, breakpointSetId);
|
|
90
|
+
if (set.breakpoints.some((bp) => bp.widthPx === widthPx)) {
|
|
91
|
+
return current;
|
|
92
|
+
}
|
|
93
|
+
// Insert sorted by widthPx ascending (Mobile → Tablet → Desktop).
|
|
94
|
+
const breakpoints = [...set.breakpoints, newBreakpoint].sort(
|
|
95
|
+
(a, b) => a.widthPx - b.widthPx,
|
|
96
|
+
);
|
|
97
|
+
return {
|
|
98
|
+
...current,
|
|
99
|
+
breakpointSet: { ...set, breakpoints },
|
|
100
|
+
breakpointSetUpdatedAt: updatedAt,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
isApplied: (current) =>
|
|
104
|
+
readBreakpointSet(current, breakpointSetId).breakpoints.some(
|
|
105
|
+
(breakpoint) => breakpoint.widthPx === widthPx,
|
|
106
|
+
),
|
|
107
|
+
});
|
|
108
|
+
const updatedSet = readBreakpointSet(persisted.data, breakpointSetId);
|
|
109
|
+
const added = updatedSet.breakpoints.find(
|
|
110
|
+
(breakpoint) => breakpoint.id === breakpointId,
|
|
131
111
|
);
|
|
132
|
-
const updatedSet: BreakpointSet = { ...set, breakpoints };
|
|
133
112
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
113
|
+
if (!added) {
|
|
114
|
+
return {
|
|
115
|
+
ignored: true,
|
|
116
|
+
reason: `A breakpoint with width ${widthPx}px already exists.`,
|
|
117
|
+
breakpointSet: updatedSet,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
140
120
|
|
|
141
121
|
return {
|
|
142
|
-
added
|
|
122
|
+
added,
|
|
143
123
|
breakpointSet: updatedSet,
|
|
144
124
|
};
|
|
145
125
|
},
|