@agent-native/core 0.114.0 → 0.114.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 +2 -2
- package/corpus/core/CHANGELOG.md +9 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/build-compatibility.ts +77 -0
- package/corpus/core/src/client/route-chunk-recovery/index.ts +1 -0
- package/corpus/core/src/client/use-action.ts +32 -1
- package/corpus/core/src/deploy/build.ts +4 -1
- package/corpus/core/src/org/context.ts +56 -30
- package/corpus/core/src/server/action-routes.ts +52 -2
- package/corpus/core/src/server/auth-plugin.ts +9 -4
- package/corpus/core/src/server/better-auth-instance.ts +5 -1
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/vite/client.ts +17 -0
- package/corpus/templates/content/AGENTS.md +2 -0
- package/corpus/templates/content/actions/_content-database-personal-view.ts +49 -5
- package/corpus/templates/content/actions/_content-document-access.ts +21 -0
- package/corpus/templates/content/actions/_content-favorites.ts +91 -0
- package/corpus/templates/content/actions/_content-files.ts +79 -23
- package/corpus/templates/content/actions/_content-sidebar-state.ts +24 -0
- package/corpus/templates/content/actions/_content-space-access.ts +15 -17
- package/corpus/templates/content/actions/_content-space-catalog-guards.ts +20 -0
- package/corpus/templates/content/actions/_content-spaces.ts +364 -167
- package/corpus/templates/content/actions/_database-source-utils.ts +8 -0
- package/corpus/templates/content/actions/_database-utils.ts +249 -15
- package/corpus/templates/content/actions/_delete-content-space.ts +84 -0
- package/corpus/templates/content/actions/_files-system-properties.ts +499 -0
- package/corpus/templates/content/actions/_local-file-documents.ts +0 -1
- package/corpus/templates/content/actions/_property-utils.ts +18 -9
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +3 -0
- package/corpus/templates/content/actions/configure-document-property.ts +3 -0
- package/corpus/templates/content/actions/create-content-database.ts +2 -2
- package/corpus/templates/content/actions/create-content-space.ts +34 -0
- package/corpus/templates/content/actions/create-document.ts +4 -1
- package/corpus/templates/content/actions/delete-content-space.ts +19 -0
- package/corpus/templates/content/actions/delete-database-items.ts +28 -1
- package/corpus/templates/content/actions/delete-document-property.ts +3 -0
- package/corpus/templates/content/actions/delete-document.ts +39 -2
- package/corpus/templates/content/actions/duplicate-database-item.ts +6 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +6 -0
- package/corpus/templates/content/actions/duplicate-document-property.ts +3 -0
- package/corpus/templates/content/actions/get-content-database.ts +11 -2
- package/corpus/templates/content/actions/get-content-sidebar-state.ts +23 -0
- package/corpus/templates/content/actions/get-document.ts +32 -7
- package/corpus/templates/content/actions/import-content-source.ts +33 -1
- package/corpus/templates/content/actions/list-content-spaces.ts +34 -2
- package/corpus/templates/content/actions/list-documents.ts +39 -7
- package/corpus/templates/content/actions/reorder-document-property.ts +9 -0
- package/corpus/templates/content/actions/set-document-property.ts +41 -23
- package/corpus/templates/content/actions/share-local-file-document.ts +15 -0
- package/corpus/templates/content/actions/submit-content-database-form.ts +7 -0
- package/corpus/templates/content/actions/sync-local-folder-source.ts +14 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +1 -0
- package/corpus/templates/content/actions/update-content-sidebar-state.ts +27 -0
- package/corpus/templates/content/actions/update-document.ts +158 -66
- package/corpus/templates/content/app/components/EmptyState.tsx +4 -57
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +519 -178
- package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +39 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +266 -7
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +430 -152
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +467 -66
- package/corpus/templates/content/app/components/editor/database/view-config.ts +9 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +720 -196
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +173 -1
- package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +1 -1
- package/corpus/templates/content/app/components/sidebar/select-content-space.ts +91 -16
- package/corpus/templates/content/app/entry.client.tsx +5 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +84 -3
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +60 -2
- package/corpus/templates/content/app/hooks/use-create-page.ts +30 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +270 -19
- package/corpus/templates/content/app/i18n-data.ts +243 -20
- package/corpus/templates/content/app/lib/local-folder-picker-safety.ts +54 -0
- package/corpus/templates/content/app/lib/local-folder-picker-support.ts +18 -0
- package/corpus/templates/content/app/routes/_app.favorites.tsx +30 -0
- package/corpus/templates/content/app/routes/_app.local-files.tsx +18 -6
- package/corpus/templates/content/changelog/2026-07-17-workspace-files-now-stay-in-a-loading-state-until-automatic-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspace-switching-now-opens-the-selected-files-database-pr.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspaces-now-expand-above-their-own-files-list-without-dup.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-create-named-workspaces-each-with-its-own-private-files-data.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-favorites-align-with-workspace-and-file-rows-in-the-sidebar.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-local-folder-selection-no-longer-invokes-the-unsafe-native-p.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-made-content-workspaces-independently-expandable-restored-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-page-details-now-live-in-a-shared-info-and-comments-rail-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-database-views-now-control-sidebar-workspace-navig.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-navigation-now-aligns-favorites-with-workspace-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-favorites-now-open-as-a-table-and-compact-breadcrumbs-make-w.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-files-databases-now-start-unfiltered-sidebar-rows-exactly-fo.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-sidebar-page-trees-now-open-only-when-expanded-remember-thei.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-file-databases-now-use-the-workspace-name-open-as-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-navigation-now-stays-stable-on-hover-uses-folder-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-rows-now-use-folder-icons-and-deleting-a-user-crea.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspaces-can-be-created-without-leaving-the-workspaces-dat.md +6 -0
- package/corpus/templates/content/e2e/global-setup.ts +3 -2
- package/corpus/templates/content/parity/matrix.md +28 -28
- package/corpus/templates/content/parity/matrix.ts +8 -2
- package/corpus/templates/content/server/db/index.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +10 -0
- package/corpus/templates/content/server/lib/documents.ts +12 -7
- package/corpus/templates/content/server/plugins/db.ts +17 -0
- package/corpus/templates/content/shared/api.ts +9 -0
- package/corpus/templates/content/shared/database-form.ts +11 -2
- package/corpus/templates/content/vite.config.ts +1 -0
- package/dist/client/build-compatibility.d.ts +11 -0
- package/dist/client/build-compatibility.d.ts.map +1 -0
- package/dist/client/build-compatibility.js +56 -0
- package/dist/client/build-compatibility.js.map +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery/index.js +1 -0
- package/dist/client/route-chunk-recovery/index.js.map +1 -1
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +19 -1
- package/dist/client/use-action.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/context.d.ts +4 -2
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +44 -22
- package/dist/org/context.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +32 -2
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth-plugin.d.ts.map +1 -1
- package/dist/server/auth-plugin.js +9 -5
- package/dist/server/auth-plugin.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +4 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/vite/client.d.ts +6 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +8 -0
- package/dist/vite/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/build-compatibility.ts +77 -0
- package/src/client/route-chunk-recovery/index.ts +1 -0
- package/src/client/use-action.ts +32 -1
- package/src/deploy/build.ts +4 -1
- package/src/org/context.ts +56 -30
- package/src/server/action-routes.ts +52 -2
- package/src/server/auth-plugin.ts +9 -4
- package/src/server/better-auth-instance.ts +5 -1
- package/src/shared/mcp-embed-headers.ts +1 -1
- package/src/vite/client.ts +17 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
verticalListSortingStrategy,
|
|
7
7
|
} from "@dnd-kit/sortable";
|
|
8
8
|
import { CSS } from "@dnd-kit/utilities";
|
|
9
|
-
import type { DocumentTreeNode } from "@shared/api";
|
|
9
|
+
import type { Document, DocumentTreeNode } from "@shared/api";
|
|
10
10
|
import {
|
|
11
11
|
IconChevronRight,
|
|
12
12
|
IconDatabase,
|
|
@@ -88,6 +88,178 @@ export function DocumentSidebarIcon({
|
|
|
88
88
|
return <IconFileText size={14} className="text-muted-foreground" />;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
export function FavoriteDocumentItem({
|
|
92
|
+
document,
|
|
93
|
+
active,
|
|
94
|
+
sidebarWidth,
|
|
95
|
+
onSelect,
|
|
96
|
+
onCreateChildPage,
|
|
97
|
+
onCreateChildDatabase,
|
|
98
|
+
onRemoveFavorite,
|
|
99
|
+
onDelete,
|
|
100
|
+
}: {
|
|
101
|
+
document: Document;
|
|
102
|
+
active: boolean;
|
|
103
|
+
sidebarWidth?: number;
|
|
104
|
+
onSelect: () => void;
|
|
105
|
+
onCreateChildPage: () => void;
|
|
106
|
+
onCreateChildDatabase: () => void;
|
|
107
|
+
onRemoveFavorite: () => void;
|
|
108
|
+
onDelete: () => void;
|
|
109
|
+
}) {
|
|
110
|
+
const t = useT();
|
|
111
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
112
|
+
const canEdit = document.canEdit !== false;
|
|
113
|
+
const canManage =
|
|
114
|
+
document.canManage === true ||
|
|
115
|
+
document.accessRole === "owner" ||
|
|
116
|
+
document.accessRole === "admin";
|
|
117
|
+
const canCreateChild = canEdit && document.source?.mode !== "local-files";
|
|
118
|
+
const title = document.title || t("sidebar.untitled");
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
className={cn(
|
|
123
|
+
"group relative flex min-w-0 cursor-pointer items-center gap-1.5 rounded-md py-[5px] pe-2 text-sm",
|
|
124
|
+
active
|
|
125
|
+
? "font-semibold text-foreground"
|
|
126
|
+
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
127
|
+
)}
|
|
128
|
+
style={{
|
|
129
|
+
paddingInlineStart: "26px",
|
|
130
|
+
width:
|
|
131
|
+
sidebarWidth === undefined
|
|
132
|
+
? undefined
|
|
133
|
+
: `${Math.max(0, sidebarWidth)}px`,
|
|
134
|
+
}}
|
|
135
|
+
aria-label={title}
|
|
136
|
+
>
|
|
137
|
+
<button
|
|
138
|
+
type="button"
|
|
139
|
+
className="absolute inset-0 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
140
|
+
aria-label={`Open ${title}`}
|
|
141
|
+
onClick={onSelect}
|
|
142
|
+
/>
|
|
143
|
+
<span className="pointer-events-none relative flex h-5 w-5 shrink-0 items-center justify-center text-center">
|
|
144
|
+
<DocumentSidebarIcon document={document} />
|
|
145
|
+
</span>
|
|
146
|
+
<span className="pointer-events-none relative min-w-0 flex-1 truncate pe-12">
|
|
147
|
+
{title}
|
|
148
|
+
</span>
|
|
149
|
+
<div
|
|
150
|
+
className={cn(
|
|
151
|
+
"pointer-events-none absolute right-1 top-1/2 z-10 flex -translate-y-1/2 items-center gap-0.5 rounded-md bg-accent px-0.5 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100",
|
|
152
|
+
active && "text-accent-foreground",
|
|
153
|
+
)}
|
|
154
|
+
onPointerDown={(event) => event.stopPropagation()}
|
|
155
|
+
onClick={(event) => event.stopPropagation()}
|
|
156
|
+
>
|
|
157
|
+
{(canEdit || canManage) && (
|
|
158
|
+
<DropdownMenu>
|
|
159
|
+
<DropdownMenuTrigger asChild>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
className="flex h-6 w-6 items-center justify-center rounded hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
163
|
+
aria-label={`More actions for ${title}`}
|
|
164
|
+
onClick={(event) => event.stopPropagation()}
|
|
165
|
+
>
|
|
166
|
+
<IconDots size={14} />
|
|
167
|
+
</button>
|
|
168
|
+
</DropdownMenuTrigger>
|
|
169
|
+
<DropdownMenuContent align="start" className="w-48">
|
|
170
|
+
{canEdit && (
|
|
171
|
+
<DropdownMenuItem
|
|
172
|
+
onClick={(event) => {
|
|
173
|
+
event.stopPropagation();
|
|
174
|
+
onRemoveFavorite();
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
<IconStar size={14} className="me-2 fill-current" />
|
|
178
|
+
{t("sidebar.removeFromFavorites")}
|
|
179
|
+
</DropdownMenuItem>
|
|
180
|
+
)}
|
|
181
|
+
{canEdit && canManage && <DropdownMenuSeparator />}
|
|
182
|
+
{canManage && (
|
|
183
|
+
<DropdownMenuItem
|
|
184
|
+
className="text-destructive"
|
|
185
|
+
onClick={(event) => {
|
|
186
|
+
event.stopPropagation();
|
|
187
|
+
setDeleteDialogOpen(true);
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
<IconTrash size={14} className="me-2" />
|
|
191
|
+
{t("database.delete")}
|
|
192
|
+
</DropdownMenuItem>
|
|
193
|
+
)}
|
|
194
|
+
</DropdownMenuContent>
|
|
195
|
+
</DropdownMenu>
|
|
196
|
+
)}
|
|
197
|
+
{canCreateChild && (
|
|
198
|
+
<DropdownMenu>
|
|
199
|
+
<Tooltip>
|
|
200
|
+
<TooltipTrigger asChild>
|
|
201
|
+
<DropdownMenuTrigger asChild>
|
|
202
|
+
<button
|
|
203
|
+
type="button"
|
|
204
|
+
className="flex h-7 w-7 items-center justify-center rounded hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
205
|
+
aria-label={t("sidebar.addChildTo", { title })}
|
|
206
|
+
onClick={(event) => event.stopPropagation()}
|
|
207
|
+
>
|
|
208
|
+
<IconPlus size={14} />
|
|
209
|
+
</button>
|
|
210
|
+
</DropdownMenuTrigger>
|
|
211
|
+
</TooltipTrigger>
|
|
212
|
+
<TooltipContent>{t("sidebar.addChild")}</TooltipContent>
|
|
213
|
+
</Tooltip>
|
|
214
|
+
<DropdownMenuContent align="start" className="w-44">
|
|
215
|
+
<DropdownMenuItem
|
|
216
|
+
onClick={(event) => {
|
|
217
|
+
event.stopPropagation();
|
|
218
|
+
onCreateChildPage();
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
<IconFileText className="me-2 size-4" />
|
|
222
|
+
{t("sidebar.page")}
|
|
223
|
+
</DropdownMenuItem>
|
|
224
|
+
<DropdownMenuItem
|
|
225
|
+
onClick={(event) => {
|
|
226
|
+
event.stopPropagation();
|
|
227
|
+
onCreateChildDatabase();
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
<IconDatabase className="me-2 size-4" />
|
|
231
|
+
{t("sidebar.database")}
|
|
232
|
+
</DropdownMenuItem>
|
|
233
|
+
</DropdownMenuContent>
|
|
234
|
+
</DropdownMenu>
|
|
235
|
+
)}
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
239
|
+
<AlertDialogContent>
|
|
240
|
+
<AlertDialogHeader>
|
|
241
|
+
<AlertDialogTitle>
|
|
242
|
+
{t("sidebar.deletePageQuestion")}
|
|
243
|
+
</AlertDialogTitle>
|
|
244
|
+
<AlertDialogDescription>
|
|
245
|
+
{t("sidebar.deletePageDescription", { title })}
|
|
246
|
+
</AlertDialogDescription>
|
|
247
|
+
</AlertDialogHeader>
|
|
248
|
+
<AlertDialogFooter>
|
|
249
|
+
<AlertDialogCancel>{t("comments.cancel")}</AlertDialogCancel>
|
|
250
|
+
<AlertDialogAction
|
|
251
|
+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
252
|
+
onClick={onDelete}
|
|
253
|
+
>
|
|
254
|
+
{t("database.delete")}
|
|
255
|
+
</AlertDialogAction>
|
|
256
|
+
</AlertDialogFooter>
|
|
257
|
+
</AlertDialogContent>
|
|
258
|
+
</AlertDialog>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
91
263
|
export function DocumentTreeItem({
|
|
92
264
|
node,
|
|
93
265
|
depth,
|
|
@@ -1,31 +1,106 @@
|
|
|
1
1
|
import type { ContentSpaceSummary } from "@/hooks/use-content-spaces";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export const SELECTED_CONTENT_SPACE_STORAGE_KEY = "content-selected-space";
|
|
4
|
+
|
|
5
|
+
export type ContentSpaceAvailability = "loading" | "ready" | "error";
|
|
6
|
+
|
|
7
|
+
export function contentSpaceAvailability(args: {
|
|
8
|
+
hasSelectedSpace: boolean;
|
|
9
|
+
contentSpacesLoading: boolean;
|
|
10
|
+
contentSpacesFetching: boolean;
|
|
11
|
+
contentSpacesError: boolean;
|
|
12
|
+
provisioningAttempted: boolean;
|
|
13
|
+
provisioningPending: boolean;
|
|
14
|
+
provisioningError: boolean;
|
|
15
|
+
}): ContentSpaceAvailability {
|
|
16
|
+
if (args.hasSelectedSpace) return "ready";
|
|
17
|
+
if (args.contentSpacesError || args.provisioningError) {
|
|
18
|
+
return "error";
|
|
19
|
+
}
|
|
20
|
+
if (
|
|
21
|
+
args.contentSpacesLoading ||
|
|
22
|
+
args.contentSpacesFetching ||
|
|
23
|
+
!args.provisioningAttempted ||
|
|
24
|
+
args.provisioningPending
|
|
25
|
+
) {
|
|
26
|
+
return "loading";
|
|
27
|
+
}
|
|
28
|
+
return "error";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function contentSpaceForStoredSelection(args: {
|
|
4
32
|
spaces: ContentSpaceSummary[];
|
|
5
33
|
storedSpaceId: string | null;
|
|
6
|
-
activeOrgId: string | null | undefined;
|
|
7
34
|
}) {
|
|
8
|
-
if (args.activeOrgId === undefined) return null;
|
|
9
35
|
const stored = args.spaces.find((space) => space.id === args.storedSpaceId);
|
|
10
|
-
if (stored
|
|
11
|
-
|
|
12
|
-
(space) => space.
|
|
36
|
+
if (stored) return stored;
|
|
37
|
+
return (
|
|
38
|
+
args.spaces.find((space) => space.kind === "personal") ??
|
|
39
|
+
args.spaces[0] ??
|
|
40
|
+
null
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function contentSpaceForCatalogItem(args: {
|
|
45
|
+
databaseId: string;
|
|
46
|
+
catalogDatabaseId: string | undefined;
|
|
47
|
+
documentId: string;
|
|
48
|
+
spaces: ContentSpaceSummary[];
|
|
49
|
+
}) {
|
|
50
|
+
if (args.databaseId !== args.catalogDatabaseId) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
args.spaces.find((space) => space.catalogDocumentId === args.documentId) ??
|
|
55
|
+
null
|
|
13
56
|
);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function toggleExpandedWorkspaceIds(
|
|
60
|
+
expandedIds: string[],
|
|
61
|
+
workspaceId: string,
|
|
62
|
+
) {
|
|
63
|
+
return expandedIds.includes(workspaceId)
|
|
64
|
+
? expandedIds.filter((id) => id !== workspaceId)
|
|
65
|
+
: [...expandedIds, workspaceId];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function ensureWorkspaceExpanded(
|
|
69
|
+
expandedIds: string[],
|
|
70
|
+
workspaceId: string,
|
|
71
|
+
) {
|
|
72
|
+
return expandedIds.includes(workspaceId)
|
|
73
|
+
? expandedIds
|
|
74
|
+
: [...expandedIds, workspaceId];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function contentSpaceIdForCreate(args: {
|
|
78
|
+
parentId?: string;
|
|
79
|
+
selectedSpace: ContentSpaceSummary | null;
|
|
80
|
+
}) {
|
|
81
|
+
if (args.parentId) return undefined;
|
|
82
|
+
if (!args.selectedSpace) {
|
|
83
|
+
throw new Error("Files are still loading. Try creating the page again.");
|
|
84
|
+
}
|
|
85
|
+
return args.selectedSpace.id;
|
|
19
86
|
}
|
|
20
87
|
|
|
21
88
|
export async function selectContentSpace(args: {
|
|
22
89
|
space: ContentSpaceSummary;
|
|
23
|
-
|
|
24
|
-
switchOrg: (orgId: string | null) => Promise<unknown>;
|
|
90
|
+
syncApplicationState: (space: ContentSpaceSummary) => Promise<unknown>;
|
|
25
91
|
persistSelection: (spaceId: string) => void;
|
|
92
|
+
openFiles: (documentId: string) => void;
|
|
26
93
|
}) {
|
|
27
|
-
|
|
28
|
-
await args.switchOrg(args.space.orgId);
|
|
29
|
-
}
|
|
94
|
+
await args.syncApplicationState(args.space);
|
|
30
95
|
args.persistSelection(args.space.id);
|
|
96
|
+
args.openFiles(args.space.filesDocumentId);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function createContentSpaceSelectionQueue() {
|
|
100
|
+
let pending = Promise.resolve();
|
|
101
|
+
return (selection: () => Promise<void>) => {
|
|
102
|
+
const next = pending.catch(() => undefined).then(selection);
|
|
103
|
+
pending = next;
|
|
104
|
+
return next;
|
|
105
|
+
};
|
|
31
106
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { appBasePath } from "@agent-native/core/client/api-path";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
installRouteChunkRecovery,
|
|
4
|
+
stripBuildCompatibilityCacheBuster,
|
|
5
|
+
} from "@agent-native/core/client/route-chunk-recovery";
|
|
3
6
|
import { hydrateRoot } from "react-dom/client";
|
|
4
7
|
import { HydratedRouter } from "react-router/dom";
|
|
5
8
|
|
|
@@ -20,3 +23,4 @@ if (context) {
|
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
hydrateRoot(document, <HydratedRouter />);
|
|
26
|
+
stripBuildCompatibilityCacheBuster();
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
CancelPreparedBuilderSourceUpdateResponse,
|
|
12
12
|
ChangeContentDatabaseSourceRoleRequest,
|
|
13
13
|
ContentDatabaseResponse,
|
|
14
|
+
ContentDatabaseItem,
|
|
14
15
|
ContentDatabasePersonalViewResponse,
|
|
15
16
|
ContentDatabaseSourceFieldMapping,
|
|
16
17
|
CreateInlineDatabaseRequest,
|
|
@@ -59,6 +60,77 @@ export function contentDatabaseByIdQueryKey(databaseId: string) {
|
|
|
59
60
|
return ["action", "get-content-database", { databaseId }] as const;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
export function applyOptimisticItemToContentDatabase(
|
|
64
|
+
current: ContentDatabaseResponse | undefined,
|
|
65
|
+
item: ContentDatabaseItem,
|
|
66
|
+
): ContentDatabaseResponse | undefined {
|
|
67
|
+
if (!current) return current;
|
|
68
|
+
if (
|
|
69
|
+
current.items.some(
|
|
70
|
+
(candidate) =>
|
|
71
|
+
candidate.id === item.id || candidate.document.id === item.document.id,
|
|
72
|
+
)
|
|
73
|
+
) {
|
|
74
|
+
return current;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
...current,
|
|
79
|
+
items: [...current.items, item],
|
|
80
|
+
pagination: current.pagination
|
|
81
|
+
? {
|
|
82
|
+
...current.pagination,
|
|
83
|
+
totalItems: current.pagination.totalItems + 1,
|
|
84
|
+
returnedItems: current.pagination.returnedItems + 1,
|
|
85
|
+
}
|
|
86
|
+
: current.pagination,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function removeOptimisticItemFromContentDatabase(
|
|
91
|
+
current: ContentDatabaseResponse | undefined,
|
|
92
|
+
documentId: string,
|
|
93
|
+
): ContentDatabaseResponse | undefined {
|
|
94
|
+
if (!current) return current;
|
|
95
|
+
const items = current.items.filter(
|
|
96
|
+
(candidate) => candidate.document.id !== documentId,
|
|
97
|
+
);
|
|
98
|
+
if (items.length === current.items.length) return current;
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
...current,
|
|
102
|
+
items,
|
|
103
|
+
pagination: current.pagination
|
|
104
|
+
? {
|
|
105
|
+
...current.pagination,
|
|
106
|
+
totalItems: Math.max(0, current.pagination.totalItems - 1),
|
|
107
|
+
returnedItems: Math.max(0, current.pagination.returnedItems - 1),
|
|
108
|
+
}
|
|
109
|
+
: current.pagination,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function preserveScopedDatabasePlaceholder<T>(
|
|
114
|
+
previous: T | undefined,
|
|
115
|
+
previousQuery: Pick<Query, "queryKey"> | undefined,
|
|
116
|
+
scope: { documentId?: string; databaseId?: string },
|
|
117
|
+
): T | undefined {
|
|
118
|
+
const previousParams = previousQuery?.queryKey[2];
|
|
119
|
+
if (!previousParams || typeof previousParams !== "object") return undefined;
|
|
120
|
+
|
|
121
|
+
const params = previousParams as {
|
|
122
|
+
documentId?: unknown;
|
|
123
|
+
databaseId?: unknown;
|
|
124
|
+
};
|
|
125
|
+
if (scope.documentId !== undefined) {
|
|
126
|
+
return params.documentId === scope.documentId ? previous : undefined;
|
|
127
|
+
}
|
|
128
|
+
if (scope.databaseId !== undefined) {
|
|
129
|
+
return params.databaseId === scope.databaseId ? previous : undefined;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
62
134
|
function isContentDatabaseQueryForDocument(
|
|
63
135
|
queryKey: readonly unknown[],
|
|
64
136
|
documentId: string,
|
|
@@ -449,7 +521,10 @@ export function useContentDatabase(documentId: string | null, limit?: number) {
|
|
|
449
521
|
{
|
|
450
522
|
enabled: !!documentId,
|
|
451
523
|
retry: false,
|
|
452
|
-
placeholderData: (previous) =>
|
|
524
|
+
placeholderData: (previous, previousQuery) =>
|
|
525
|
+
preserveScopedDatabasePlaceholder(previous, previousQuery, {
|
|
526
|
+
documentId: documentId ?? undefined,
|
|
527
|
+
}),
|
|
453
528
|
initialData: () =>
|
|
454
529
|
documentId
|
|
455
530
|
? readCachedContentDatabaseResponse(queryClient, documentId)
|
|
@@ -468,7 +543,10 @@ export function useContentDatabaseById(databaseId: string | null) {
|
|
|
468
543
|
{
|
|
469
544
|
enabled: !!databaseId,
|
|
470
545
|
retry: false,
|
|
471
|
-
placeholderData: (previous) =>
|
|
546
|
+
placeholderData: (previous, previousQuery) =>
|
|
547
|
+
preserveScopedDatabasePlaceholder(previous, previousQuery, {
|
|
548
|
+
databaseId: databaseId ?? undefined,
|
|
549
|
+
}),
|
|
472
550
|
},
|
|
473
551
|
);
|
|
474
552
|
}
|
|
@@ -719,7 +797,10 @@ export function useContentDatabasePersonalView(databaseId: string | null) {
|
|
|
719
797
|
{
|
|
720
798
|
enabled: !!databaseId,
|
|
721
799
|
retry: false,
|
|
722
|
-
placeholderData: (previous) =>
|
|
800
|
+
placeholderData: (previous, previousQuery) =>
|
|
801
|
+
preserveScopedDatabasePlaceholder(previous, previousQuery, {
|
|
802
|
+
databaseId: databaseId ?? undefined,
|
|
803
|
+
}),
|
|
723
804
|
},
|
|
724
805
|
);
|
|
725
806
|
}
|
|
@@ -9,6 +9,7 @@ export type ContentSpaceSummary = {
|
|
|
9
9
|
name: string;
|
|
10
10
|
kind: string;
|
|
11
11
|
filesDatabaseId: string;
|
|
12
|
+
filesDocumentId: string;
|
|
12
13
|
orgId: string | null;
|
|
13
14
|
role: "owner" | "editor" | "viewer";
|
|
14
15
|
catalogItemId: string;
|
|
@@ -17,6 +18,9 @@ export type ContentSpaceSummary = {
|
|
|
17
18
|
|
|
18
19
|
export type ListContentSpacesResponse = {
|
|
19
20
|
catalogDatabaseId: string;
|
|
21
|
+
catalogDocumentId: string;
|
|
22
|
+
favoritesDatabaseId: string | null;
|
|
23
|
+
favoritesDocumentId: string | null;
|
|
20
24
|
spaces: ContentSpaceSummary[];
|
|
21
25
|
};
|
|
22
26
|
|
|
@@ -33,10 +37,64 @@ export function useContentSpaces() {
|
|
|
33
37
|
export function useEnsureContentSpaces() {
|
|
34
38
|
const queryClient = useQueryClient();
|
|
35
39
|
return useActionMutation("ensure-content-spaces", {
|
|
36
|
-
onSuccess: () => {
|
|
37
|
-
queryClient.
|
|
40
|
+
onSuccess: async () => {
|
|
41
|
+
await queryClient.refetchQueries({
|
|
38
42
|
queryKey: ["action", "list-content-spaces"],
|
|
39
43
|
});
|
|
40
44
|
},
|
|
41
45
|
});
|
|
42
46
|
}
|
|
47
|
+
|
|
48
|
+
export function useCreateContentSpace() {
|
|
49
|
+
const queryClient = useQueryClient();
|
|
50
|
+
return useActionMutation<
|
|
51
|
+
{
|
|
52
|
+
spaceId: string;
|
|
53
|
+
filesDatabaseId: string;
|
|
54
|
+
filesDocumentId: string;
|
|
55
|
+
catalogDatabaseId: string;
|
|
56
|
+
catalogItemId: string;
|
|
57
|
+
catalogDocumentId: string;
|
|
58
|
+
name: string;
|
|
59
|
+
kind: "user";
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: string;
|
|
63
|
+
requestId: string;
|
|
64
|
+
propertyValues?: Record<string, unknown>;
|
|
65
|
+
}
|
|
66
|
+
>("create-content-space", {
|
|
67
|
+
onSuccess: async () => {
|
|
68
|
+
await Promise.all([
|
|
69
|
+
queryClient.refetchQueries({
|
|
70
|
+
queryKey: ["action", "list-content-spaces"],
|
|
71
|
+
}),
|
|
72
|
+
queryClient.refetchQueries({
|
|
73
|
+
queryKey: ["action", "get-content-database"],
|
|
74
|
+
}),
|
|
75
|
+
]);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function useDeleteContentSpace() {
|
|
81
|
+
const queryClient = useQueryClient();
|
|
82
|
+
return useActionMutation<
|
|
83
|
+
{ success: boolean; spaceId: string; deletedDocuments: number },
|
|
84
|
+
{ spaceId: string }
|
|
85
|
+
>("delete-content-space", {
|
|
86
|
+
onSuccess: async () => {
|
|
87
|
+
await Promise.all([
|
|
88
|
+
queryClient.refetchQueries({
|
|
89
|
+
queryKey: ["action", "list-content-spaces"],
|
|
90
|
+
}),
|
|
91
|
+
queryClient.refetchQueries({
|
|
92
|
+
queryKey: ["action", "get-content-database"],
|
|
93
|
+
}),
|
|
94
|
+
queryClient.refetchQueries({
|
|
95
|
+
queryKey: ["action", "list-documents"],
|
|
96
|
+
}),
|
|
97
|
+
]);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -4,7 +4,14 @@ import { useCallback } from "react";
|
|
|
4
4
|
import { useNavigate } from "react-router";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
6
|
|
|
7
|
+
import {
|
|
8
|
+
contentSpaceForStoredSelection,
|
|
9
|
+
contentSpaceIdForCreate,
|
|
10
|
+
SELECTED_CONTENT_SPACE_STORAGE_KEY,
|
|
11
|
+
} from "@/components/sidebar/select-content-space";
|
|
12
|
+
import { useContentSpaces } from "@/hooks/use-content-spaces";
|
|
7
13
|
import { useCreateDocument } from "@/hooks/use-documents";
|
|
14
|
+
import { useLocalStorage } from "@/hooks/use-local-storage";
|
|
8
15
|
|
|
9
16
|
const LIST_DOCUMENTS_QUERY_KEY = [
|
|
10
17
|
"action",
|
|
@@ -27,12 +34,33 @@ export function useCreatePage(opts?: {
|
|
|
27
34
|
const navigate = useNavigate();
|
|
28
35
|
const queryClient = useQueryClient();
|
|
29
36
|
const createDocument = useCreateDocument();
|
|
37
|
+
const contentSpacesQuery = useContentSpaces();
|
|
38
|
+
const [storedSpaceId] = useLocalStorage<string | null>(
|
|
39
|
+
SELECTED_CONTENT_SPACE_STORAGE_KEY,
|
|
40
|
+
null,
|
|
41
|
+
);
|
|
42
|
+
const selectedSpace = contentSpaceForStoredSelection({
|
|
43
|
+
spaces: contentSpacesQuery.data?.spaces ?? [],
|
|
44
|
+
storedSpaceId,
|
|
45
|
+
});
|
|
30
46
|
const onAfterNavigate = opts?.onAfterNavigate;
|
|
31
47
|
const shouldNavigate = opts?.navigate ?? true;
|
|
32
48
|
const shouldAwaitPersist = opts?.awaitPersist ?? true;
|
|
33
49
|
|
|
34
50
|
return useCallback(
|
|
35
51
|
async (parentId?: string) => {
|
|
52
|
+
let spaceId: string | undefined;
|
|
53
|
+
try {
|
|
54
|
+
spaceId = contentSpaceIdForCreate({
|
|
55
|
+
parentId,
|
|
56
|
+
selectedSpace,
|
|
57
|
+
});
|
|
58
|
+
} catch (error) {
|
|
59
|
+
toast.error(
|
|
60
|
+
error instanceof Error ? error.message : "Files are still loading",
|
|
61
|
+
);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
36
64
|
const id = nanoid();
|
|
37
65
|
const now = new Date().toISOString();
|
|
38
66
|
const tempDoc: Document = {
|
|
@@ -66,6 +94,7 @@ export function useCreatePage(opts?: {
|
|
|
66
94
|
id,
|
|
67
95
|
title: "",
|
|
68
96
|
parentId: parentId ?? undefined,
|
|
97
|
+
spaceId,
|
|
69
98
|
});
|
|
70
99
|
// Replace optimistic doc with real server doc + clear any 404 error
|
|
71
100
|
// state from the in-flight fetch that ran before create completed.
|
|
@@ -109,6 +138,7 @@ export function useCreatePage(opts?: {
|
|
|
109
138
|
navigate,
|
|
110
139
|
onAfterNavigate,
|
|
111
140
|
queryClient,
|
|
141
|
+
selectedSpace,
|
|
112
142
|
shouldAwaitPersist,
|
|
113
143
|
shouldNavigate,
|
|
114
144
|
],
|