@agent-native/core 0.84.0 → 0.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/docs/content/evals.mdx +34 -12
- package/corpus/core/docs/content/locales/ar-SA/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/de-DE/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/es-ES/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/fr-FR/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/hi-IN/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/ja-JP/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/ko-KR/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/pt-BR/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/zh-CN/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/zh-TW/evals.mdx +7 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/eval/define-eval.ts +4 -1
- package/corpus/core/src/eval/report.ts +23 -8
- package/corpus/core/src/eval/runner.ts +41 -6
- package/corpus/core/src/eval/types.ts +11 -0
- package/corpus/templates/content/AGENTS.md +9 -2
- package/corpus/templates/content/actions/_database-row-batch.ts +230 -0
- package/corpus/templates/content/actions/_database-utils.ts +17 -9
- package/corpus/templates/content/actions/_notion-action-utils.ts +26 -0
- package/corpus/templates/content/actions/connect-notion-status.ts +13 -4
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +23 -0
- package/corpus/templates/content/actions/delete-database-items.ts +55 -0
- package/corpus/templates/content/actions/delete-document.ts +4 -4
- package/corpus/templates/content/actions/disconnect-notion.ts +16 -0
- package/corpus/templates/content/actions/duplicate-database-item.ts +1 -1
- package/corpus/templates/content/actions/duplicate-database-items.ts +191 -0
- package/corpus/templates/content/actions/link-notion-page.ts +10 -7
- package/corpus/templates/content/actions/list-notion-links.ts +3 -4
- package/corpus/templates/content/actions/pull-notion-page.ts +7 -9
- package/corpus/templates/content/actions/push-notion-page.ts +7 -9
- package/corpus/templates/content/actions/refresh-notion-sync-status.ts +24 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +23 -0
- package/corpus/templates/content/actions/search-notion-pages.ts +67 -0
- package/corpus/templates/content/actions/unlink-notion-page.ts +23 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +27 -34
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +16 -13
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +10 -10
- package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +1 -1
- package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +18 -9
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +27 -34
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +10 -4
- package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +32 -17
- package/corpus/templates/content/app/hooks/use-content-database.ts +35 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +108 -99
- package/corpus/templates/content/package.json +3 -0
- package/corpus/templates/content/parity/README.md +69 -0
- package/corpus/templates/content/parity/eval-scenarios.ts +118 -0
- package/corpus/templates/content/parity/exceptions.allowlist.ts +17 -0
- package/corpus/templates/content/parity/matrix.md +28 -0
- package/corpus/templates/content/parity/matrix.ts +606 -0
- package/corpus/templates/content/parity/matrix.types.ts +42 -0
- package/corpus/templates/content/parity/parity-evals.eval.ts +4 -0
- package/corpus/templates/content/parity/render-matrix.ts +90 -0
- package/corpus/templates/content/parity/scenario-to-eval.ts +57 -0
- package/corpus/templates/content/shared/api.ts +11 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/eval/define-eval.d.ts.map +1 -1
- package/dist/eval/define-eval.js +2 -1
- package/dist/eval/define-eval.js.map +1 -1
- package/dist/eval/report.d.ts.map +1 -1
- package/dist/eval/report.js +19 -4
- package/dist/eval/report.js.map +1 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +38 -6
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval/types.d.ts +11 -0
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/eval/types.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/docs/content/evals.mdx +34 -12
- package/docs/content/locales/ar-SA/evals.mdx +7 -0
- package/docs/content/locales/de-DE/evals.mdx +8 -0
- package/docs/content/locales/es-ES/evals.mdx +8 -0
- package/docs/content/locales/fr-FR/evals.mdx +8 -0
- package/docs/content/locales/hi-IN/evals.mdx +8 -0
- package/docs/content/locales/ja-JP/evals.mdx +7 -0
- package/docs/content/locales/ko-KR/evals.mdx +7 -0
- package/docs/content/locales/pt-BR/evals.mdx +8 -0
- package/docs/content/locales/zh-CN/evals.mdx +7 -0
- package/docs/content/locales/zh-TW/evals.mdx +7 -0
- package/package.json +1 -1
- package/corpus/templates/content/server/routes/api/notion/disconnect.post.ts +0 -12
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
|
|
5
4
|
import { linkDocumentToNotionPage } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
6
9
|
|
|
7
10
|
export default defineAction({
|
|
8
11
|
description: "Link a document to a Notion page for syncing.",
|
|
@@ -10,19 +13,19 @@ export default defineAction({
|
|
|
10
13
|
documentId: z.string().optional().describe("Document ID (required)"),
|
|
11
14
|
id: z.string().optional().describe("Alias for --documentId"),
|
|
12
15
|
pageId: z.string().optional().describe("Notion page ID or URL (required)"),
|
|
16
|
+
pageIdOrUrl: z.string().optional().describe("Alias for --pageId"),
|
|
13
17
|
url: z.string().optional().describe("Alias for --pageId"),
|
|
14
18
|
}),
|
|
15
|
-
http:
|
|
19
|
+
http: { method: "POST" },
|
|
16
20
|
run: async (args) => {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const documentId = args.documentId || args.id;
|
|
20
|
-
const pageIdOrUrl = args.pageId || args.url;
|
|
21
|
+
const documentId = resolveDocumentId(args);
|
|
22
|
+
const pageIdOrUrl = args.pageId || args.pageIdOrUrl || args.url;
|
|
21
23
|
|
|
22
|
-
if (!
|
|
24
|
+
if (!pageIdOrUrl) {
|
|
23
25
|
throw new Error("documentId and pageId are required");
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
26
29
|
return linkDocumentToNotionPage(owner, documentId, pageIdOrUrl);
|
|
27
30
|
},
|
|
28
31
|
});
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
|
|
5
4
|
import { listNotionLinks } from "../server/lib/notion-sync.js";
|
|
5
|
+
import { getCurrentNotionOwner } from "./_notion-action-utils.js";
|
|
6
6
|
|
|
7
7
|
export default defineAction({
|
|
8
8
|
description: "List all documents linked to Notion pages.",
|
|
9
9
|
schema: z.object({}),
|
|
10
|
-
http:
|
|
10
|
+
http: { method: "GET" },
|
|
11
11
|
run: async () => {
|
|
12
|
-
const owner =
|
|
13
|
-
if (!owner) throw new Error("no authenticated user");
|
|
12
|
+
const owner = getCurrentNotionOwner();
|
|
14
13
|
return listNotionLinks(owner);
|
|
15
14
|
},
|
|
16
15
|
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
|
|
5
4
|
import { pullDocumentFromNotion } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
6
9
|
|
|
7
10
|
export default defineAction({
|
|
8
11
|
description: "Pull content from a linked Notion page into a local document.",
|
|
@@ -10,15 +13,10 @@ export default defineAction({
|
|
|
10
13
|
documentId: z.string().optional().describe("Document ID (required)"),
|
|
11
14
|
id: z.string().optional().describe("Alias for --documentId"),
|
|
12
15
|
}),
|
|
13
|
-
http:
|
|
16
|
+
http: { method: "POST" },
|
|
14
17
|
run: async (args) => {
|
|
15
|
-
const documentId = args
|
|
16
|
-
|
|
17
|
-
throw new Error("documentId is required");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const owner = getRequestUserEmail();
|
|
21
|
-
if (!owner) throw new Error("no authenticated user");
|
|
18
|
+
const documentId = resolveDocumentId(args);
|
|
19
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
22
20
|
return pullDocumentFromNotion(owner, documentId, true);
|
|
23
21
|
},
|
|
24
22
|
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
|
|
5
4
|
import { pushDocumentToNotion } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
6
9
|
|
|
7
10
|
export default defineAction({
|
|
8
11
|
description: "Push local document content to a linked Notion page.",
|
|
@@ -10,15 +13,10 @@ export default defineAction({
|
|
|
10
13
|
documentId: z.string().optional().describe("Document ID (required)"),
|
|
11
14
|
id: z.string().optional().describe("Alias for --documentId"),
|
|
12
15
|
}),
|
|
13
|
-
http:
|
|
16
|
+
http: { method: "POST" },
|
|
14
17
|
run: async (args) => {
|
|
15
|
-
const documentId = args
|
|
16
|
-
|
|
17
|
-
throw new Error("documentId is required");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const owner = getRequestUserEmail();
|
|
21
|
-
if (!owner) throw new Error("no authenticated user");
|
|
18
|
+
const documentId = resolveDocumentId(args);
|
|
19
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
22
20
|
return pushDocumentToNotion(owner, documentId);
|
|
23
21
|
},
|
|
24
22
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { refreshDocumentSyncStatus } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
9
|
+
|
|
10
|
+
export default defineAction({
|
|
11
|
+
description: "Refresh Notion sync status for a linked Content document.",
|
|
12
|
+
schema: z.object({
|
|
13
|
+
documentId: z.string().optional().describe("Document ID (required)"),
|
|
14
|
+
id: z.string().optional().describe("Alias for --documentId"),
|
|
15
|
+
autoSync: z.boolean().optional(),
|
|
16
|
+
}),
|
|
17
|
+
run: async (args) => {
|
|
18
|
+
const documentId = resolveDocumentId(args);
|
|
19
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
20
|
+
return refreshDocumentSyncStatus(owner, documentId, {
|
|
21
|
+
autoSync: !!args.autoSync,
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { resolveDocumentSyncConflict } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
9
|
+
|
|
10
|
+
export default defineAction({
|
|
11
|
+
description: "Resolve a Notion sync conflict by pulling or pushing.",
|
|
12
|
+
schema: z.object({
|
|
13
|
+
documentId: z.string().optional().describe("Document ID (required)"),
|
|
14
|
+
id: z.string().optional().describe("Alias for --documentId"),
|
|
15
|
+
direction: z.enum(["pull", "push"]),
|
|
16
|
+
}),
|
|
17
|
+
http: { method: "POST" },
|
|
18
|
+
run: async (args) => {
|
|
19
|
+
const documentId = resolveDocumentId(args);
|
|
20
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
21
|
+
return resolveDocumentSyncConflict(owner, documentId, args.direction);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getNotionConnectionForOwner,
|
|
6
|
+
notionFetch,
|
|
7
|
+
} from "../server/lib/notion.js";
|
|
8
|
+
import type {
|
|
9
|
+
NotionSearchResponse,
|
|
10
|
+
NotionSearchResult,
|
|
11
|
+
} from "../shared/api.js";
|
|
12
|
+
import { getCurrentNotionOwner } from "./_notion-action-utils.js";
|
|
13
|
+
|
|
14
|
+
export default defineAction({
|
|
15
|
+
description: "Search connected Notion pages visible to the current user.",
|
|
16
|
+
schema: z.object({
|
|
17
|
+
query: z.string().default(""),
|
|
18
|
+
}),
|
|
19
|
+
http: { method: "GET" },
|
|
20
|
+
run: async ({ query }): Promise<NotionSearchResponse> => {
|
|
21
|
+
const owner = getCurrentNotionOwner();
|
|
22
|
+
const conn = await getNotionConnectionForOwner(owner);
|
|
23
|
+
if (!conn) {
|
|
24
|
+
throw new Error("Notion not connected");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const result = await notionFetch<{
|
|
28
|
+
results: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
object: string;
|
|
31
|
+
icon?: { type: string; emoji?: string } | null;
|
|
32
|
+
url?: string;
|
|
33
|
+
last_edited_time?: string;
|
|
34
|
+
properties?: Record<string, any>;
|
|
35
|
+
}>;
|
|
36
|
+
has_more: boolean;
|
|
37
|
+
}>("/search", conn.accessToken, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: JSON.stringify({
|
|
40
|
+
query: query.trim(),
|
|
41
|
+
filter: { value: "page", property: "object" },
|
|
42
|
+
sort: { direction: "descending", timestamp: "last_edited_time" },
|
|
43
|
+
page_size: 20,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const results: NotionSearchResult[] = result.results.map((page) => {
|
|
48
|
+
const titleProp = Object.values(page.properties || {}).find(
|
|
49
|
+
(value: any) => value?.type === "title",
|
|
50
|
+
) as any;
|
|
51
|
+
const title =
|
|
52
|
+
(titleProp?.title || [])
|
|
53
|
+
.map((part: any) => part.plain_text || "")
|
|
54
|
+
.join("") || "Untitled";
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
id: page.id,
|
|
58
|
+
title,
|
|
59
|
+
icon: page.icon?.type === "emoji" ? page.icon.emoji || null : null,
|
|
60
|
+
url: page.url || `https://notion.so/${page.id.replace(/-/g, "")}`,
|
|
61
|
+
lastEditedTime: page.last_edited_time || null,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return { results, hasMore: result.has_more };
|
|
66
|
+
},
|
|
67
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import { unlinkDocumentFromNotion } from "../server/lib/notion-sync.js";
|
|
5
|
+
import {
|
|
6
|
+
getNotionDocumentOwner,
|
|
7
|
+
resolveDocumentId,
|
|
8
|
+
} from "./_notion-action-utils.js";
|
|
9
|
+
|
|
10
|
+
export default defineAction({
|
|
11
|
+
description: "Unlink a Content document from its Notion page.",
|
|
12
|
+
schema: z.object({
|
|
13
|
+
documentId: z.string().optional().describe("Document ID (required)"),
|
|
14
|
+
id: z.string().optional().describe("Alias for --documentId"),
|
|
15
|
+
}),
|
|
16
|
+
http: { method: "DELETE" },
|
|
17
|
+
run: async (args) => {
|
|
18
|
+
const documentId = resolveDocumentId(args);
|
|
19
|
+
const owner = await getNotionDocumentOwner(documentId);
|
|
20
|
+
await unlinkDocumentFromNotion(owner, documentId);
|
|
21
|
+
return { success: true };
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -143,8 +143,10 @@ import {
|
|
|
143
143
|
useChangeContentDatabaseSourceRole,
|
|
144
144
|
useContentDatabase,
|
|
145
145
|
useContentDatabases,
|
|
146
|
+
useDeleteDatabaseItems,
|
|
146
147
|
useDisconnectContentDatabaseSource,
|
|
147
148
|
useDuplicateDatabaseItem,
|
|
149
|
+
useDuplicateDatabaseItems,
|
|
148
150
|
useExecuteBuilderSourceBatch,
|
|
149
151
|
useMoveDatabaseItem,
|
|
150
152
|
usePrepareBuilderSourceReview,
|
|
@@ -2862,9 +2864,9 @@ function DatabaseTableView({
|
|
|
2862
2864
|
const db = useDatabaseT();
|
|
2863
2865
|
const queryClient = useQueryClient();
|
|
2864
2866
|
const moveItem = useMoveDatabaseItem(databaseDocumentId);
|
|
2865
|
-
const
|
|
2867
|
+
const duplicateItems = useDuplicateDatabaseItems(databaseDocumentId);
|
|
2866
2868
|
const setProperty = useSetDocumentProperty(databaseDocumentId);
|
|
2867
|
-
const
|
|
2869
|
+
const deleteItems = useDeleteDatabaseItems(databaseDocumentId);
|
|
2868
2870
|
const [draggedItemId, setDraggedItemId] = useState<string | null>(null);
|
|
2869
2871
|
const [dropTargetItemId, setDropTargetItemId] = useState<string | null>(null);
|
|
2870
2872
|
const [draggedPropertyId, setDraggedPropertyId] = useState<string | null>(
|
|
@@ -3113,14 +3115,15 @@ function DatabaseTableView({
|
|
|
3113
3115
|
async function deleteSelectedRows() {
|
|
3114
3116
|
if (selectedItems.length === 0) return;
|
|
3115
3117
|
const selectedSnapshot = selectedItems;
|
|
3116
|
-
onClearSelection();
|
|
3117
3118
|
setConfirmDeleteSelectedOpen(false);
|
|
3118
3119
|
|
|
3119
3120
|
try {
|
|
3121
|
+
await deleteItems.mutateAsync({
|
|
3122
|
+
documentId: databaseDocumentId,
|
|
3123
|
+
itemIds: selectedSnapshot.map((item) => item.id),
|
|
3124
|
+
});
|
|
3125
|
+
onClearSelection();
|
|
3120
3126
|
onDeletedPreviewItems(selectedSnapshot);
|
|
3121
|
-
for (const item of selectedSnapshot) {
|
|
3122
|
-
await deleteDocument.mutateAsync({ id: item.document.id });
|
|
3123
|
-
}
|
|
3124
3127
|
await queryClient.invalidateQueries({
|
|
3125
3128
|
queryKey: [
|
|
3126
3129
|
"action",
|
|
@@ -3144,22 +3147,11 @@ function DatabaseTableView({
|
|
|
3144
3147
|
const selectedSnapshot = selectedItems;
|
|
3145
3148
|
setIsDuplicatingSelected(true);
|
|
3146
3149
|
|
|
3147
|
-
let duplicatedPreviewItem: ContentDatabaseItem | null = null;
|
|
3148
|
-
let duplicatedCount = 0;
|
|
3149
|
-
let failedCount = 0;
|
|
3150
|
-
|
|
3151
3150
|
try {
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
duplicatedPreviewItem =
|
|
3157
|
-
databaseDuplicatedItemFromResponse(response) ??
|
|
3158
|
-
duplicatedPreviewItem;
|
|
3159
|
-
} catch {
|
|
3160
|
-
failedCount += 1;
|
|
3161
|
-
}
|
|
3162
|
-
}
|
|
3151
|
+
const response = await duplicateItems.mutateAsync({
|
|
3152
|
+
documentId: databaseDocumentId,
|
|
3153
|
+
itemIds: selectedSnapshot.map((item) => item.id),
|
|
3154
|
+
});
|
|
3163
3155
|
|
|
3164
3156
|
await queryClient.invalidateQueries({
|
|
3165
3157
|
queryKey: [
|
|
@@ -3172,16 +3164,15 @@ function DatabaseTableView({
|
|
|
3172
3164
|
queryKey: ["action", "list-documents"],
|
|
3173
3165
|
});
|
|
3174
3166
|
|
|
3167
|
+
const duplicatedPreviewItem =
|
|
3168
|
+
databaseDuplicatedItemFromResponse(response);
|
|
3175
3169
|
if (duplicatedPreviewItem) onPreview(duplicatedPreviewItem);
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
: "No rows were duplicated.",
|
|
3183
|
-
});
|
|
3184
|
-
}
|
|
3170
|
+
onClearSelection();
|
|
3171
|
+
} catch (err) {
|
|
3172
|
+
toast.error(db("failedToDuplicateEverySelectedRow"), {
|
|
3173
|
+
description:
|
|
3174
|
+
err instanceof Error ? err.message : db("somethingWentWrong"),
|
|
3175
|
+
});
|
|
3185
3176
|
} finally {
|
|
3186
3177
|
setIsDuplicatingSelected(false);
|
|
3187
3178
|
}
|
|
@@ -3240,9 +3231,11 @@ function DatabaseTableView({
|
|
|
3240
3231
|
canEdit={canEdit}
|
|
3241
3232
|
properties={bulkEditableProperties}
|
|
3242
3233
|
duplicateDisabled={
|
|
3243
|
-
isDuplicatingSelected ||
|
|
3234
|
+
isDuplicatingSelected ||
|
|
3235
|
+
duplicateItems.isPending ||
|
|
3236
|
+
deleteItems.isPending
|
|
3244
3237
|
}
|
|
3245
|
-
deleteDisabled={
|
|
3238
|
+
deleteDisabled={deleteItems.isPending}
|
|
3246
3239
|
updateDisabled={setProperty.isPending}
|
|
3247
3240
|
onClearSelection={onClearSelection}
|
|
3248
3241
|
onSetPropertyValue={setSelectedPropertyValue}
|
|
@@ -3466,10 +3459,10 @@ function DatabaseTableView({
|
|
|
3466
3459
|
</AlertDialogCancel>
|
|
3467
3460
|
<AlertDialogAction
|
|
3468
3461
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
3469
|
-
disabled={
|
|
3462
|
+
disabled={deleteItems.isPending}
|
|
3470
3463
|
onClick={() => void deleteSelectedRows()}
|
|
3471
3464
|
>
|
|
3472
|
-
{
|
|
3465
|
+
{deleteItems.isPending ? "Deleting..." : "Delete"}
|
|
3473
3466
|
</AlertDialogAction>
|
|
3474
3467
|
</AlertDialogFooter>
|
|
3475
3468
|
</AlertDialogContent>
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
emailToName,
|
|
7
7
|
useSession,
|
|
8
8
|
useT,
|
|
9
|
-
appApiPath,
|
|
10
9
|
agentNativePath,
|
|
11
10
|
type CollabUser,
|
|
12
11
|
} from "@agent-native/core/client";
|
|
@@ -41,7 +40,11 @@ import {
|
|
|
41
40
|
useUpdateDocument,
|
|
42
41
|
} from "@/hooks/use-documents";
|
|
43
42
|
import { useLocalStorage } from "@/hooks/use-local-storage";
|
|
44
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
documentSyncStatusQueryKey,
|
|
45
|
+
useDocumentSyncStatus,
|
|
46
|
+
usePushDocumentToNotion,
|
|
47
|
+
} from "@/hooks/use-notion";
|
|
45
48
|
import {
|
|
46
49
|
canWriteLinkedLocalSource,
|
|
47
50
|
readDocumentFromLinkedLocalSource,
|
|
@@ -360,6 +363,7 @@ function DocumentEditorBody({ documentId, document }: DocumentEditorBodyProps) {
|
|
|
360
363
|
useDocumentSyncStatus(canEdit && !isLocalFileDocument ? documentId : null, {
|
|
361
364
|
autoSync,
|
|
362
365
|
});
|
|
366
|
+
const pushDocumentToNotion = usePushDocumentToNotion(documentId);
|
|
363
367
|
const [localTitle, setLocalTitle] = useState("");
|
|
364
368
|
const [localContent, setLocalContent] = useState("");
|
|
365
369
|
const [localContentUpdatedAt, setLocalContentUpdatedAt] = useState<
|
|
@@ -775,20 +779,18 @@ function DocumentEditorBody({ documentId, document }: DocumentEditorBodyProps) {
|
|
|
775
779
|
// the debounce and the next save, reading the previous content.
|
|
776
780
|
// Pulls remain driven by the polling refetch in useDocumentSyncStatus.
|
|
777
781
|
if (autoSync) {
|
|
778
|
-
const status = queryClient.getQueryData<DocumentSyncStatus>(
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
]);
|
|
782
|
+
const status = queryClient.getQueryData<DocumentSyncStatus>(
|
|
783
|
+
documentSyncStatusQueryKey(documentId, { autoSync }),
|
|
784
|
+
);
|
|
782
785
|
if (status?.pageId && !status.hasConflict) {
|
|
783
786
|
try {
|
|
784
|
-
const
|
|
785
|
-
|
|
786
|
-
|
|
787
|
+
const next = await pushDocumentToNotion.mutateAsync({
|
|
788
|
+
documentId,
|
|
789
|
+
});
|
|
790
|
+
queryClient.setQueryData(
|
|
791
|
+
documentSyncStatusQueryKey(documentId, { autoSync }),
|
|
792
|
+
next,
|
|
787
793
|
);
|
|
788
|
-
if (res.ok) {
|
|
789
|
-
const next = (await res.json()) as DocumentSyncStatus;
|
|
790
|
-
queryClient.setQueryData(["document-sync", documentId], next);
|
|
791
|
-
}
|
|
792
794
|
} catch {
|
|
793
795
|
// Non-fatal — next polling refetch will surface any error.
|
|
794
796
|
}
|
|
@@ -803,6 +805,7 @@ function DocumentEditorBody({ documentId, document }: DocumentEditorBodyProps) {
|
|
|
803
805
|
autoSync,
|
|
804
806
|
isLinkedLocalSourceDocument,
|
|
805
807
|
persistDocumentUpdates,
|
|
808
|
+
pushDocumentToNotion,
|
|
806
809
|
queryClient,
|
|
807
810
|
],
|
|
808
811
|
);
|
|
@@ -533,7 +533,7 @@ export function DocumentToolbar({
|
|
|
533
533
|
async (pageId: string) => {
|
|
534
534
|
setLinkingPageId(pageId);
|
|
535
535
|
try {
|
|
536
|
-
await linkDocument.mutateAsync({ pageIdOrUrl: pageId });
|
|
536
|
+
await linkDocument.mutateAsync({ documentId, pageIdOrUrl: pageId });
|
|
537
537
|
toast.success(t("editor.toolbar.linkedToNotionPage"));
|
|
538
538
|
setSearchQuery("");
|
|
539
539
|
} catch (error) {
|
|
@@ -546,34 +546,34 @@ export function DocumentToolbar({
|
|
|
546
546
|
setLinkingPageId(null);
|
|
547
547
|
}
|
|
548
548
|
},
|
|
549
|
-
[linkDocument, t],
|
|
549
|
+
[documentId, linkDocument, t],
|
|
550
550
|
);
|
|
551
551
|
|
|
552
552
|
const handlePull = useCallback(async () => {
|
|
553
553
|
try {
|
|
554
|
-
await pullDocument.mutateAsync();
|
|
554
|
+
await pullDocument.mutateAsync({ documentId });
|
|
555
555
|
toast.success(t("editor.toolbar.pulledFromNotion"));
|
|
556
556
|
} catch (error) {
|
|
557
557
|
toast.error(
|
|
558
558
|
error instanceof Error ? error.message : t("editor.toolbar.pullFailed"),
|
|
559
559
|
);
|
|
560
560
|
}
|
|
561
|
-
}, [pullDocument, t]);
|
|
561
|
+
}, [documentId, pullDocument, t]);
|
|
562
562
|
|
|
563
563
|
const handlePush = useCallback(async () => {
|
|
564
564
|
try {
|
|
565
|
-
await pushDocument.mutateAsync();
|
|
565
|
+
await pushDocument.mutateAsync({ documentId });
|
|
566
566
|
toast.success(t("editor.toolbar.pushedToNotion"));
|
|
567
567
|
} catch (error) {
|
|
568
568
|
toast.error(
|
|
569
569
|
error instanceof Error ? error.message : t("editor.toolbar.pushFailed"),
|
|
570
570
|
);
|
|
571
571
|
}
|
|
572
|
-
}, [pushDocument, t]);
|
|
572
|
+
}, [documentId, pushDocument, t]);
|
|
573
573
|
|
|
574
574
|
const handleUnlink = useCallback(async () => {
|
|
575
575
|
try {
|
|
576
|
-
await unlinkDocument.mutateAsync();
|
|
576
|
+
await unlinkDocument.mutateAsync({ documentId });
|
|
577
577
|
toast.success(t("editor.toolbar.unlinkedFromNotion"));
|
|
578
578
|
} catch (error) {
|
|
579
579
|
toast.error(
|
|
@@ -582,13 +582,13 @@ export function DocumentToolbar({
|
|
|
582
582
|
: t("editor.toolbar.unlinkFailed"),
|
|
583
583
|
);
|
|
584
584
|
}
|
|
585
|
-
}, [unlinkDocument, t]);
|
|
585
|
+
}, [documentId, unlinkDocument, t]);
|
|
586
586
|
|
|
587
587
|
const handleCreateAndLink = useCallback(
|
|
588
588
|
(parentPageIdOrUrl?: string) => {
|
|
589
589
|
if (parentPageIdOrUrl) setCreatingParentPageId(parentPageIdOrUrl);
|
|
590
590
|
createAndLink.mutate(
|
|
591
|
-
parentPageIdOrUrl ? { parentPageIdOrUrl } :
|
|
591
|
+
{ documentId, ...(parentPageIdOrUrl ? { parentPageIdOrUrl } : {}) },
|
|
592
592
|
{
|
|
593
593
|
onSuccess: () => {
|
|
594
594
|
toast.success(t("editor.toolbar.createdAndLinkedToNotionPage"));
|
|
@@ -605,7 +605,7 @@ export function DocumentToolbar({
|
|
|
605
605
|
},
|
|
606
606
|
);
|
|
607
607
|
},
|
|
608
|
-
[createAndLink, t],
|
|
608
|
+
[createAndLink, documentId, t],
|
|
609
609
|
);
|
|
610
610
|
|
|
611
611
|
const handleSetup = () => {
|
|
@@ -34,7 +34,7 @@ export function NotionConflictBanner({
|
|
|
34
34
|
const handleResolve = async (dir: "pull" | "push") => {
|
|
35
35
|
setDirection(dir);
|
|
36
36
|
try {
|
|
37
|
-
await resolveConflict.mutateAsync({ direction: dir });
|
|
37
|
+
await resolveConflict.mutateAsync({ documentId, direction: dir });
|
|
38
38
|
toast.success(
|
|
39
39
|
dir === "pull"
|
|
40
40
|
? t("editor.notionConflictResolvedPulled")
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
useDocumentSyncStatus,
|
|
20
20
|
useLinkDocumentToNotion,
|
|
21
21
|
useNotionConnection,
|
|
22
|
+
openNotionOAuthUrl,
|
|
22
23
|
usePullDocumentFromNotion,
|
|
23
24
|
usePushDocumentToNotion,
|
|
24
25
|
useResolveDocumentSyncConflict,
|
|
@@ -63,12 +64,20 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
63
64
|
resolveConflict.isPending ||
|
|
64
65
|
disconnectNotion.isPending;
|
|
65
66
|
|
|
66
|
-
const handleConnect = () => {
|
|
67
|
-
if (
|
|
67
|
+
const handleConnect = async () => {
|
|
68
|
+
if (connection?.error === "missing_credentials") {
|
|
68
69
|
toast.error(t("editor.toolbar.setUpNotionFirst"));
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
try {
|
|
73
|
+
window.location.href = await openNotionOAuthUrl();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
toast.error(
|
|
76
|
+
error instanceof Error
|
|
77
|
+
? error.message
|
|
78
|
+
: t("editor.toolbar.setUpNotionFirst"),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
72
81
|
};
|
|
73
82
|
|
|
74
83
|
const handleLink = async () => {
|
|
@@ -77,7 +86,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
77
86
|
return;
|
|
78
87
|
}
|
|
79
88
|
try {
|
|
80
|
-
await linkDocument.mutateAsync({ pageIdOrUrl });
|
|
89
|
+
await linkDocument.mutateAsync({ documentId, pageIdOrUrl });
|
|
81
90
|
setPageIdOrUrl("");
|
|
82
91
|
toast.success(t("editor.toolbar.linkedToNotion"));
|
|
83
92
|
} catch (error) {
|
|
@@ -91,7 +100,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
91
100
|
|
|
92
101
|
const handlePull = async () => {
|
|
93
102
|
try {
|
|
94
|
-
await pullDocument.mutateAsync();
|
|
103
|
+
await pullDocument.mutateAsync({ documentId });
|
|
95
104
|
toast.success(t("editor.toolbar.pulledFromNotion"));
|
|
96
105
|
} catch (error) {
|
|
97
106
|
toast.error(
|
|
@@ -102,7 +111,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
102
111
|
|
|
103
112
|
const handlePush = async () => {
|
|
104
113
|
try {
|
|
105
|
-
await pushDocument.mutateAsync();
|
|
114
|
+
await pushDocument.mutateAsync({ documentId });
|
|
106
115
|
toast.success(t("editor.toolbar.pushedToNotion"));
|
|
107
116
|
} catch (error) {
|
|
108
117
|
toast.error(
|
|
@@ -113,7 +122,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
113
122
|
|
|
114
123
|
const handleResolve = async (direction: "pull" | "push") => {
|
|
115
124
|
try {
|
|
116
|
-
await resolveConflict.mutateAsync({ direction });
|
|
125
|
+
await resolveConflict.mutateAsync({ documentId, direction });
|
|
117
126
|
toast.success(
|
|
118
127
|
direction === "pull"
|
|
119
128
|
? t("editor.toolbar.conflictResolvedFromNotion")
|
|
@@ -130,7 +139,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
130
139
|
|
|
131
140
|
const handleUnlink = async () => {
|
|
132
141
|
try {
|
|
133
|
-
await unlinkDocument.mutateAsync();
|
|
142
|
+
await unlinkDocument.mutateAsync({ documentId });
|
|
134
143
|
toast.success(t("editor.toolbar.unlinkedFromNotion"));
|
|
135
144
|
} catch (error) {
|
|
136
145
|
toast.error(
|
|
@@ -143,7 +152,7 @@ export function NotionSyncBar({ documentId }: NotionSyncBarProps) {
|
|
|
143
152
|
|
|
144
153
|
const handleDisconnect = async () => {
|
|
145
154
|
try {
|
|
146
|
-
await disconnectNotion.mutateAsync();
|
|
155
|
+
await disconnectNotion.mutateAsync({});
|
|
147
156
|
toast.success(t("editor.toolbar.disconnectedNotionWorkspace"));
|
|
148
157
|
} catch (error) {
|
|
149
158
|
toast.error(
|