@agent-native/core 0.114.5 → 0.114.6

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 (76) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/resources/ResourceTree.tsx +11 -5
  5. package/corpus/core/src/client/resources/ResourcesPanel.tsx +141 -18
  6. package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +1 -2
  7. package/corpus/templates/clips/changelog/2026-07-20-opening-zoom-meeting-launches-native-app.md +6 -0
  8. package/corpus/templates/clips/desktop/src/app.tsx +7 -11
  9. package/corpus/templates/clips/desktop/src/lib/open-meeting-join-url.ts +22 -0
  10. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +2 -3
  11. package/corpus/templates/clips/shared/meeting-join-url.ts +0 -5
  12. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +9 -1
  13. package/corpus/templates/content/AGENTS.md +4 -1
  14. package/corpus/templates/content/actions/_content-spaces.ts +6 -1
  15. package/corpus/templates/content/actions/_database-row-batch.ts +15 -2
  16. package/corpus/templates/content/actions/_database-utils.ts +83 -15
  17. package/corpus/templates/content/actions/add-database-item.ts +3 -0
  18. package/corpus/templates/content/actions/connect-local-folder-source.ts +2 -1
  19. package/corpus/templates/content/actions/delete-content-database.ts +12 -9
  20. package/corpus/templates/content/actions/delete-database-items.ts +3 -2
  21. package/corpus/templates/content/actions/delete-document.ts +233 -6
  22. package/corpus/templates/content/actions/duplicate-database-item.ts +1 -0
  23. package/corpus/templates/content/actions/get-document.ts +4 -1
  24. package/corpus/templates/content/actions/list-content-databases.ts +1 -0
  25. package/corpus/templates/content/actions/list-documents.ts +1 -0
  26. package/corpus/templates/content/actions/list-trashed-content-databases.ts +8 -2
  27. package/corpus/templates/content/actions/list-trashed-documents.ts +50 -0
  28. package/corpus/templates/content/actions/permanently-delete-document.ts +28 -0
  29. package/corpus/templates/content/actions/pull-document.ts +15 -2
  30. package/corpus/templates/content/actions/restore-content-database.ts +48 -11
  31. package/corpus/templates/content/actions/restore-document.ts +28 -0
  32. package/corpus/templates/content/actions/search-documents.ts +2 -1
  33. package/corpus/templates/content/actions/view-screen.ts +2 -1
  34. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +149 -55
  35. package/corpus/templates/content/app/components/editor/database/GalleryView.tsx +7 -2
  36. package/corpus/templates/content/app/components/editor/database/ListView.tsx +7 -2
  37. package/corpus/templates/content/app/components/editor/database/TimelineView.tsx +3 -0
  38. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +26 -5
  39. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +243 -163
  40. package/corpus/templates/content/app/components/sidebar/WorkspaceSourceMenu.tsx +154 -0
  41. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +11 -0
  42. package/corpus/templates/content/app/hooks/use-content-database.ts +6 -0
  43. package/corpus/templates/content/app/hooks/use-documents.ts +57 -0
  44. package/corpus/templates/content/app/i18n-data.ts +83 -2
  45. package/corpus/templates/content/app/routes/_app.local-files.tsx +8 -1
  46. package/corpus/templates/content/changelog/2026-07-19-pages-now-move-to-a-reversible-trash-and-the-organization-pi.md +6 -0
  47. package/corpus/templates/content/changelog/2026-07-20-trash-actions-now-preserve-independent-archived-pages-enforc.md +6 -0
  48. package/corpus/templates/content/changelog/2026-07-20-workspace-toggles-now-stay-independently-open-or-closed-and-.md +6 -0
  49. package/corpus/templates/content/changelog/2026-07-20-workspaces-can-be-added-from-a-blank-workspace-or-a-connecte.md +6 -0
  50. package/corpus/templates/content/parity/matrix.md +1 -1
  51. package/corpus/templates/content/parity/matrix.ts +3 -0
  52. package/corpus/templates/content/server/db/schema.ts +2 -0
  53. package/corpus/templates/content/server/lib/public-documents.ts +8 -2
  54. package/corpus/templates/content/server/plugins/db.ts +52 -0
  55. package/corpus/templates/content/server/routes/api/document-agent-context.json.get.ts +2 -2
  56. package/corpus/templates/content/shared/api.ts +10 -0
  57. package/corpus/toolkit/CHANGELOG.md +6 -0
  58. package/corpus/toolkit/package.json +1 -1
  59. package/corpus/toolkit/src/ui/progress.tsx +3 -2
  60. package/dist/client/resources/ResourceTree.d.ts +3 -1
  61. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  62. package/dist/client/resources/ResourceTree.js +4 -4
  63. package/dist/client/resources/ResourceTree.js.map +1 -1
  64. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  65. package/dist/client/resources/ResourcesPanel.js +55 -6
  66. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  67. package/dist/collab/routes.d.ts +1 -1
  68. package/dist/collab/struct-routes.d.ts +1 -1
  69. package/dist/notifications/routes.d.ts +1 -1
  70. package/dist/observability/routes.d.ts +5 -5
  71. package/dist/progress/routes.d.ts +1 -1
  72. package/dist/secrets/routes.d.ts +9 -9
  73. package/dist/server/transcribe-voice.d.ts +1 -1
  74. package/package.json +2 -2
  75. package/src/client/resources/ResourceTree.tsx +11 -5
  76. package/src/client/resources/ResourcesPanel.tsx +141 -18
