@agent-native/core 0.114.0 → 0.114.2
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 +15 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/create.ts +23 -0
- package/corpus/core/src/cli/skills.ts +24 -0
- 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/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/default/AGENTS.md +4 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/headless/AGENTS.md +5 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -1
- package/corpus/core/src/vite/client.ts +17 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/analytics/AGENTS.md +5 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/assets/AGENTS.md +5 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/brain/AGENTS.md +5 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/chat/AGENTS.md +4 -1
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/clips/AGENTS.md +5 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/content/AGENTS.md +7 -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/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/forms/AGENTS.md +5 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/macros/AGENTS.md +5 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/mail/AGENTS.md +5 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/plan/AGENTS.md +5 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/slides/AGENTS.md +5 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/tasks/AGENTS.md +5 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +21 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +19 -0
- package/dist/cli/skills.js.map +1 -1
- 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/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- 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/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/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/chat/AGENTS.md +4 -1
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/default/AGENTS.md +4 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/headless/AGENTS.md +5 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -1
- package/dist/templates/workspace-root/AGENTS.md +3 -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/cli/create.ts +23 -0
- package/src/cli/skills.ts +24 -0
- 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/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/chat/AGENTS.md +4 -1
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/default/AGENTS.md +4 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/headless/AGENTS.md +5 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/src/templates/workspace-core/AGENTS.md +3 -1
- package/src/templates/workspace-root/AGENTS.md +3 -1
- package/src/vite/client.ts +17 -0
|
@@ -8,13 +8,9 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
setClientAppState,
|
|
10
10
|
useActionMutation,
|
|
11
|
+
useActionQuery,
|
|
11
12
|
} from "@agent-native/core/client/hooks";
|
|
12
13
|
import { useT } from "@agent-native/core/client/i18n";
|
|
13
|
-
import {
|
|
14
|
-
OrgSwitcher,
|
|
15
|
-
useOrg,
|
|
16
|
-
useSwitchOrg,
|
|
17
|
-
} from "@agent-native/core/client/org";
|
|
18
14
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
19
15
|
import {
|
|
20
16
|
closestCenter,
|
|
@@ -31,20 +27,25 @@ import {
|
|
|
31
27
|
sortableKeyboardCoordinates,
|
|
32
28
|
verticalListSortingStrategy,
|
|
33
29
|
} from "@dnd-kit/sortable";
|
|
34
|
-
import type {
|
|
30
|
+
import type {
|
|
31
|
+
ContentDatabaseItem,
|
|
32
|
+
ContentDatabaseResponse,
|
|
33
|
+
Document,
|
|
34
|
+
DocumentTreeNode,
|
|
35
|
+
} from "@shared/api";
|
|
36
|
+
import { CONTENT_DATABASE_PERSONAL_VIEW_OVERRIDES_VERSION } from "@shared/api";
|
|
35
37
|
import {
|
|
36
|
-
IconDatabase,
|
|
37
38
|
IconBrain,
|
|
38
|
-
|
|
39
|
+
IconFolder,
|
|
40
|
+
IconFolderOpen,
|
|
39
41
|
IconPlus,
|
|
40
42
|
IconRestore,
|
|
41
43
|
IconSearch,
|
|
42
|
-
IconStar,
|
|
43
44
|
IconSettings,
|
|
44
45
|
IconTrashX,
|
|
45
46
|
IconLayoutSidebarLeftCollapse,
|
|
46
47
|
IconLayoutSidebarLeftExpand,
|
|
47
|
-
|
|
48
|
+
IconChevronDown,
|
|
48
49
|
IconChevronRight,
|
|
49
50
|
IconDots,
|
|
50
51
|
IconTrash,
|
|
@@ -75,6 +76,14 @@ import {
|
|
|
75
76
|
AlertDialogTitle,
|
|
76
77
|
AlertDialogTrigger,
|
|
77
78
|
} from "@/components/ui/alert-dialog";
|
|
79
|
+
import {
|
|
80
|
+
Dialog,
|
|
81
|
+
DialogContent,
|
|
82
|
+
DialogDescription,
|
|
83
|
+
DialogFooter,
|
|
84
|
+
DialogHeader,
|
|
85
|
+
DialogTitle,
|
|
86
|
+
} from "@/components/ui/dialog";
|
|
78
87
|
import {
|
|
79
88
|
DropdownMenu,
|
|
80
89
|
DropdownMenuContent,
|
|
@@ -82,6 +91,7 @@ import {
|
|
|
82
91
|
DropdownMenuSeparator,
|
|
83
92
|
DropdownMenuTrigger,
|
|
84
93
|
} from "@/components/ui/dropdown-menu";
|
|
94
|
+
import { Input } from "@/components/ui/input";
|
|
85
95
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
86
96
|
import {
|
|
87
97
|
Tooltip,
|
|
@@ -89,6 +99,9 @@ import {
|
|
|
89
99
|
TooltipTrigger,
|
|
90
100
|
} from "@/components/ui/tooltip";
|
|
91
101
|
import {
|
|
102
|
+
applyOptimisticItemToContentDatabase,
|
|
103
|
+
contentDatabaseByIdQueryKey,
|
|
104
|
+
removeOptimisticItemFromContentDatabase,
|
|
92
105
|
useContentDatabaseById,
|
|
93
106
|
useContentDatabasePersonalView,
|
|
94
107
|
useUpdateContentDatabasePersonalView,
|
|
@@ -98,8 +111,10 @@ import {
|
|
|
98
111
|
useTrashedContentDatabases,
|
|
99
112
|
} from "@/hooks/use-content-database";
|
|
100
113
|
import {
|
|
114
|
+
useCreateContentSpace,
|
|
101
115
|
useContentSpaces,
|
|
102
116
|
useEnsureContentSpaces,
|
|
117
|
+
type ContentSpaceSummary,
|
|
103
118
|
} from "@/hooks/use-content-spaces";
|
|
104
119
|
import {
|
|
105
120
|
useDocuments,
|
|
@@ -117,11 +132,20 @@ import {
|
|
|
117
132
|
getDocumentSidebarSections,
|
|
118
133
|
isDirectLocalDocument,
|
|
119
134
|
} from "./document-sidebar-sections";
|
|
120
|
-
import {
|
|
135
|
+
import {
|
|
136
|
+
DocumentSidebarIcon,
|
|
137
|
+
DocumentTreeItem,
|
|
138
|
+
FavoriteDocumentItem,
|
|
139
|
+
} from "./DocumentTreeItem";
|
|
121
140
|
import { NotionButton } from "./NotionButton";
|
|
122
141
|
import {
|
|
123
|
-
|
|
142
|
+
contentSpaceAvailability,
|
|
143
|
+
contentSpaceForStoredSelection,
|
|
144
|
+
createContentSpaceSelectionQueue,
|
|
145
|
+
ensureWorkspaceExpanded,
|
|
146
|
+
SELECTED_CONTENT_SPACE_STORAGE_KEY,
|
|
124
147
|
selectContentSpace,
|
|
148
|
+
toggleExpandedWorkspaceIds,
|
|
125
149
|
} from "./select-content-space";
|
|
126
150
|
|
|
127
151
|
function nanoid(size = 12): string {
|
|
@@ -177,6 +201,7 @@ function collectDocumentSubtreeIds(documents: Document[], rootId: string) {
|
|
|
177
201
|
}
|
|
178
202
|
|
|
179
203
|
type SidebarSectionId =
|
|
204
|
+
| "favorites"
|
|
180
205
|
| "local-files"
|
|
181
206
|
| "shared-copies"
|
|
182
207
|
| "private"
|
|
@@ -187,9 +212,9 @@ type CollapsedSectionsState = Record<SidebarSectionId, boolean>;
|
|
|
187
212
|
|
|
188
213
|
const SIDEBAR_SECTION_COLLAPSE_STORAGE_KEY =
|
|
189
214
|
"content-sidebar-collapsed-sections";
|
|
190
|
-
const
|
|
191
|
-
|
|
215
|
+
const CONTENT_SIDEBAR_STATE_VERSION = 1 as const;
|
|
192
216
|
const DEFAULT_COLLAPSED_SECTIONS: CollapsedSectionsState = {
|
|
217
|
+
favorites: false,
|
|
193
218
|
"local-files": false,
|
|
194
219
|
"shared-copies": false,
|
|
195
220
|
private: false,
|
|
@@ -201,6 +226,7 @@ function normalizeCollapsedSections(
|
|
|
201
226
|
value: Partial<Record<SidebarSectionId, boolean>> | null | undefined,
|
|
202
227
|
): CollapsedSectionsState {
|
|
203
228
|
return {
|
|
229
|
+
favorites: value?.favorites ?? false,
|
|
204
230
|
"local-files": value?.["local-files"] ?? false,
|
|
205
231
|
"shared-copies": value?.["shared-copies"] ?? false,
|
|
206
232
|
private: value?.private ?? false,
|
|
@@ -214,6 +240,99 @@ interface RemoveLocalFileSourceResult {
|
|
|
214
240
|
deleted: number;
|
|
215
241
|
}
|
|
216
242
|
|
|
243
|
+
function WorkspaceFilesSection({
|
|
244
|
+
space,
|
|
245
|
+
selected,
|
|
246
|
+
activeDocumentId,
|
|
247
|
+
expandedDocumentIds,
|
|
248
|
+
onDocumentExpandedChange,
|
|
249
|
+
onActivate,
|
|
250
|
+
onCreateChildPage,
|
|
251
|
+
onCreateChildDatabase,
|
|
252
|
+
onDeleteItem,
|
|
253
|
+
onToggleFavorite,
|
|
254
|
+
}: {
|
|
255
|
+
space: ContentSpaceSummary;
|
|
256
|
+
selected: boolean;
|
|
257
|
+
activeDocumentId: string | null;
|
|
258
|
+
expandedDocumentIds: ReadonlySet<string>;
|
|
259
|
+
onDocumentExpandedChange: (documentId: string, expanded: boolean) => void;
|
|
260
|
+
onActivate: (space: ContentSpaceSummary, documentId?: string) => void;
|
|
261
|
+
onCreateChildPage: (
|
|
262
|
+
space: ContentSpaceSummary,
|
|
263
|
+
item: ContentDatabaseItem,
|
|
264
|
+
) => void;
|
|
265
|
+
onCreateChildDatabase: (
|
|
266
|
+
space: ContentSpaceSummary,
|
|
267
|
+
item: ContentDatabaseItem,
|
|
268
|
+
) => void;
|
|
269
|
+
onDeleteItem: (item: ContentDatabaseItem) => void;
|
|
270
|
+
onToggleFavorite: (item: ContentDatabaseItem) => void;
|
|
271
|
+
}) {
|
|
272
|
+
const t = useT();
|
|
273
|
+
const filesDatabase = useContentDatabaseById(space.filesDatabaseId);
|
|
274
|
+
const filesPersonalView = useContentDatabasePersonalView(
|
|
275
|
+
space.filesDatabaseId,
|
|
276
|
+
);
|
|
277
|
+
const updateFilesPersonalView = useUpdateContentDatabasePersonalView(
|
|
278
|
+
space.filesDatabaseId,
|
|
279
|
+
);
|
|
280
|
+
const failed = filesDatabase.isError || filesPersonalView.isError;
|
|
281
|
+
|
|
282
|
+
return (
|
|
283
|
+
<div className="ms-3 border-s border-border/70 pb-1 ps-1">
|
|
284
|
+
{failed ? (
|
|
285
|
+
<QueryErrorState
|
|
286
|
+
compact
|
|
287
|
+
onRetry={() => {
|
|
288
|
+
void filesDatabase.refetch();
|
|
289
|
+
void filesPersonalView.refetch();
|
|
290
|
+
}}
|
|
291
|
+
retrying={filesDatabase.isFetching || filesPersonalView.isFetching}
|
|
292
|
+
/>
|
|
293
|
+
) : (
|
|
294
|
+
<ContentFilesSidebarView
|
|
295
|
+
data={filesDatabase.data}
|
|
296
|
+
overrides={filesPersonalView.data?.overrides}
|
|
297
|
+
isLoading={filesDatabase.isLoading || filesPersonalView.isLoading}
|
|
298
|
+
activeDocumentId={activeDocumentId}
|
|
299
|
+
expandedDocumentIds={expandedDocumentIds}
|
|
300
|
+
onDocumentExpandedChange={onDocumentExpandedChange}
|
|
301
|
+
onSelectView={(viewId) => {
|
|
302
|
+
const current = filesPersonalView.data?.overrides;
|
|
303
|
+
updateFilesPersonalView.mutate({
|
|
304
|
+
databaseId: space.filesDatabaseId,
|
|
305
|
+
overrides: {
|
|
306
|
+
version:
|
|
307
|
+
current?.version ??
|
|
308
|
+
CONTENT_DATABASE_PERSONAL_VIEW_OVERRIDES_VERSION,
|
|
309
|
+
activeViewId: viewId,
|
|
310
|
+
views: current?.views ?? [],
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
}}
|
|
314
|
+
onOpenItem={(item: ContentDatabaseItem) => {
|
|
315
|
+
if (selected) return false;
|
|
316
|
+
onActivate(space, item.document.id);
|
|
317
|
+
return true;
|
|
318
|
+
}}
|
|
319
|
+
onCreateChildPage={(item) => onCreateChildPage(space, item)}
|
|
320
|
+
onCreateChildDatabase={(item) => onCreateChildDatabase(space, item)}
|
|
321
|
+
onDeleteItem={onDeleteItem}
|
|
322
|
+
onToggleFavorite={onToggleFavorite}
|
|
323
|
+
labels={{
|
|
324
|
+
loadingLabel: t("sidebar.loadingFiles"),
|
|
325
|
+
noMatchesLabel: t("database.noRowsMatchThisView"),
|
|
326
|
+
clearLabel: t("database.clearSearchAndFilters"),
|
|
327
|
+
navigationLabel: `${space.name} ${t("sidebar.files")}`,
|
|
328
|
+
untitledLabel: t("sidebar.untitled"),
|
|
329
|
+
}}
|
|
330
|
+
/>
|
|
331
|
+
)}
|
|
332
|
+
</div>
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
217
336
|
export function DocumentSidebar({
|
|
218
337
|
activeDocumentId,
|
|
219
338
|
collapsed,
|
|
@@ -238,10 +357,22 @@ export function DocumentSidebar({
|
|
|
238
357
|
const { isCodeMode } = useCodeMode();
|
|
239
358
|
const updateDocument = useUpdateDocument();
|
|
240
359
|
const contentSpacesQuery = useContentSpaces();
|
|
360
|
+
const createContentSpace = useCreateContentSpace();
|
|
241
361
|
const ensureContentSpaces = useEnsureContentSpaces();
|
|
242
|
-
const
|
|
243
|
-
const switchOrg = useSwitchOrg();
|
|
362
|
+
const workspaceSelectionQueueRef = useRef(createContentSpaceSelectionQueue());
|
|
244
363
|
const contentSpaces = contentSpacesQuery.data?.spaces ?? [];
|
|
364
|
+
const workspaceCatalogDatabaseId =
|
|
365
|
+
contentSpacesQuery.data?.catalogDatabaseId ?? null;
|
|
366
|
+
const favoritesDocumentId =
|
|
367
|
+
contentSpacesQuery.data?.favoritesDocumentId ?? null;
|
|
368
|
+
const workspaceCatalogDatabase = useContentDatabaseById(
|
|
369
|
+
workspaceCatalogDatabaseId,
|
|
370
|
+
);
|
|
371
|
+
const workspaceCatalogPersonalView = useContentDatabasePersonalView(
|
|
372
|
+
workspaceCatalogDatabaseId,
|
|
373
|
+
);
|
|
374
|
+
const updateWorkspaceCatalogPersonalView =
|
|
375
|
+
useUpdateContentDatabasePersonalView(workspaceCatalogDatabaseId);
|
|
245
376
|
const spaceProvisionAttemptedRef = useRef(false);
|
|
246
377
|
useEffect(() => {
|
|
247
378
|
if (
|
|
@@ -261,31 +392,215 @@ export function DocumentSidebar({
|
|
|
261
392
|
SELECTED_CONTENT_SPACE_STORAGE_KEY,
|
|
262
393
|
null,
|
|
263
394
|
);
|
|
264
|
-
const selectedSpace =
|
|
395
|
+
const selectedSpace = contentSpaceForStoredSelection({
|
|
265
396
|
spaces: contentSpaces,
|
|
266
397
|
storedSpaceId,
|
|
267
|
-
activeOrgId: activeOrg?.orgId,
|
|
268
398
|
});
|
|
399
|
+
const sidebarStateQuery = useActionQuery("get-content-sidebar-state", {});
|
|
400
|
+
const updateSidebarState = useActionMutation("update-content-sidebar-state", {
|
|
401
|
+
skipActionQueryInvalidation: true,
|
|
402
|
+
onSuccess: (data) => {
|
|
403
|
+
queryClient.setQueryData(
|
|
404
|
+
["action", "get-content-sidebar-state", {}],
|
|
405
|
+
data,
|
|
406
|
+
);
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
const [expandedWorkspaceIds, setExpandedWorkspaceIds] = useState<string[]>(
|
|
410
|
+
[],
|
|
411
|
+
);
|
|
412
|
+
const [expandedDocumentIds, setExpandedDocumentIds] = useState<string[]>([]);
|
|
413
|
+
const expandedDocumentIdSet = useMemo(
|
|
414
|
+
() => new Set(expandedDocumentIds),
|
|
415
|
+
[expandedDocumentIds],
|
|
416
|
+
);
|
|
417
|
+
const sidebarStateHydratedRef = useRef(false);
|
|
418
|
+
const expandedWorkspaceIdsRef = useRef<string[]>([]);
|
|
419
|
+
const expandedDocumentIdsRef = useRef<string[]>([]);
|
|
420
|
+
const sidebarStateWriteTimerRef = useRef<ReturnType<
|
|
421
|
+
typeof setTimeout
|
|
422
|
+
> | null>(null);
|
|
423
|
+
const [createWorkspaceDialogOpen, setCreateWorkspaceDialogOpen] =
|
|
424
|
+
useState(false);
|
|
425
|
+
const [newWorkspaceName, setNewWorkspaceName] = useState("");
|
|
426
|
+
const createWorkspaceRequestIdRef = useRef<string | null>(null);
|
|
427
|
+
const contentSpaceState = contentSpaceAvailability({
|
|
428
|
+
hasSelectedSpace: Boolean(selectedSpace),
|
|
429
|
+
contentSpacesLoading: contentSpacesQuery.isLoading,
|
|
430
|
+
contentSpacesFetching: contentSpacesQuery.isFetching,
|
|
431
|
+
contentSpacesError: contentSpacesQuery.isError,
|
|
432
|
+
provisioningAttempted: spaceProvisionAttemptedRef.current,
|
|
433
|
+
provisioningPending: ensureContentSpaces.isPending,
|
|
434
|
+
provisioningError: ensureContentSpaces.isError,
|
|
435
|
+
});
|
|
436
|
+
const handleRetryContentSpaces = useCallback(() => {
|
|
437
|
+
if (contentSpacesQuery.isError) {
|
|
438
|
+
spaceProvisionAttemptedRef.current = false;
|
|
439
|
+
void contentSpacesQuery.refetch();
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
spaceProvisionAttemptedRef.current = true;
|
|
443
|
+
ensureContentSpaces.mutate({});
|
|
444
|
+
}, [contentSpacesQuery, ensureContentSpaces]);
|
|
269
445
|
useEffect(() => {
|
|
270
446
|
if (selectedSpace && selectedSpace.id !== storedSpaceId) {
|
|
271
447
|
setStoredSpaceId(selectedSpace.id);
|
|
272
448
|
}
|
|
273
449
|
}, [selectedSpace, setStoredSpaceId, storedSpaceId]);
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
if (
|
|
452
|
+
sidebarStateHydratedRef.current ||
|
|
453
|
+
!contentSpacesQuery.isSuccess ||
|
|
454
|
+
sidebarStateQuery.isLoading
|
|
455
|
+
) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const stored = sidebarStateQuery.data?.state;
|
|
459
|
+
const workspaceIds =
|
|
460
|
+
stored?.expandedWorkspaceIds ?? contentSpaces.map((space) => space.id);
|
|
461
|
+
const documentIds = stored?.expandedDocumentIds ?? [];
|
|
462
|
+
expandedWorkspaceIdsRef.current = workspaceIds;
|
|
463
|
+
expandedDocumentIdsRef.current = documentIds;
|
|
464
|
+
setExpandedWorkspaceIds(workspaceIds);
|
|
465
|
+
setExpandedDocumentIds(documentIds);
|
|
466
|
+
sidebarStateHydratedRef.current = true;
|
|
467
|
+
}, [
|
|
468
|
+
contentSpaces,
|
|
469
|
+
contentSpacesQuery.isSuccess,
|
|
470
|
+
sidebarStateQuery.data?.state,
|
|
471
|
+
sidebarStateQuery.isLoading,
|
|
472
|
+
]);
|
|
473
|
+
|
|
474
|
+
const queueSidebarStateWrite = useCallback(
|
|
475
|
+
(workspaceIds: string[], documentIds: string[]) => {
|
|
476
|
+
if (!sidebarStateHydratedRef.current) return;
|
|
477
|
+
if (sidebarStateWriteTimerRef.current) {
|
|
478
|
+
clearTimeout(sidebarStateWriteTimerRef.current);
|
|
479
|
+
}
|
|
480
|
+
sidebarStateWriteTimerRef.current = setTimeout(() => {
|
|
481
|
+
sidebarStateWriteTimerRef.current = null;
|
|
482
|
+
updateSidebarState.mutate({
|
|
483
|
+
version: CONTENT_SIDEBAR_STATE_VERSION,
|
|
484
|
+
expandedWorkspaceIds: workspaceIds,
|
|
485
|
+
expandedDocumentIds: documentIds,
|
|
486
|
+
});
|
|
487
|
+
}, 150);
|
|
488
|
+
},
|
|
489
|
+
[updateSidebarState],
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
const updateExpandedWorkspaceIds = useCallback(
|
|
493
|
+
(update: (current: string[]) => string[]) => {
|
|
494
|
+
setExpandedWorkspaceIds((current) => {
|
|
495
|
+
const next = update(current);
|
|
496
|
+
if (next === current) return current;
|
|
497
|
+
expandedWorkspaceIdsRef.current = next;
|
|
498
|
+
queueSidebarStateWrite(next, expandedDocumentIdsRef.current);
|
|
499
|
+
return next;
|
|
500
|
+
});
|
|
501
|
+
},
|
|
502
|
+
[queueSidebarStateWrite],
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
const handleDocumentExpandedChange = useCallback(
|
|
506
|
+
(documentId: string, expanded: boolean) => {
|
|
507
|
+
setExpandedDocumentIds((current) => {
|
|
508
|
+
const nextSet = new Set(current);
|
|
509
|
+
if (expanded) nextSet.add(documentId);
|
|
510
|
+
else nextSet.delete(documentId);
|
|
511
|
+
const next = [...nextSet];
|
|
512
|
+
expandedDocumentIdsRef.current = next;
|
|
513
|
+
queueSidebarStateWrite(expandedWorkspaceIdsRef.current, next);
|
|
514
|
+
return next;
|
|
515
|
+
});
|
|
516
|
+
},
|
|
517
|
+
[queueSidebarStateWrite],
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
useEffect(
|
|
521
|
+
() => () => {
|
|
522
|
+
if (sidebarStateWriteTimerRef.current) {
|
|
523
|
+
clearTimeout(sidebarStateWriteTimerRef.current);
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
[],
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
useEffect(() => {
|
|
530
|
+
if (!selectedSpace || !sidebarStateHydratedRef.current) return;
|
|
531
|
+
updateExpandedWorkspaceIds((current) =>
|
|
532
|
+
ensureWorkspaceExpanded(current, selectedSpace.id),
|
|
533
|
+
);
|
|
534
|
+
}, [selectedSpace, updateExpandedWorkspaceIds]);
|
|
274
535
|
const handleSelectContentSpace = useCallback(
|
|
275
|
-
async (
|
|
536
|
+
async (
|
|
537
|
+
space: (typeof contentSpaces)[number],
|
|
538
|
+
targetDocumentId?: string | null,
|
|
539
|
+
) => {
|
|
540
|
+
updateExpandedWorkspaceIds((current) =>
|
|
541
|
+
ensureWorkspaceExpanded(current, space.id),
|
|
542
|
+
);
|
|
276
543
|
try {
|
|
277
|
-
await
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
544
|
+
await workspaceSelectionQueueRef.current(() =>
|
|
545
|
+
selectContentSpace({
|
|
546
|
+
space,
|
|
547
|
+
syncApplicationState: (selected) =>
|
|
548
|
+
setClientAppState(
|
|
549
|
+
"content-space",
|
|
550
|
+
{
|
|
551
|
+
spaceId: selected.id,
|
|
552
|
+
name: selected.name,
|
|
553
|
+
kind: selected.kind,
|
|
554
|
+
filesDatabaseId: selected.filesDatabaseId,
|
|
555
|
+
},
|
|
556
|
+
{ requestSource: "content-sidebar" },
|
|
557
|
+
),
|
|
558
|
+
persistSelection: setStoredSpaceId,
|
|
559
|
+
openFiles: (documentId) => {
|
|
560
|
+
if (targetDocumentId === null) return;
|
|
561
|
+
navigate(`/page/${targetDocumentId ?? documentId}`, {
|
|
562
|
+
flushSync: true,
|
|
563
|
+
});
|
|
564
|
+
},
|
|
565
|
+
}),
|
|
566
|
+
);
|
|
567
|
+
return true;
|
|
283
568
|
} catch (error) {
|
|
284
569
|
toast.error(error instanceof Error ? error.message : String(error));
|
|
570
|
+
return false;
|
|
285
571
|
}
|
|
286
572
|
},
|
|
287
|
-
[
|
|
573
|
+
[navigate, setStoredSpaceId, updateExpandedWorkspaceIds],
|
|
288
574
|
);
|
|
575
|
+
const handleCreateWorkspace = useCallback(async () => {
|
|
576
|
+
const name = newWorkspaceName.trim();
|
|
577
|
+
if (!name) return;
|
|
578
|
+
const requestId = createWorkspaceRequestIdRef.current ?? nanoid();
|
|
579
|
+
createWorkspaceRequestIdRef.current = requestId;
|
|
580
|
+
try {
|
|
581
|
+
const created = await createContentSpace.mutateAsync({ name, requestId });
|
|
582
|
+
const space: ContentSpaceSummary = {
|
|
583
|
+
id: created.spaceId,
|
|
584
|
+
name: created.name,
|
|
585
|
+
kind: created.kind,
|
|
586
|
+
filesDatabaseId: created.filesDatabaseId,
|
|
587
|
+
filesDocumentId: created.filesDocumentId,
|
|
588
|
+
orgId: null,
|
|
589
|
+
role: "owner",
|
|
590
|
+
catalogItemId: created.catalogItemId,
|
|
591
|
+
catalogDocumentId: created.catalogDocumentId,
|
|
592
|
+
};
|
|
593
|
+
const selected = await handleSelectContentSpace(space);
|
|
594
|
+
if (!selected) return;
|
|
595
|
+
setCreateWorkspaceDialogOpen(false);
|
|
596
|
+
setNewWorkspaceName("");
|
|
597
|
+
createWorkspaceRequestIdRef.current = null;
|
|
598
|
+
} catch (error) {
|
|
599
|
+
toast.error(t("sidebar.failedCreateWorkspace"), {
|
|
600
|
+
description: error instanceof Error ? error.message : String(error),
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}, [createContentSpace, handleSelectContentSpace, newWorkspaceName, t]);
|
|
289
604
|
useEffect(() => {
|
|
290
605
|
if (!selectedSpace) return;
|
|
291
606
|
void setClientAppState(
|
|
@@ -301,15 +616,6 @@ export function DocumentSidebar({
|
|
|
301
616
|
// Space selection remains usable when best-effort agent context sync fails.
|
|
302
617
|
});
|
|
303
618
|
}, [selectedSpace]);
|
|
304
|
-
const filesDatabase = useContentDatabaseById(
|
|
305
|
-
selectedSpace?.filesDatabaseId ?? null,
|
|
306
|
-
);
|
|
307
|
-
const filesPersonalView = useContentDatabasePersonalView(
|
|
308
|
-
selectedSpace?.filesDatabaseId ?? null,
|
|
309
|
-
);
|
|
310
|
-
const updateFilesPersonalView = useUpdateContentDatabasePersonalView(
|
|
311
|
-
selectedSpace?.filesDatabaseId ?? null,
|
|
312
|
-
);
|
|
313
619
|
const removeLocalFileSource = useActionMutation<
|
|
314
620
|
RemoveLocalFileSourceResult,
|
|
315
621
|
{ sourceRootPath?: string | null }
|
|
@@ -330,7 +636,6 @@ export function DocumentSidebar({
|
|
|
330
636
|
);
|
|
331
637
|
const [removeLocalFilesDialogOpen, setRemoveLocalFilesDialogOpen] =
|
|
332
638
|
useState(false);
|
|
333
|
-
const localFilesActive = location.pathname.startsWith("/local-files");
|
|
334
639
|
const agentActive = location.pathname.startsWith("/agent");
|
|
335
640
|
const settingsActive = location.pathname.startsWith("/settings");
|
|
336
641
|
const sensors = useSensors(
|
|
@@ -390,7 +695,7 @@ export function DocumentSidebar({
|
|
|
390
695
|
// Match the tree rows' right-side inset so favorite titles clip inside the
|
|
391
696
|
// visible sidebar instead of widening the scroll surface.
|
|
392
697
|
const favoriteRowWidth =
|
|
393
|
-
width === undefined ? undefined : Math.max(
|
|
698
|
+
width === undefined ? undefined : Math.max(208, width - 24);
|
|
394
699
|
const activeDocument = activeDocumentId
|
|
395
700
|
? documents.find((doc) => doc.id === activeDocumentId)
|
|
396
701
|
: null;
|
|
@@ -436,13 +741,18 @@ export function DocumentSidebar({
|
|
|
436
741
|
);
|
|
437
742
|
|
|
438
743
|
const handleCreatePage = useCallback(
|
|
439
|
-
async (
|
|
744
|
+
async (
|
|
745
|
+
parentId?: string,
|
|
746
|
+
rootSpaceId = selectedSpace?.id,
|
|
747
|
+
optimisticId?: string,
|
|
748
|
+
rootFilesDatabaseId?: string,
|
|
749
|
+
) => {
|
|
440
750
|
if (localFileMode) {
|
|
441
751
|
try {
|
|
442
752
|
const created = await createDocument.mutateAsync({
|
|
443
753
|
title: "",
|
|
444
754
|
parentId: parentId ?? undefined,
|
|
445
|
-
spaceId:
|
|
755
|
+
spaceId: parentId ? undefined : rootSpaceId,
|
|
446
756
|
});
|
|
447
757
|
queryClient.setQueryData(
|
|
448
758
|
["action", "get-document", { id: created.id }],
|
|
@@ -462,7 +772,7 @@ export function DocumentSidebar({
|
|
|
462
772
|
return;
|
|
463
773
|
}
|
|
464
774
|
|
|
465
|
-
const id = nanoid();
|
|
775
|
+
const id = optimisticId ?? nanoid();
|
|
466
776
|
const now = new Date().toISOString();
|
|
467
777
|
const tempDoc: Document = {
|
|
468
778
|
id,
|
|
@@ -488,6 +798,20 @@ export function DocumentSidebar({
|
|
|
488
798
|
return { documents: [...docs, tempDoc] };
|
|
489
799
|
});
|
|
490
800
|
queryClient.setQueryData(["action", "get-document", { id }], tempDoc);
|
|
801
|
+
if (rootFilesDatabaseId) {
|
|
802
|
+
const optimisticItem: ContentDatabaseItem = {
|
|
803
|
+
id: `optimistic-${id}`,
|
|
804
|
+
databaseId: rootFilesDatabaseId,
|
|
805
|
+
document: tempDoc,
|
|
806
|
+
position: tempDoc.position,
|
|
807
|
+
properties: [],
|
|
808
|
+
};
|
|
809
|
+
queryClient.setQueryData<ContentDatabaseResponse>(
|
|
810
|
+
contentDatabaseByIdQueryKey(rootFilesDatabaseId),
|
|
811
|
+
(current) =>
|
|
812
|
+
applyOptimisticItemToContentDatabase(current, optimisticItem),
|
|
813
|
+
);
|
|
814
|
+
}
|
|
491
815
|
|
|
492
816
|
navigateToDocument(id);
|
|
493
817
|
onNavigate?.();
|
|
@@ -497,7 +821,7 @@ export function DocumentSidebar({
|
|
|
497
821
|
id,
|
|
498
822
|
title: "",
|
|
499
823
|
parentId: parentId ?? undefined,
|
|
500
|
-
spaceId:
|
|
824
|
+
spaceId: parentId ? undefined : rootSpaceId,
|
|
501
825
|
});
|
|
502
826
|
const nextId = created?.id || id;
|
|
503
827
|
if (nextId !== id) {
|
|
@@ -518,6 +842,11 @@ export function DocumentSidebar({
|
|
|
518
842
|
queryClient.invalidateQueries({
|
|
519
843
|
queryKey: ["action", "list-documents"],
|
|
520
844
|
});
|
|
845
|
+
if (rootFilesDatabaseId) {
|
|
846
|
+
queryClient.invalidateQueries({
|
|
847
|
+
queryKey: contentDatabaseByIdQueryKey(rootFilesDatabaseId),
|
|
848
|
+
});
|
|
849
|
+
}
|
|
521
850
|
} catch (err) {
|
|
522
851
|
// Revert optimistic updates
|
|
523
852
|
queryClient.invalidateQueries({
|
|
@@ -526,6 +855,12 @@ export function DocumentSidebar({
|
|
|
526
855
|
queryClient.removeQueries({
|
|
527
856
|
queryKey: ["action", "get-document", { id }],
|
|
528
857
|
});
|
|
858
|
+
if (rootFilesDatabaseId) {
|
|
859
|
+
queryClient.setQueryData<ContentDatabaseResponse>(
|
|
860
|
+
contentDatabaseByIdQueryKey(rootFilesDatabaseId),
|
|
861
|
+
(current) => removeOptimisticItemFromContentDatabase(current, id),
|
|
862
|
+
);
|
|
863
|
+
}
|
|
529
864
|
navigate("/");
|
|
530
865
|
toast.error(t("sidebar.failedCreatePage"), {
|
|
531
866
|
description:
|
|
@@ -545,11 +880,11 @@ export function DocumentSidebar({
|
|
|
545
880
|
);
|
|
546
881
|
|
|
547
882
|
const handleCreateDatabase = useCallback(
|
|
548
|
-
async (parentId?: string | null) => {
|
|
883
|
+
async (parentId?: string | null, rootSpaceId = selectedSpace?.id) => {
|
|
549
884
|
try {
|
|
550
885
|
const result = await createDatabase.mutateAsync({
|
|
551
886
|
parentId: parentId ?? null,
|
|
552
|
-
spaceId: parentId ? undefined :
|
|
887
|
+
spaceId: parentId ? undefined : rootSpaceId,
|
|
553
888
|
title: t("editor.untitledDatabase"),
|
|
554
889
|
});
|
|
555
890
|
navigateToDocument(result.database.documentId);
|
|
@@ -564,6 +899,33 @@ export function DocumentSidebar({
|
|
|
564
899
|
[createDatabase, navigateToDocument, onNavigate, selectedSpace?.id, t],
|
|
565
900
|
);
|
|
566
901
|
|
|
902
|
+
const handleCreatePageInSpace = useCallback(
|
|
903
|
+
async (space: ContentSpaceSummary) => {
|
|
904
|
+
const id = nanoid();
|
|
905
|
+
if (selectedSpace?.id !== space.id) {
|
|
906
|
+
void handleSelectContentSpace(space, null);
|
|
907
|
+
}
|
|
908
|
+
await handleCreatePage(undefined, space.id, id, space.filesDatabaseId);
|
|
909
|
+
},
|
|
910
|
+
[handleCreatePage, handleSelectContentSpace, selectedSpace?.id],
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
const handleOpenFavorite = useCallback(
|
|
914
|
+
(document: Document) => {
|
|
915
|
+
const space = contentSpaces.find(
|
|
916
|
+
(candidate) =>
|
|
917
|
+
candidate.filesDocumentId ===
|
|
918
|
+
document.databaseMembership?.databaseDocumentId,
|
|
919
|
+
);
|
|
920
|
+
if (space) {
|
|
921
|
+
void handleSelectContentSpace(space, document.id);
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
navigateToDocument(document.id);
|
|
925
|
+
},
|
|
926
|
+
[contentSpaces, handleSelectContentSpace, navigateToDocument],
|
|
927
|
+
);
|
|
928
|
+
|
|
567
929
|
const handleDelete = useCallback(
|
|
568
930
|
async (id: string) => {
|
|
569
931
|
const deletedDocument = documents.find((doc) => doc.id === id) ?? null;
|
|
@@ -727,9 +1089,21 @@ export function DocumentSidebar({
|
|
|
727
1089
|
|
|
728
1090
|
const handleToggleFavorite = useCallback(
|
|
729
1091
|
(id: string, isFavorite: boolean) => {
|
|
730
|
-
updateDocument.mutate(
|
|
1092
|
+
updateDocument.mutate(
|
|
1093
|
+
{ id, isFavorite },
|
|
1094
|
+
{
|
|
1095
|
+
onError: (error) => {
|
|
1096
|
+
toast.error(t("sidebar.failedUpdateFavorite"), {
|
|
1097
|
+
description:
|
|
1098
|
+
error instanceof Error
|
|
1099
|
+
? error.message
|
|
1100
|
+
: t("empty.genericError"),
|
|
1101
|
+
});
|
|
1102
|
+
},
|
|
1103
|
+
},
|
|
1104
|
+
);
|
|
731
1105
|
},
|
|
732
|
-
[updateDocument],
|
|
1106
|
+
[t, updateDocument],
|
|
733
1107
|
);
|
|
734
1108
|
|
|
735
1109
|
const handleRestoreDatabase = useCallback(
|
|
@@ -821,33 +1195,17 @@ export function DocumentSidebar({
|
|
|
821
1195
|
</SortableContext>
|
|
822
1196
|
);
|
|
823
1197
|
|
|
824
|
-
const renderNewButton = () =>
|
|
825
|
-
|
|
826
|
-
<
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
</button>
|
|
836
|
-
<Tooltip>
|
|
837
|
-
<TooltipTrigger asChild>
|
|
838
|
-
<button
|
|
839
|
-
type="button"
|
|
840
|
-
className="flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/50 hover:text-foreground"
|
|
841
|
-
disabled={createDatabase.isPending}
|
|
842
|
-
aria-label={t("sidebar.newDatabase")}
|
|
843
|
-
onClick={() => void handleCreateDatabase()}
|
|
844
|
-
>
|
|
845
|
-
<IconDatabase size={14} />
|
|
846
|
-
</button>
|
|
847
|
-
</TooltipTrigger>
|
|
848
|
-
<TooltipContent>{t("sidebar.newDatabase")}</TooltipContent>
|
|
849
|
-
</Tooltip>
|
|
850
|
-
</div>
|
|
1198
|
+
const renderNewButton = (space = selectedSpace) =>
|
|
1199
|
+
space ? (
|
|
1200
|
+
<button
|
|
1201
|
+
type="button"
|
|
1202
|
+
className="flex w-full min-w-0 items-center gap-2 rounded-md px-3 py-[5px] text-sm text-muted-foreground hover:bg-accent/50 hover:text-foreground"
|
|
1203
|
+
disabled={createDocument.isPending}
|
|
1204
|
+
onClick={() => void handleCreatePageInSpace(space)}
|
|
1205
|
+
>
|
|
1206
|
+
<IconPlus size={14} className="shrink-0" />
|
|
1207
|
+
<span>{t("sidebar.newPage")}</span>
|
|
1208
|
+
</button>
|
|
851
1209
|
) : null;
|
|
852
1210
|
|
|
853
1211
|
const renderCollapsedNewButton = () =>
|
|
@@ -858,7 +1216,7 @@ export function DocumentSidebar({
|
|
|
858
1216
|
type="button"
|
|
859
1217
|
className="w-10 h-10 flex items-center justify-center rounded-lg hover:bg-accent text-muted-foreground hover:text-foreground"
|
|
860
1218
|
disabled={createDocument.isPending}
|
|
861
|
-
onClick={() => void
|
|
1219
|
+
onClick={() => void handleCreatePageInSpace(selectedSpace)}
|
|
862
1220
|
>
|
|
863
1221
|
<IconPlus size={16} />
|
|
864
1222
|
</button>
|
|
@@ -867,23 +1225,6 @@ export function DocumentSidebar({
|
|
|
867
1225
|
</Tooltip>
|
|
868
1226
|
) : null;
|
|
869
1227
|
|
|
870
|
-
const renderLocalFilesNavButton = () => (
|
|
871
|
-
<Link
|
|
872
|
-
to="/local-files"
|
|
873
|
-
className={cn(
|
|
874
|
-
"flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm",
|
|
875
|
-
localFilesActive
|
|
876
|
-
? "bg-accent text-accent-foreground"
|
|
877
|
-
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
878
|
-
)}
|
|
879
|
-
>
|
|
880
|
-
<IconFolderOpen size={15} className="shrink-0" />
|
|
881
|
-
<span className="min-w-0 flex-1 truncate text-start">
|
|
882
|
-
{t("sidebar.localFiles")}
|
|
883
|
-
</span>
|
|
884
|
-
</Link>
|
|
885
|
-
);
|
|
886
|
-
|
|
887
1228
|
const renderSettingsNavButton = () => (
|
|
888
1229
|
<Link
|
|
889
1230
|
to="/settings"
|
|
@@ -1065,69 +1406,200 @@ export function DocumentSidebar({
|
|
|
1065
1406
|
);
|
|
1066
1407
|
};
|
|
1067
1408
|
|
|
1068
|
-
const
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
<button
|
|
1075
|
-
key={space.id}
|
|
1076
|
-
type="button"
|
|
1409
|
+
const renderWorkspaceRoot = (space: ContentSpaceSummary) => {
|
|
1410
|
+
const selected = selectedSpace?.id === space.id;
|
|
1411
|
+
const expanded = expandedWorkspaceIds.includes(space.id);
|
|
1412
|
+
return (
|
|
1413
|
+
<div className="min-w-0">
|
|
1414
|
+
<div
|
|
1077
1415
|
className={cn(
|
|
1078
|
-
"flex h-
|
|
1079
|
-
|
|
1080
|
-
? "
|
|
1081
|
-
: "text-muted-foreground hover:bg-accent/
|
|
1416
|
+
"group/workspace-header flex h-7 w-full min-w-0 items-center rounded-md",
|
|
1417
|
+
selected
|
|
1418
|
+
? "text-foreground"
|
|
1419
|
+
: "text-muted-foreground hover:bg-accent/40 hover:text-foreground",
|
|
1082
1420
|
)}
|
|
1083
|
-
onClick={() => void handleSelectContentSpace(space)}
|
|
1084
|
-
disabled={switchOrg.isPending}
|
|
1085
1421
|
>
|
|
1086
|
-
<
|
|
1422
|
+
<button
|
|
1423
|
+
type="button"
|
|
1424
|
+
aria-expanded={expanded}
|
|
1425
|
+
aria-label={`${expanded ? t("sidebar.collapse") : t("sidebar.expand")} ${space.name}`}
|
|
1426
|
+
className="relative flex size-7 shrink-0 items-center justify-center rounded-md hover:bg-background/60"
|
|
1427
|
+
onClick={() =>
|
|
1428
|
+
updateExpandedWorkspaceIds((current) =>
|
|
1429
|
+
toggleExpandedWorkspaceIds(current, space.id),
|
|
1430
|
+
)
|
|
1431
|
+
}
|
|
1432
|
+
>
|
|
1433
|
+
<span className="group-hover/workspace-header:opacity-0 group-focus-within/workspace-header:opacity-0">
|
|
1434
|
+
{expanded ? (
|
|
1435
|
+
<IconFolderOpen size={14} />
|
|
1436
|
+
) : (
|
|
1437
|
+
<IconFolder size={14} />
|
|
1438
|
+
)}
|
|
1439
|
+
</span>
|
|
1440
|
+
<span className="absolute inset-0 flex items-center justify-center opacity-0 group-hover/workspace-header:opacity-100 group-focus-within/workspace-header:opacity-100">
|
|
1441
|
+
{expanded ? (
|
|
1442
|
+
<IconChevronDown size={14} />
|
|
1443
|
+
) : (
|
|
1444
|
+
<IconChevronRight size={14} />
|
|
1445
|
+
)}
|
|
1446
|
+
</span>
|
|
1447
|
+
</button>
|
|
1448
|
+
<button
|
|
1449
|
+
type="button"
|
|
1450
|
+
className="h-7 min-w-0 flex-1 truncate pe-2 text-start text-[10px] font-semibold uppercase tracking-wider"
|
|
1451
|
+
onClick={() => void handleSelectContentSpace(space)}
|
|
1452
|
+
>
|
|
1087
1453
|
{space.name}
|
|
1088
|
-
</
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1454
|
+
</button>
|
|
1455
|
+
<button
|
|
1456
|
+
type="button"
|
|
1457
|
+
className="flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background/60 hover:text-foreground disabled:opacity-50"
|
|
1458
|
+
disabled={createDocument.isPending}
|
|
1459
|
+
aria-label={`${t("sidebar.newPage")} — ${space.name}`}
|
|
1460
|
+
onClick={() => void handleCreatePageInSpace(space)}
|
|
1461
|
+
>
|
|
1462
|
+
<IconPlus size={14} />
|
|
1463
|
+
</button>
|
|
1464
|
+
</div>
|
|
1465
|
+
{expanded && (
|
|
1466
|
+
<WorkspaceFilesSection
|
|
1467
|
+
space={space}
|
|
1468
|
+
selected={selected}
|
|
1469
|
+
activeDocumentId={activeDocumentId}
|
|
1470
|
+
expandedDocumentIds={expandedDocumentIdSet}
|
|
1471
|
+
onDocumentExpandedChange={handleDocumentExpandedChange}
|
|
1472
|
+
onActivate={(nextSpace, documentId) =>
|
|
1473
|
+
void handleSelectContentSpace(nextSpace, documentId)
|
|
1474
|
+
}
|
|
1475
|
+
onCreateChildPage={(nextSpace, item) =>
|
|
1476
|
+
void handleCreatePage(
|
|
1477
|
+
item.document.id,
|
|
1478
|
+
nextSpace.id,
|
|
1479
|
+
undefined,
|
|
1480
|
+
nextSpace.filesDatabaseId,
|
|
1481
|
+
)
|
|
1482
|
+
}
|
|
1483
|
+
onCreateChildDatabase={(nextSpace, item) =>
|
|
1484
|
+
void handleCreateDatabase(item.document.id, nextSpace.id)
|
|
1485
|
+
}
|
|
1486
|
+
onDeleteItem={(item) => void handleDelete(item.document.id)}
|
|
1487
|
+
onToggleFavorite={(item) =>
|
|
1488
|
+
handleToggleFavorite(item.document.id, !item.document.isFavorite)
|
|
1489
|
+
}
|
|
1124
1490
|
/>
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1491
|
+
)}
|
|
1492
|
+
</div>
|
|
1493
|
+
);
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1496
|
+
const renderWorkspaceNavigation = () => (
|
|
1497
|
+
<div className="mb-2 min-w-0 overflow-x-hidden px-2">
|
|
1498
|
+
{contentSpaceState === "ready" && selectedSpace ? (
|
|
1499
|
+
<div className="grid gap-1">
|
|
1500
|
+
{workspaceCatalogDatabase.isError ||
|
|
1501
|
+
workspaceCatalogPersonalView.isError ? (
|
|
1502
|
+
<QueryErrorState
|
|
1503
|
+
compact
|
|
1504
|
+
onRetry={() => {
|
|
1505
|
+
void workspaceCatalogDatabase.refetch();
|
|
1506
|
+
void workspaceCatalogPersonalView.refetch();
|
|
1507
|
+
}}
|
|
1508
|
+
retrying={
|
|
1509
|
+
workspaceCatalogDatabase.isFetching ||
|
|
1510
|
+
workspaceCatalogPersonalView.isFetching
|
|
1511
|
+
}
|
|
1512
|
+
/>
|
|
1513
|
+
) : (
|
|
1514
|
+
<ContentFilesSidebarView
|
|
1515
|
+
data={workspaceCatalogDatabase.data}
|
|
1516
|
+
overrides={workspaceCatalogPersonalView.data?.overrides}
|
|
1517
|
+
isLoading={
|
|
1518
|
+
workspaceCatalogDatabase.isLoading ||
|
|
1519
|
+
workspaceCatalogPersonalView.isLoading
|
|
1520
|
+
}
|
|
1521
|
+
onSelectView={(viewId) => {
|
|
1522
|
+
if (!workspaceCatalogDatabaseId) return;
|
|
1523
|
+
const current = workspaceCatalogPersonalView.data?.overrides;
|
|
1524
|
+
updateWorkspaceCatalogPersonalView.mutate({
|
|
1525
|
+
databaseId: workspaceCatalogDatabaseId,
|
|
1526
|
+
overrides: {
|
|
1527
|
+
version:
|
|
1528
|
+
current?.version ??
|
|
1529
|
+
CONTENT_DATABASE_PERSONAL_VIEW_OVERRIDES_VERSION,
|
|
1530
|
+
activeViewId: viewId,
|
|
1531
|
+
views: current?.views ?? [],
|
|
1532
|
+
},
|
|
1533
|
+
});
|
|
1534
|
+
}}
|
|
1535
|
+
renderItem={(item) => {
|
|
1536
|
+
const space = contentSpaces.find(
|
|
1537
|
+
(candidate) =>
|
|
1538
|
+
candidate.catalogDocumentId === item.document.id,
|
|
1539
|
+
);
|
|
1540
|
+
return space
|
|
1541
|
+
? renderWorkspaceRoot({
|
|
1542
|
+
...space,
|
|
1543
|
+
name: item.document.title || space.name,
|
|
1544
|
+
})
|
|
1545
|
+
: null;
|
|
1546
|
+
}}
|
|
1547
|
+
scroll={false}
|
|
1548
|
+
labels={{
|
|
1549
|
+
loadingLabel: t("sidebar.loadingFiles"),
|
|
1550
|
+
noMatchesLabel: t("database.noRowsMatchThisView"),
|
|
1551
|
+
clearLabel: t("database.clearSearchAndFilters"),
|
|
1552
|
+
navigationLabel: "Content navigation",
|
|
1553
|
+
untitledLabel: t("sidebar.untitled"),
|
|
1554
|
+
}}
|
|
1555
|
+
/>
|
|
1556
|
+
)}
|
|
1557
|
+
<div className="px-1">
|
|
1558
|
+
<DropdownMenu>
|
|
1559
|
+
<DropdownMenuTrigger asChild>
|
|
1560
|
+
<button
|
|
1561
|
+
type="button"
|
|
1562
|
+
className="flex h-7 w-full min-w-0 items-center rounded-md text-muted-foreground hover:bg-accent/40 hover:text-foreground"
|
|
1563
|
+
aria-label={t("sidebar.addWorkspace")}
|
|
1564
|
+
>
|
|
1565
|
+
<span className="flex size-7 shrink-0 items-center justify-center">
|
|
1566
|
+
<IconPlus size={14} />
|
|
1567
|
+
</span>
|
|
1568
|
+
<span className="truncate text-start text-[10px] font-semibold uppercase tracking-wider">
|
|
1569
|
+
{t("sidebar.addWorkspace")}
|
|
1570
|
+
</span>
|
|
1571
|
+
</button>
|
|
1572
|
+
</DropdownMenuTrigger>
|
|
1573
|
+
<DropdownMenuContent align="start" className="w-52">
|
|
1574
|
+
<DropdownMenuItem
|
|
1575
|
+
onSelect={() => setCreateWorkspaceDialogOpen(true)}
|
|
1576
|
+
>
|
|
1577
|
+
<IconPlus className="me-2 size-4" />
|
|
1578
|
+
{t("sidebar.newWorkspace")}
|
|
1579
|
+
</DropdownMenuItem>
|
|
1580
|
+
<DropdownMenuSeparator />
|
|
1581
|
+
<DropdownMenuItem asChild>
|
|
1582
|
+
<Link to="/local-files">
|
|
1583
|
+
<IconFolder className="me-2 size-4" />
|
|
1584
|
+
{t("sidebar.localFolder")}
|
|
1585
|
+
</Link>
|
|
1586
|
+
</DropdownMenuItem>
|
|
1587
|
+
</DropdownMenuContent>
|
|
1588
|
+
</DropdownMenu>
|
|
1589
|
+
</div>
|
|
1590
|
+
</div>
|
|
1591
|
+
) : contentSpaceState === "loading" ? (
|
|
1128
1592
|
<div className="px-3 py-4 text-center text-sm text-muted-foreground">
|
|
1129
|
-
{t("sidebar.
|
|
1593
|
+
{t("sidebar.loadingFiles")}
|
|
1130
1594
|
</div>
|
|
1595
|
+
) : (
|
|
1596
|
+
<QueryErrorState
|
|
1597
|
+
compact
|
|
1598
|
+
onRetry={handleRetryContentSpaces}
|
|
1599
|
+
retrying={
|
|
1600
|
+
contentSpacesQuery.isFetching || ensureContentSpaces.isPending
|
|
1601
|
+
}
|
|
1602
|
+
/>
|
|
1131
1603
|
)}
|
|
1132
1604
|
</div>
|
|
1133
1605
|
);
|
|
@@ -1244,22 +1716,6 @@ export function DocumentSidebar({
|
|
|
1244
1716
|
<TooltipContent>{t("sidebar.expand")}</TooltipContent>
|
|
1245
1717
|
</Tooltip>
|
|
1246
1718
|
{renderCollapsedNewButton()}
|
|
1247
|
-
<Tooltip>
|
|
1248
|
-
<TooltipTrigger asChild>
|
|
1249
|
-
<Link
|
|
1250
|
-
to="/local-files"
|
|
1251
|
-
className={cn(
|
|
1252
|
-
"w-10 h-10 flex items-center justify-center rounded-lg hover:bg-accent",
|
|
1253
|
-
localFilesActive
|
|
1254
|
-
? "bg-accent text-accent-foreground"
|
|
1255
|
-
: "text-muted-foreground hover:text-foreground",
|
|
1256
|
-
)}
|
|
1257
|
-
>
|
|
1258
|
-
<IconFolderOpen size={16} />
|
|
1259
|
-
</Link>
|
|
1260
|
-
</TooltipTrigger>
|
|
1261
|
-
<TooltipContent>{t("sidebar.localFiles")}</TooltipContent>
|
|
1262
|
-
</Tooltip>
|
|
1263
1719
|
<Tooltip>
|
|
1264
1720
|
<TooltipTrigger asChild>
|
|
1265
1721
|
<Link
|
|
@@ -1416,46 +1872,62 @@ export function DocumentSidebar({
|
|
|
1416
1872
|
<>
|
|
1417
1873
|
{/* Favorites */}
|
|
1418
1874
|
{showFavorites && (
|
|
1419
|
-
<div className="mb-2 min-w-0">
|
|
1420
|
-
<div className="flex min-w-0 items-center
|
|
1421
|
-
<IconStar size={10} />
|
|
1422
|
-
<span className="min-w-0 flex-1 truncate">
|
|
1423
|
-
{t("sidebar.favorites")}
|
|
1424
|
-
</span>
|
|
1425
|
-
</div>
|
|
1426
|
-
{favorites.map((doc) => (
|
|
1875
|
+
<div className="mb-2 min-w-0 px-2">
|
|
1876
|
+
<div className="flex h-7 w-full min-w-0 items-center rounded-md px-1 text-muted-foreground hover:bg-accent/40 hover:text-foreground">
|
|
1427
1877
|
<button
|
|
1428
|
-
|
|
1878
|
+
type="button"
|
|
1879
|
+
aria-expanded={!collapsedSections.favorites}
|
|
1880
|
+
aria-label={`${collapsedSections.favorites ? t("sidebar.expand") : t("sidebar.collapse")} ${t("sidebar.favorites")}`}
|
|
1881
|
+
className="flex size-7 shrink-0 items-center justify-center rounded-md hover:bg-background/60"
|
|
1882
|
+
onClick={() => toggleSection("favorites")}
|
|
1883
|
+
>
|
|
1884
|
+
{collapsedSections.favorites ? (
|
|
1885
|
+
<IconChevronRight size={14} />
|
|
1886
|
+
) : (
|
|
1887
|
+
<IconChevronDown size={14} />
|
|
1888
|
+
)}
|
|
1889
|
+
</button>
|
|
1890
|
+
<Link
|
|
1891
|
+
to={
|
|
1892
|
+
favoritesDocumentId
|
|
1893
|
+
? `/page/${favoritesDocumentId}`
|
|
1894
|
+
: "/favorites"
|
|
1895
|
+
}
|
|
1429
1896
|
className={cn(
|
|
1430
|
-
"
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1897
|
+
"h-7 min-w-0 flex-1 truncate pe-2 text-start text-[10px] font-semibold uppercase tracking-wider leading-7",
|
|
1898
|
+
(location.pathname === "/favorites" ||
|
|
1899
|
+
activeDocumentId === favoritesDocumentId) &&
|
|
1900
|
+
"text-foreground",
|
|
1434
1901
|
)}
|
|
1435
|
-
style={{
|
|
1436
|
-
width:
|
|
1437
|
-
favoriteRowWidth === undefined
|
|
1438
|
-
? undefined
|
|
1439
|
-
: `${favoriteRowWidth}px`,
|
|
1440
|
-
}}
|
|
1441
|
-
onClick={() => {
|
|
1442
|
-
navigateToDocument(doc.id);
|
|
1443
|
-
onNavigate?.();
|
|
1444
|
-
}}
|
|
1445
1902
|
>
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1903
|
+
{t("sidebar.favorites")}
|
|
1904
|
+
</Link>
|
|
1905
|
+
</div>
|
|
1906
|
+
{!collapsedSections.favorites &&
|
|
1907
|
+
favorites.map((doc) => (
|
|
1908
|
+
<FavoriteDocumentItem
|
|
1909
|
+
key={doc.id}
|
|
1910
|
+
document={doc}
|
|
1911
|
+
active={doc.id === activeDocumentId}
|
|
1912
|
+
sidebarWidth={favoriteRowWidth}
|
|
1913
|
+
onSelect={() => {
|
|
1914
|
+
handleOpenFavorite(doc);
|
|
1915
|
+
onNavigate?.();
|
|
1916
|
+
}}
|
|
1917
|
+
onCreateChildPage={() => void handleCreatePage(doc.id)}
|
|
1918
|
+
onCreateChildDatabase={() =>
|
|
1919
|
+
void handleCreateDatabase(doc.id)
|
|
1920
|
+
}
|
|
1921
|
+
onRemoveFavorite={() =>
|
|
1922
|
+
handleToggleFavorite(doc.id, false)
|
|
1923
|
+
}
|
|
1924
|
+
onDelete={() => void handleDelete(doc.id)}
|
|
1925
|
+
/>
|
|
1926
|
+
))}
|
|
1454
1927
|
</div>
|
|
1455
1928
|
)}
|
|
1456
1929
|
|
|
1457
1930
|
{renderWorkspaceNavigation()}
|
|
1458
|
-
{renderFilesDatabase()}
|
|
1459
1931
|
{renderTrashSection()}
|
|
1460
1932
|
</>
|
|
1461
1933
|
)}
|
|
@@ -1464,7 +1936,6 @@ export function DocumentSidebar({
|
|
|
1464
1936
|
|
|
1465
1937
|
<div className="shrink-0 px-3 py-2">
|
|
1466
1938
|
<div className="space-y-1">
|
|
1467
|
-
{renderLocalFilesNavButton()}
|
|
1468
1939
|
{renderAgentNavButton()}
|
|
1469
1940
|
{renderSettingsNavButton()}
|
|
1470
1941
|
</div>
|
|
@@ -1487,7 +1958,6 @@ export function DocumentSidebar({
|
|
|
1487
1958
|
|
|
1488
1959
|
{/* Footer */}
|
|
1489
1960
|
<div className="shrink-0 space-y-2 px-3 py-2">
|
|
1490
|
-
<OrgSwitcher />
|
|
1491
1961
|
{isCodeMode ? <DevDatabaseLink /> : null}
|
|
1492
1962
|
<div className="flex items-center gap-1">
|
|
1493
1963
|
<FeedbackButton className="h-8 min-w-0 flex-1 gap-2 rounded-md px-2 py-0" />
|
|
@@ -1508,6 +1978,60 @@ export function DocumentSidebar({
|
|
|
1508
1978
|
onMouseDown={handleMouseDown}
|
|
1509
1979
|
/>
|
|
1510
1980
|
)}
|
|
1981
|
+
<Dialog
|
|
1982
|
+
open={createWorkspaceDialogOpen}
|
|
1983
|
+
onOpenChange={(open) => {
|
|
1984
|
+
setCreateWorkspaceDialogOpen(open);
|
|
1985
|
+
if (!open && !createContentSpace.isPending) {
|
|
1986
|
+
setNewWorkspaceName("");
|
|
1987
|
+
createWorkspaceRequestIdRef.current = null;
|
|
1988
|
+
}
|
|
1989
|
+
}}
|
|
1990
|
+
>
|
|
1991
|
+
<DialogContent className="sm:max-w-sm">
|
|
1992
|
+
<form
|
|
1993
|
+
className="grid gap-4"
|
|
1994
|
+
onSubmit={(event) => {
|
|
1995
|
+
event.preventDefault();
|
|
1996
|
+
void handleCreateWorkspace();
|
|
1997
|
+
}}
|
|
1998
|
+
>
|
|
1999
|
+
<DialogHeader>
|
|
2000
|
+
<DialogTitle>{t("sidebar.newWorkspace")}</DialogTitle>
|
|
2001
|
+
<DialogDescription>
|
|
2002
|
+
{t("sidebar.newWorkspaceDescription")}
|
|
2003
|
+
</DialogDescription>
|
|
2004
|
+
</DialogHeader>
|
|
2005
|
+
<Input
|
|
2006
|
+
autoFocus
|
|
2007
|
+
aria-label={t("sidebar.workspaceName")}
|
|
2008
|
+
placeholder={t("sidebar.workspaceName")}
|
|
2009
|
+
value={newWorkspaceName}
|
|
2010
|
+
maxLength={200}
|
|
2011
|
+
onChange={(event) => setNewWorkspaceName(event.target.value)}
|
|
2012
|
+
/>
|
|
2013
|
+
<DialogFooter>
|
|
2014
|
+
<button
|
|
2015
|
+
type="button"
|
|
2016
|
+
className="inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium hover:bg-accent"
|
|
2017
|
+
disabled={createContentSpace.isPending}
|
|
2018
|
+
onClick={() => setCreateWorkspaceDialogOpen(false)}
|
|
2019
|
+
>
|
|
2020
|
+
{t("comments.cancel")}
|
|
2021
|
+
</button>
|
|
2022
|
+
<button
|
|
2023
|
+
type="submit"
|
|
2024
|
+
className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
|
|
2025
|
+
disabled={
|
|
2026
|
+
createContentSpace.isPending || !newWorkspaceName.trim()
|
|
2027
|
+
}
|
|
2028
|
+
>
|
|
2029
|
+
{t("sidebar.createWorkspace")}
|
|
2030
|
+
</button>
|
|
2031
|
+
</DialogFooter>
|
|
2032
|
+
</form>
|
|
2033
|
+
</DialogContent>
|
|
2034
|
+
</Dialog>
|
|
1511
2035
|
<AlertDialog
|
|
1512
2036
|
open={removeLocalFilesDialogOpen}
|
|
1513
2037
|
onOpenChange={setRemoveLocalFilesDialogOpen}
|