@@ -4,6 +4,7 @@ import { resolveAccess } from "@agent-native/core/sharing";
4
4
  import { z } from "zod";
5
5
 
6
6
  import "../server/db/index.js";
7
+ import { isSoftDeletedDatabaseDocument } from "./_database-utils.js";
7
8
  import { flushOpenDocumentEditorToSql } from "./_document-flush.js";
8
9
 
9
10
  /**
@@ -62,7 +63,13 @@ export default defineAction({
62
63
  publicAgent: { expose: true, readOnly: true, requiresAuth: true },
63
64
  run: async ({ id, format }) => {
64
65
  const access = await resolveAccess("document", id);
65
- if (!access) throw new Error(`Document "${id}" not found`);
66
+ if (
67
+ !access ||
68
+ access.resource.trashedAt ||
69
+ (await isSoftDeletedDatabaseDocument(id))
70
+ ) {
71
+ throw new Error(`Document "${id}" not found`);
72
+ }
66
73
 
67
74
  // If a live Yjs collab session is open, the in-memory editor doc is fresher
68
75
  // than the SQL column. Ask the open editor to serialize + save, then wait
@@ -74,7 +81,13 @@ export default defineAction({
74
81
 
75
82
  // Re-resolve so we read the now-fresh row (and re-check access).
76
83
  const fresh = await resolveAccess("document", id);
77
- if (!fresh) throw new Error(`Document "${id}" not found`);
84
+ if (
85
+ !fresh ||
86
+ fresh.resource.trashedAt ||
87
+ (await isSoftDeletedDatabaseDocument(id))
88
+ ) {
89
+ throw new Error(`Document "${id}" not found`);
90
+ }
78
91
  const doc = fresh.resource;
79
92
  const markdown = (doc.content as string) ?? "";
80
93
  const content = formatDocumentContent(markdown, format);
@@ -1,7 +1,7 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
3
  import { resolveAccess } from "@agent-native/core/sharing";
4
- import { eq } from "drizzle-orm";
4
+ import { and, eq, isNotNull } from "drizzle-orm";
5
5
  import { z } from "zod";
6
6
 
7
7
  import { getDb, schema } from "../server/db/index.js";
@@ -9,6 +9,7 @@ import {
9
9
  assertContentDatabaseLifecycleAccess,
10
10
  collectInlineDatabaseOwnerBlockIds,
11
11
  } from "./_content-database-lifecycle.js";
12
+ import { restoreDocumentSubtree } from "./delete-document.js";
12
13
  import pullDocumentAction from "./pull-document.js";
13
14
 
14
15
  async function shouldClearStaleInlineOwnership(args: {
@@ -47,16 +48,52 @@ export default defineAction({
47
48
  ownerBlockId: ownership.database.ownerBlockId,
48
49
  });
49
50
 
50
- await db
51
- .update(schema.contentDatabases)
52
- .set({
53
- deletedAt: null,
54
- updatedAt: now,
55
- ...(clearInlineOwnership
56
- ? { ownerDocumentId: null, ownerBlockId: null }
57
- : {}),
58
- })
59
- .where(eq(schema.contentDatabases.id, databaseId));
51
+ await db.transaction(async (tx) => {
52
+ const [backingDocument] = await tx
53
+ .select({
54
+ trashedAt: schema.documents.trashedAt,
55
+ trashRootId: schema.documents.trashRootId,
56
+ })
57
+ .from(schema.documents)
58
+ .where(eq(schema.documents.id, ownership.database.documentId))
59
+ .limit(1);
60
+ if (!backingDocument) {
61
+ throw new Error(`Database "${databaseId}" not found`);
62
+ }
63
+ if (
64
+ backingDocument.trashedAt &&
65
+ backingDocument.trashRootId !== ownership.database.documentId
66
+ ) {
67
+ throw new Error("Restore the parent Trash item instead");
68
+ }
69
+
70
+ const restoredDocumentIds = await restoreDocumentSubtree(
71
+ tx as unknown as ReturnType<typeof getDb>,
72
+ ownership.database.documentId,
73
+ ownership.database.ownerEmail,
74
+ );
75
+ if (
76
+ backingDocument.trashedAt &&
77
+ !restoredDocumentIds.includes(ownership.database.documentId)
78
+ ) {
79
+ throw new Error("Database backing page was not restored");
80
+ }
81
+ await tx
82
+ .update(schema.contentDatabases)
83
+ .set({
84
+ deletedAt: null,
85
+ updatedAt: now,
86
+ ...(clearInlineOwnership
87
+ ? { ownerDocumentId: null, ownerBlockId: null }
88
+ : {}),
89
+ })
90
+ .where(
91
+ and(
92
+ eq(schema.contentDatabases.id, databaseId),
93
+ isNotNull(schema.contentDatabases.deletedAt),
94
+ ),
95
+ );
96
+ });
60
97
 
61
98
  await writeAppState("refresh-signal", { ts: Date.now() });
62
99
 
@@ -0,0 +1,28 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { writeAppState } from "@agent-native/core/application-state";
3
+ import { assertAccess } from "@agent-native/core/sharing";
4
+ import { z } from "zod";
5
+
6
+ import { getDb } from "../server/db/index.js";
7
+ import { restoreDocumentSubtree } from "./delete-document.js";
8
+
9
+ export default defineAction({
10
+ description: "Restore a page subtree from Trash.",
11
+ schema: z.object({
12
+ id: z.string().describe("Trashed root document ID"),
13
+ }),
14
+ run: async ({ id }) => {
15
+ const access = await assertAccess("document", id, "admin");
16
+ const restored = await getDb().transaction((tx) =>
17
+ restoreDocumentSubtree(
18
+ tx as unknown as ReturnType<typeof getDb>,
19
+ id,
20
+ access.resource.ownerEmail as string,
21
+ ),
22
+ );
23
+ if (restored.length === 0) throw new Error("Document is not in Trash");
24
+
25
+ await writeAppState("refresh-signal", { ts: Date.now() });
26
+ return { success: true, restored: restored.length, documentId: id };
27
+ },
28
+ });
@@ -1,6 +1,6 @@
1
1
  import { defineAction } from "@agent-native/core";
2
2
  import { accessFilter } from "@agent-native/core/sharing";
3
- import { and, sql } from "drizzle-orm";
3
+ import { and, isNull, sql } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
@@ -74,6 +74,7 @@ export default defineAction({
74
74
  .where(
75
75
  and(
76
76
  accessFilter(schema.documents, schema.documentShares),
77
+ isNull(schema.documents.trashedAt),
77
78
  documentDiscoveryFilter(),
78
79
  sql`(${schema.documents.title} LIKE ${pattern} ESCAPE '\\' OR ${schema.documents.description} LIKE ${pattern} ESCAPE '\\' OR ${schema.documents.content} LIKE ${pattern} ESCAPE '\\')`,
79
80
  ),
@@ -4,7 +4,7 @@ import {
4
4
  readAppStateForCurrentTab,
5
5
  } from "@agent-native/core/application-state";
6
6
  import { accessFilter, resolveAccess } from "@agent-native/core/sharing";
7
- import { and, asc, inArray } from "drizzle-orm";
7
+ import { and, asc, inArray, isNull } from "drizzle-orm";
8
8
  import { z } from "zod";
9
9
 
10
10
  import { getDb, schema } from "../server/db/index.js";
@@ -765,6 +765,7 @@ export default defineAction({
765
765
  .where(
766
766
  and(
767
767
  accessFilter(schema.documents, schema.documentShares),
768
+ isNull(schema.documents.trashedAt),
768
769
  documentDiscoveryFilter(),
769
770
  ),
770
771
  )
@@ -157,6 +157,7 @@ import {
157
157
  SELECTED_CONTENT_SPACE_STORAGE_KEY,
158
158
  selectContentSpace,
159
159
  } from "@/components/sidebar/select-content-space";
160
+ import { WorkspaceSourceMenu } from "@/components/sidebar/WorkspaceSourceMenu";
160
161
  import {
161
162
  isContentDatabaseUnavailable,
162
163
  useAddDatabaseItem,
@@ -188,7 +189,6 @@ import {
188
189
  } from "@/hooks/use-content-database";
189
190
  import {
190
191
  useContentSpaces,
191
- useCreateContentSpace,
192
192
  useDeleteContentSpace,
193
193
  } from "@/hooks/use-content-spaces";
194
194
  import {
@@ -729,8 +729,6 @@ function DatabaseTable({
729
729
  );
730
730
  const database = useContentDatabase(document.id, databaseRequestItemLimit);
731
731
  const addItem = useAddDatabaseItem(document.id);
732
- const createContentSpace = useCreateContentSpace();
733
- const workspaceCreateRequestIdRef = useRef<string | null>(null);
734
732
  const attachSource = useAttachContentDatabaseSource(document.id);
735
733
  const changeSourceRole = useChangeContentDatabaseSourceRole(document.id);
736
734
  const refreshSource = useRefreshContentDatabaseSource(document.id);
@@ -750,10 +748,8 @@ function DatabaseTable({
750
748
  const data = isContentDatabaseUnavailable(database.data)
751
749
  ? undefined
752
750
  : database.data;
753
- const isCreatingDatabaseItem =
754
- data?.database.systemRole === "workspaces"
755
- ? createContentSpace.isPending
756
- : addItem.isPending;
751
+ const isWorkspaceCatalog = data?.database.systemRole === "workspaces";
752
+ const isCreatingDatabaseItem = addItem.isPending;
757
753
  const isDatabaseInitialLoading = database.isLoading && !data;
758
754
  const properties = data?.properties ?? [];
759
755
  const items = data?.items ?? [];
@@ -764,10 +760,9 @@ function DatabaseTable({
764
760
  const isLoadingMoreItems =
765
761
  database.isFetching && data?.pagination?.limit !== databaseRequestItemLimit;
766
762
  const databaseId = data?.database.id ?? expectedDatabaseId;
767
- const newDatabaseRowLabel =
768
- data?.database.systemRole === "workspaces"
769
- ? t("sidebar.newWorkspace")
770
- : dbText("newPage");
763
+ const newDatabaseRowLabel = isWorkspaceCatalog
764
+ ? t("sidebar.addWorkspace")
765
+ : dbText("newPage");
771
766
  const personalView = useContentDatabasePersonalView(databaseId);
772
767
  const updatePersonalView = useUpdateContentDatabasePersonalView(databaseId);
773
768
  const source = data?.source ?? null;
@@ -847,6 +842,9 @@ function DatabaseTable({
847
842
  const filters = activeView.filters;
848
843
  const visibleFilters = filters;
849
844
  const filterMode = activeView.filterMode ?? "and";
845
+ const workspaceCreationPropertyValues = isWorkspaceCatalog
846
+ ? databasePropertyValuesForNewItem(filters, properties, filterMode)
847
+ : undefined;
850
848
  const columnWidths = activeView.columnWidths;
851
849
  const databaseGroupProperty = useMemo(
852
850
  () => databaseViewGroupingProperty(activeView, orderedProperties),
@@ -1427,29 +1425,7 @@ function DatabaseTable({
1427
1425
  } = {},
1428
1426
  ) {
1429
1427
  if (!databaseId) return null;
1430
- if (data?.database.systemRole === "workspaces") {
1431
- const name = title.trim() || t("sidebar.newWorkspace");
1432
- const requestId =
1433
- workspaceCreateRequestIdRef.current ?? crypto.randomUUID();
1434
- workspaceCreateRequestIdRef.current = requestId;
1435
- try {
1436
- await createContentSpace.mutateAsync({
1437
- name,
1438
- requestId,
1439
- propertyValues:
1440
- Object.keys(propertyValueOverrides).length > 0
1441
- ? propertyValueOverrides
1442
- : undefined,
1443
- });
1444
- workspaceCreateRequestIdRef.current = null;
1445
- } catch (err) {
1446
- toast.error(dbText("failedToCreateRow"), {
1447
- description:
1448
- err instanceof Error ? err.message : dbText("somethingWentWrong"),
1449
- });
1450
- }
1451
- return null;
1452
- }
1428
+ if (isWorkspaceCatalog) return null;
1453
1429
  const propertyValues = {
1454
1430
  ...databasePropertyValuesForNewItem(filters, properties, filterMode),
1455
1431
  ...propertyValueOverrides,
@@ -2417,7 +2393,21 @@ function DatabaseTable({
2417
2393
  </span>
2418
2394
  ) : null}
2419
2395
  </Button>
2420
- {canEdit ? (
2396
+ {canEdit && isWorkspaceCatalog ? (
2397
+ <WorkspaceSourceMenu
2398
+ align="end"
2399
+ propertyValues={workspaceCreationPropertyValues}
2400
+ >
2401
+ <Button
2402
+ type="button"
2403
+ size="sm"
2404
+ className="h-7 rounded-md bg-foreground px-2.5 text-xs font-medium text-background hover:bg-foreground/90"
2405
+ disabled={!databaseId}
2406
+ >
2407
+ New
2408
+ </Button>
2409
+ </WorkspaceSourceMenu>
2410
+ ) : canEdit ? (
2421
2411
  <Button
2422
2412
  type="button"
2423
2413
  size="sm"
@@ -2541,6 +2531,7 @@ function DatabaseTable({
2541
2531
  groupProperty={boardGroupProperty}
2542
2532
  databaseDocumentId={document.id}
2543
2533
  canEdit={canEdit}
2534
+ canCreateItems={!isWorkspaceCatalog}
2544
2535
  isLoading={isDatabaseViewLoading}
2545
2536
  isCreating={isCreatingDatabaseItem || setProperty.isPending}
2546
2537
  hasActiveConstraints={!!searchQuery || activeFilters.length > 0}
@@ -2569,6 +2560,7 @@ function DatabaseTable({
2569
2560
  items={visibleItems}
2570
2561
  databaseDocumentId={document.id}
2571
2562
  canEdit={canEdit}
2563
+ canCreateItems={!isWorkspaceCatalog}
2572
2564
  isLoading={isDatabaseViewLoading}
2573
2565
  isCreating={isCreatingDatabaseItem}
2574
2566
  activeFilters={activeFilters}
@@ -2592,6 +2584,7 @@ function DatabaseTable({
2592
2584
  items={visibleItems}
2593
2585
  databaseDocumentId={document.id}
2594
2586
  canEdit={canEdit}
2587
+ canCreateItems={!isWorkspaceCatalog}
2595
2588
  isLoading={isDatabaseViewLoading}
2596
2589
  isCreating={isCreatingDatabaseItem}
2597
2590
  activeFilters={activeFilters}
@@ -2615,6 +2608,7 @@ function DatabaseTable({
2615
2608
  items={visibleItems}
2616
2609
  databaseDocumentId={document.id}
2617
2610
  canEdit={canEdit}
2611
+ canCreateItems={!isWorkspaceCatalog}
2618
2612
  isLoading={isDatabaseViewLoading}
2619
2613
  isCreating={isCreatingDatabaseItem || setProperty.isPending}
2620
2614
  activeFilters={activeFilters}
@@ -2641,6 +2635,7 @@ function DatabaseTable({
2641
2635
  items={visibleItems}
2642
2636
  databaseDocumentId={document.id}
2643
2637
  canEdit={canEdit}
2638
+ canCreateItems={!isWorkspaceCatalog}
2644
2639
  isLoading={isDatabaseViewLoading}
2645
2640
  isCreating={isCreatingDatabaseItem || setProperty.isPending}
2646
2641
  activeFilters={activeFilters}
@@ -2676,6 +2671,7 @@ function DatabaseTable({
2676
2671
  sources={sources}
2677
2672
  databaseDocumentId={document.id}
2678
2673
  canEdit={canEdit}
2674
+ workspaceCreationPropertyValues={workspaceCreationPropertyValues}
2679
2675
  isLoading={isDatabaseViewLoading}
2680
2676
  isCreating={isCreatingDatabaseItem}
2681
2677
  columnWidths={columnWidths}
@@ -5045,6 +5041,7 @@ function DatabaseTableView({
5045
5041
  sources,
5046
5042
  databaseDocumentId,
5047
5043
  canEdit,
5044
+ workspaceCreationPropertyValues,
5048
5045
  isLoading,
5049
5046
  isCreating,
5050
5047
  columnWidths,
@@ -5090,6 +5087,7 @@ function DatabaseTableView({
5090
5087
  sources: ContentDatabaseSource[];
5091
5088
  databaseDocumentId: string;
5092
5089
  canEdit: boolean;
5090
+ workspaceCreationPropertyValues?: Record<string, DocumentPropertyValue>;
5093
5091
  isLoading: boolean;
5094
5092
  isCreating: boolean;
5095
5093
  columnWidths: Record<string, number>;
@@ -5632,6 +5630,9 @@ function DatabaseTableView({
5632
5630
  columnWidths={columnWidths}
5633
5631
  databaseDocumentId={databaseDocumentId}
5634
5632
  workspaceCatalog={isWorkspaceCatalog}
5633
+ workspaceCreationPropertyValues={
5634
+ workspaceCreationPropertyValues
5635
+ }
5635
5636
  canEdit={canEdit}
5636
5637
  selectedIdSet={selectedIdSet}
5637
5638
  wrapCells={wrapCells}
@@ -5698,16 +5699,27 @@ function DatabaseTableView({
5698
5699
  />
5699
5700
  ))}
5700
5701
  {canEdit && !grouped ? (
5701
- <NewDatabaseRow
5702
- label={newRowLabel}
5703
- properties={properties}
5704
- columnWidths={columnWidths}
5705
- rowDensity={rowDensity}
5706
- disabled={isCreating}
5707
- isPending={isCreating}
5708
- onCreate={onCreateRow}
5709
- actionColumnWidth={actionColumnWidth}
5710
- />
5702
+ isWorkspaceCatalog ? (
5703
+ <WorkspaceSourceMenuRow
5704
+ label={newRowLabel}
5705
+ properties={properties}
5706
+ columnWidths={columnWidths}
5707
+ rowDensity={rowDensity}
5708
+ propertyValues={workspaceCreationPropertyValues}
5709
+ actionColumnWidth={actionColumnWidth}
5710
+ />
5711
+ ) : (
5712
+ <NewDatabaseRow
5713
+ label={newRowLabel}
5714
+ properties={properties}
5715
+ columnWidths={columnWidths}
5716
+ rowDensity={rowDensity}
5717
+ disabled={isCreating}
5718
+ isPending={isCreating}
5719
+ onCreate={onCreateRow}
5720
+ actionColumnWidth={actionColumnWidth}
5721
+ />
5722
+ )
5711
5723
  ) : null}
5712
5724
  {cleanDefaultTable ? (
5713
5725
  <DatabaseBlankDefaultRows
@@ -11602,6 +11614,7 @@ function DatabaseCalendarView({
11602
11614
  items,
11603
11615
  databaseDocumentId,
11604
11616
  canEdit,
11617
+ canCreateItems,
11605
11618
  isLoading,
11606
11619
  isCreating,
11607
11620
  activeFilters,
@@ -11621,6 +11634,7 @@ function DatabaseCalendarView({
11621
11634
  items: ContentDatabaseItem[];
11622
11635
  databaseDocumentId: string;
11623
11636
  canEdit: boolean;
11637
+ canCreateItems: boolean;
11624
11638
  isLoading: boolean;
11625
11639
  isCreating: boolean;
11626
11640
  activeFilters: DatabaseFilter[];
@@ -11659,6 +11673,7 @@ function DatabaseCalendarView({
11659
11673
  );
11660
11674
  const canCreateOnDay =
11661
11675
  canEdit &&
11676
+ canCreateItems &&
11662
11677
  dateProperty?.editable &&
11663
11678
  dateProperty.definition.type === "date";
11664
11679
  const monthLabel = month.toLocaleDateString(undefined, {
@@ -12051,6 +12066,7 @@ function DatabaseBoardView({
12051
12066
  groupProperty,
12052
12067
  databaseDocumentId,
12053
12068
  canEdit,
12069
+ canCreateItems,
12054
12070
  isLoading,
12055
12071
  isCreating,
12056
12072
  isMoving,
@@ -12074,6 +12090,7 @@ function DatabaseBoardView({
12074
12090
  groupProperty: DocumentProperty | null;
12075
12091
  databaseDocumentId: string;
12076
12092
  canEdit: boolean;
12093
+ canCreateItems: boolean;
12077
12094
  isLoading: boolean;
12078
12095
  isCreating: boolean;
12079
12096
  isMoving: boolean;
@@ -12380,7 +12397,7 @@ function DatabaseBoardView({
12380
12397
  {dbText("noMatchingPages")}
12381
12398
  </div>
12382
12399
  ) : null}
12383
- {canEdit ? (
12400
+ {canEdit && canCreateItems ? (
12384
12401
  <NewBoardCard
12385
12402
  group={group}
12386
12403
  disabled={isCreating}
@@ -12812,6 +12829,60 @@ function NewBoardCard({
12812
12829
  );
12813
12830
  }
12814
12831
 
12832
+ function WorkspaceSourceMenuRow({
12833
+ label,
12834
+ properties,
12835
+ columnWidths,
12836
+ rowDensity,
12837
+ actionColumnWidth = ACTION_COLUMN_WIDTH,
12838
+ propertyValues,
12839
+ }: {
12840
+ label: string;
12841
+ properties: DocumentProperty[];
12842
+ columnWidths: Record<string, number>;
12843
+ rowDensity: DatabaseRowDensity;
12844
+ actionColumnWidth?: number;
12845
+ propertyValues?: Record<string, DocumentPropertyValue>;
12846
+ }) {
12847
+ return (
12848
+ <WorkspaceSourceMenu propertyValues={propertyValues}>
12849
+ <button
12850
+ type="button"
12851
+ aria-label={label}
12852
+ className={cn(
12853
+ "grid w-full border-t border-border/35 text-left text-sm text-muted-foreground transition-colors hover:bg-muted/35 hover:text-foreground focus-visible:bg-muted/35 focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
12854
+ databaseTableRowDensityClass(rowDensity),
12855
+ )}
12856
+ style={{
12857
+ gridTemplateColumns: databaseGridColumns(
12858
+ properties,
12859
+ true,
12860
+ columnWidths,
12861
+ actionColumnWidth,
12862
+ ),
12863
+ }}
12864
+ >
12865
+ <span
12866
+ className={cn(
12867
+ "flex min-w-0 items-center gap-2 border-r border-border/35",
12868
+ databaseTableCellDensityClass(rowDensity),
12869
+ )}
12870
+ >
12871
+ <IconPlus className="size-4 shrink-0" />
12872
+ <span className="h-7 min-w-0 flex-1 truncate leading-7">{label}</span>
12873
+ </span>
12874
+ {properties.map((property) => (
12875
+ <span
12876
+ key={property.definition.id}
12877
+ className="border-r border-border/35 last:border-r-0"
12878
+ />
12879
+ ))}
12880
+ <span />
12881
+ </button>
12882
+ </WorkspaceSourceMenu>
12883
+ );
12884
+ }
12885
+
12815
12886
  function NewDatabaseRow({
12816
12887
  label,
12817
12888
  properties,
@@ -17831,6 +17902,7 @@ function DatabaseGroupedTableSection({
17831
17902
  columnWidths,
17832
17903
  databaseDocumentId,
17833
17904
  workspaceCatalog,
17905
+ workspaceCreationPropertyValues,
17834
17906
  canEdit,
17835
17907
  selectedIdSet,
17836
17908
  wrapCells,
@@ -17853,6 +17925,7 @@ function DatabaseGroupedTableSection({
17853
17925
  columnWidths: Record<string, number>;
17854
17926
  databaseDocumentId: string;
17855
17927
  workspaceCatalog: boolean;
17928
+ workspaceCreationPropertyValues?: Record<string, DocumentPropertyValue>;
17856
17929
  canEdit: boolean;
17857
17930
  selectedIdSet: Set<string>;
17858
17931
  wrapCells: boolean;
@@ -17918,15 +17991,36 @@ function DatabaseGroupedTableSection({
17918
17991
  />
17919
17992
  ))}
17920
17993
  {canEdit ? (
17921
- <NewDatabaseRow
17922
- label={newRowLabel}
17923
- properties={properties}
17924
- columnWidths={columnWidths}
17925
- rowDensity={rowDensity}
17926
- disabled={isCreating}
17927
- isPending={isCreating}
17928
- onCreate={(title) => onCreateRow(group, title)}
17929
- />
17994
+ workspaceCatalog ? (
17995
+ <WorkspaceSourceMenuRow
17996
+ label={newRowLabel}
17997
+ properties={properties}
17998
+ columnWidths={columnWidths}
17999
+ rowDensity={rowDensity}
18000
+ propertyValues={{
18001
+ ...workspaceCreationPropertyValues,
18002
+ ...(group.property && group.value !== BOARD_UNGROUPED_VALUE
18003
+ ? {
18004
+ [group.property.definition.id]:
18005
+ boardGroupValueForProperty(
18006
+ group.property,
18007
+ group.value,
18008
+ ),
18009
+ }
18010
+ : {}),
18011
+ }}
18012
+ />
18013
+ ) : (
18014
+ <NewDatabaseRow
18015
+ label={newRowLabel}
18016
+ properties={properties}
18017
+ columnWidths={columnWidths}
18018
+ rowDensity={rowDensity}
18019
+ disabled={isCreating}
18020
+ isPending={isCreating}
18021
+ onCreate={(title) => onCreateRow(group, title)}
18022
+ />
18023
+ )
17930
18024
  ) : null}
17931
18025
  </>
17932
18026
  ) : null}
@@ -26,6 +26,7 @@ export function DatabaseGalleryView({
26
26
  items,
27
27
  databaseDocumentId,
28
28
  canEdit,
29
+ canCreateItems,
29
30
  isLoading,
30
31
  isCreating,
31
32
  activeFilters,
@@ -47,6 +48,7 @@ export function DatabaseGalleryView({
47
48
  items: ContentDatabaseItem[];
48
49
  databaseDocumentId: string;
49
50
  canEdit: boolean;
51
+ canCreateItems: boolean;
50
52
  isLoading: boolean;
51
53
  isCreating: boolean;
52
54
  activeFilters: DatabaseFilter[];
@@ -106,6 +108,7 @@ export function DatabaseGalleryView({
106
108
  properties={properties}
107
109
  databaseDocumentId={databaseDocumentId}
108
110
  canEdit={canEdit}
111
+ canCreateItems={canCreateItems}
109
112
  isCreating={isCreating}
110
113
  collapsed={databaseGroupIsCollapsed(
111
114
  collapsedGroupIds,
@@ -139,7 +142,7 @@ export function DatabaseGalleryView({
139
142
  onOpenPage={() => onOpenPage(item)}
140
143
  />
141
144
  ))}
142
- {canEdit && !grouped ? (
145
+ {canEdit && canCreateItems && !grouped ? (
143
146
  <NewGalleryCard
144
147
  disabled={isCreating}
145
148
  isPending={isCreating}
@@ -157,6 +160,7 @@ function DatabaseGroupedGallerySection({
157
160
  properties,
158
161
  databaseDocumentId,
159
162
  canEdit,
163
+ canCreateItems,
160
164
  isCreating,
161
165
  collapsed,
162
166
  onCreateRow,
@@ -169,6 +173,7 @@ function DatabaseGroupedGallerySection({
169
173
  properties: DocumentProperty[];
170
174
  databaseDocumentId: string;
171
175
  canEdit: boolean;
176
+ canCreateItems: boolean;
172
177
  isCreating: boolean;
173
178
  collapsed: boolean;
174
179
  onCreateRow: (
@@ -206,7 +211,7 @@ function DatabaseGroupedGallerySection({
206
211
  onOpenPage={() => onOpenPage(item)}
207
212
  />
208
213
  ))}
209
- {canEdit ? (
214
+ {canEdit && canCreateItems ? (
210
215
  <NewGalleryCard
211
216
  disabled={isCreating}
212
217
  isPending={isCreating}
@@ -26,6 +26,7 @@ export function DatabaseListView({
26
26
  items,
27
27
  databaseDocumentId,
28
28
  canEdit,
29
+ canCreateItems,
29
30
  isLoading,
30
31
  isCreating,
31
32
  activeFilters,
@@ -47,6 +48,7 @@ export function DatabaseListView({
47
48
  items: ContentDatabaseItem[];
48
49
  databaseDocumentId: string;
49
50
  canEdit: boolean;
51
+ canCreateItems: boolean;
50
52
  isLoading: boolean;
51
53
  isCreating: boolean;
52
54
  activeFilters: DatabaseFilter[];
@@ -103,6 +105,7 @@ export function DatabaseListView({
103
105
  properties={properties}
104
106
  databaseDocumentId={databaseDocumentId}
105
107
  canEdit={canEdit}
108
+ canCreateItems={canCreateItems}
106
109
  isCreating={isCreating}
107
110
  collapsed={databaseGroupIsCollapsed(
108
111
  collapsedGroupIds,
@@ -136,7 +139,7 @@ export function DatabaseListView({
136
139
  onOpenPage={() => onOpenPage(item)}
137
140
  />
138
141
  ))}
139
- {canEdit && !grouped ? (
142
+ {canEdit && canCreateItems && !grouped ? (
140
143
  <NewListRow
141
144
  disabled={isCreating}
142
145
  isPending={isCreating}
@@ -154,6 +157,7 @@ function DatabaseGroupedListSection({
154
157
  properties,
155
158
  databaseDocumentId,
156
159
  canEdit,
160
+ canCreateItems,
157
161
  isCreating,
158
162
  collapsed,
159
163
  onCreateRow,
@@ -166,6 +170,7 @@ function DatabaseGroupedListSection({
166
170
  properties: DocumentProperty[];
167
171
  databaseDocumentId: string;
168
172
  canEdit: boolean;
173
+ canCreateItems: boolean;
169
174
  isCreating: boolean;
170
175
  collapsed: boolean;
171
176
  onCreateRow: (
@@ -203,7 +208,7 @@ function DatabaseGroupedListSection({
203
208
  onOpenPage={() => onOpenPage(item)}
204
209
  />
205
210
  ))}
206
- {canEdit ? (
211
+ {canEdit && canCreateItems ? (
207
212
  <NewListRow
208
213
  disabled={isCreating}
209
214
  isPending={isCreating}