@agent-native/core-corpus 0.201.0-nightly-20261005153421 → 0.201.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +14 -4
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/analytics/CHANGELOG.md +6 -0
- package/corpus/templates/analytics/README.md +2 -2
- package/corpus/templates/analytics/changelog/2026-10-02-events-with-a-very-long-name-app-or-page-path-no-longer-caus.md +6 -0
- package/corpus/templates/analytics/package.json +1 -0
- package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -19
- package/corpus/templates/analytics/server/handlers/session-replay.ts +34 -47
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -6
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -36
- package/corpus/templates/analytics/server/lib/indexed-text.ts +53 -0
- package/corpus/templates/analytics/server/lib/request-errors.ts +73 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +6 -16
- package/corpus/templates/analytics/server/lib/session-replay.ts +12 -2
- package/corpus/templates/analytics/server/plugins/auth.ts +2 -1
- package/corpus/templates/analytics/server/plugins/otel.ts +6 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/assets/CHANGELOG.md +7 -0
- package/corpus/templates/assets/README.md +2 -2
- package/corpus/templates/assets/package.json +1 -0
- package/corpus/templates/assets/server/plugins/auth.ts +2 -1
- package/corpus/templates/assets/server/plugins/otel.ts +6 -0
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +2 -1
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +5 -4
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/brain/README.md +12 -8
- package/corpus/templates/brain/changelog/2026-10-05-private-slack-channels-are-searchable-org-wide.md +6 -0
- package/corpus/templates/brain/package.json +1 -0
- package/corpus/templates/brain/server/lib/audiences.ts +1 -98
- package/corpus/templates/brain/server/lib/connectors.ts +2 -166
- package/corpus/templates/brain/server/plugins/otel.ts +6 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/calendar/CHANGELOG.md +7 -0
- package/corpus/templates/calendar/README.md +2 -2
- package/corpus/templates/calendar/package.json +1 -0
- package/corpus/templates/calendar/server/plugins/auth.ts +2 -1
- package/corpus/templates/calendar/server/plugins/otel.ts +6 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/chat/README.md +2 -2
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +9 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/clips/CHANGELOG.md +24 -0
- package/corpus/templates/clips/README.md +2 -2
- package/corpus/templates/clips/actions/lib/audio-chunk-list.ts +23 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +187 -292
- package/corpus/templates/clips/actions/lib/chunked-transcription.ts +151 -0
- package/corpus/templates/clips/actions/lib/recording-audio-source.ts +191 -0
- package/corpus/templates/clips/actions/request-transcript.ts +81 -135
- package/corpus/templates/clips/actions/search-recordings.ts +19 -5
- package/corpus/templates/clips/app/components/clips-command-menu.tsx +5 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -1
- package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -0
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
- package/corpus/templates/clips/app/lib/local-recording-upload.ts +13 -6
- package/corpus/templates/clips/app/lib/recording-section.ts +1 -1
- package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +7 -5
- package/corpus/templates/clips/app/routes/record.tsx +16 -6
- package/corpus/templates/clips/changelog/2026-10-02-long-uploads-an-hour-or-more-now-transcribe-reliably-instead.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-confirming-discard-recording-now-returns-you-to-your-library.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recording-now-removes-its-failed-upload-card-fr.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recovered-recording-no-longer-warns-that-it-s-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-10-05-search-results-identify-recordings-in-trash-and-open-them-wi.md +6 -0
- package/corpus/templates/clips/package.json +1 -0
- package/corpus/templates/clips/server/lib/builder-cdn.ts +5 -0
- package/corpus/templates/clips/server/lib/builder-media-compression.ts +2 -2
- package/corpus/templates/clips/server/plugins/auth.ts +2 -1
- package/corpus/templates/clips/server/plugins/otel.ts +6 -0
- package/corpus/templates/clips/shared/transcript-failure.ts +5 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
- package/corpus/templates/content/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/content/CHANGELOG.md +41 -0
- package/corpus/templates/content/README.md +2 -2
- package/corpus/templates/content/actions/_database-navigation.ts +523 -344
- package/corpus/templates/content/actions/_database-row-mutation.ts +44 -10
- package/corpus/templates/content/actions/_database-setup-discovery.ts +9 -3
- package/corpus/templates/content/actions/_database-utils.ts +299 -271
- package/corpus/templates/content/actions/_property-utils.ts +293 -190
- package/corpus/templates/content/actions/_relation-values.ts +3 -1
- package/corpus/templates/content/actions/get-content-database.ts +1 -0
- package/corpus/templates/content/actions/query-content-database-items.ts +32 -5
- package/corpus/templates/content/actions/set-document-property.ts +17 -11
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -43
- package/corpus/templates/content/app/components/editor/DocumentEditorSkeleton.tsx +159 -50
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +12 -28
- package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +6 -1
- package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +16 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +180 -75
- package/corpus/templates/content/app/components/editor/database/DatabaseViewSkeleton.tsx +76 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +60 -2
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +41 -42
- package/corpus/templates/content/app/components/editor/document-editor-layout.ts +18 -0
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +11 -3
- package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +15 -7
- package/corpus/templates/content/app/components/editor/suggestions/model.ts +13 -0
- package/corpus/templates/content/app/components/editor/suggestions/read-only-blocks.ts +136 -0
- package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
- package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +1 -1
- package/corpus/templates/content/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +57 -16
- package/corpus/templates/content/app/components/sidebar/MovePageDialog.tsx +4 -4
- package/corpus/templates/content/app/components/sidebar/SidebarNavigationRow.tsx +34 -10
- package/corpus/templates/content/app/global.css +16 -8
- package/corpus/templates/content/app/hooks/content-action-refresh.ts +14 -13
- package/corpus/templates/content/app/hooks/use-content-database.ts +72 -9
- package/corpus/templates/content/app/hooks/use-content-personal-navigation.ts +7 -3
- package/corpus/templates/content/app/hooks/use-documents.ts +27 -0
- package/corpus/templates/content/app/i18n-data.ts +3 -2
- package/corpus/templates/content/app/lib/content-landing.ts +3 -31
- package/corpus/templates/content/app/lib/files-navigation.ts +182 -10
- package/corpus/templates/content/app/lib/files-root-hint.ts +20 -32
- package/corpus/templates/content/app/lib/page-startup-hints.ts +108 -0
- package/corpus/templates/content/app/lib/private-link-redirect.ts +25 -0
- package/corpus/templates/content/app/lib/sidebar-layout-hint.ts +34 -1
- package/corpus/templates/content/app/lib/startup-timing.ts +2 -0
- package/corpus/templates/content/app/root.tsx +3 -1
- package/corpus/templates/content/app/routes/_app.home.tsx +10 -19
- package/corpus/templates/content/app/routes/p.$id.tsx +23 -5
- package/corpus/templates/content/changelog/2026-10-02-a-page-link-you-cant-open-now-says-so-instead-of-opening-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-after-a-refresh-the-files-sidebar-shows-the-open-page-s-fold.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-large-collections-open-faster.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-pages-with-open-comments-and-collections-with-sorted-or-filt.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-suggest-edits-works-on-pages-written-by-agents-including-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-10-02-while-you-suggest-edits-tables-and-other-blocks-that-suggest.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-view-context-now-survives-quick-page-changes-when.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-collection-views-keep-their-saved-rows-accurate-during-refre.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-exact-saved-view-links-keep-collection-retry-available.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-expanding-a-files-folder-now-shares-one-navigation-read-acro.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-files-navigation-retries-temporary-failures-consistently.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-shared-page-owners-keep-edit-and-manage-controls-in-files-an.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-tagging-an-ai-in-a-comment-works-again-instead-of-failing-ri.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-the-home-loading-shell-keeps-the-layout-of-your-last-opened-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-05-typing-and-a-space-or-inserting-a-toggle-or-callout-no-longe.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +4 -1
- package/corpus/templates/content/e2e/playwright.config.ts +1 -1
- package/corpus/templates/content/package.json +2 -1
- package/corpus/templates/content/scripts/seed-perf-database.mjs +600 -0
- package/corpus/templates/content/scripts/trace-startup.mjs +25 -3
- package/corpus/templates/content/server/db/index.ts +1 -1
- package/corpus/templates/content/server/lib/suggested-edits.ts +23 -26
- package/corpus/templates/content/server/plugins/auth.ts +2 -1
- package/corpus/templates/content/server/plugins/otel.ts +6 -0
- package/corpus/templates/content/shared/api.ts +17 -0
- package/corpus/templates/content/shared/suggestion-diff.ts +124 -38
- package/corpus/templates/content/shared/suggestion-formatting.ts +134 -3
- package/corpus/templates/crm/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/crm/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/crm/package.json +1 -0
- package/corpus/templates/crm/server/plugins/otel.ts +6 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/design/CHANGELOG.md +41 -0
- package/corpus/templates/design/README.md +2 -2
- package/corpus/templates/design/actions/list-designs.ts +11 -4
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +110 -32
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +28 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -0
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +79 -0
- package/corpus/templates/design/app/components/layout/Header.tsx +2 -4
- package/corpus/templates/design/app/components/ui/tabs.tsx +59 -1
- package/corpus/templates/design/app/global.css +1 -34
- package/corpus/templates/design/app/i18n/en-US.ts +4 -0
- package/corpus/templates/design/app/lib/design-filter.ts +4 -2
- package/corpus/templates/design/app/pages/Index.tsx +91 -59
- package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +58 -17
- package/corpus/templates/design/changelog/2026-10-01-filter-designs-by-owner.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-layers-dropped-into-visible-canvas-space-beyond-a-screen-now.md +6 -0
- package/corpus/templates/design/changelog/2026-10-03-visible-screen-overflow-no-longer-routes-drops-to-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
- package/corpus/templates/design/package.json +1 -0
- package/corpus/templates/design/server/plugins/auth.ts +2 -1
- package/corpus/templates/design/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/dispatch/README.md +2 -2
- package/corpus/templates/dispatch/package.json +1 -0
- package/corpus/templates/dispatch/server/plugins/otel.ts +6 -0
- package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +2 -1
- package/corpus/templates/factory/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/plugins/otel.ts +6 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/forms/README.md +2 -2
- package/corpus/templates/forms/package.json +1 -0
- package/corpus/templates/forms/server/plugins/auth.ts +2 -1
- package/corpus/templates/forms/server/plugins/otel.ts +6 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/mail/CHANGELOG.md +6 -0
- package/corpus/templates/mail/README.md +2 -2
- package/corpus/templates/mail/package.json +1 -0
- package/corpus/templates/mail/server/plugins/auth.ts +2 -1
- package/corpus/templates/mail/server/plugins/otel.ts +6 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/plan/CHANGELOG.md +1 -0
- package/corpus/templates/plan/README.md +2 -2
- package/corpus/templates/plan/package.json +1 -0
- package/corpus/templates/plan/server/plugins/auth.ts +2 -1
- package/corpus/templates/plan/server/plugins/otel.ts +6 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +12 -7
- package/corpus/templates/slides/CHANGELOG.md +23 -0
- package/corpus/templates/slides/README.md +2 -2
- package/corpus/templates/slides/actions/list-decks.ts +11 -4
- package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +44 -36
- package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +79 -0
- package/corpus/templates/slides/app/components/layout/Header.tsx +2 -15
- package/corpus/templates/slides/app/components/ui/tabs.tsx +59 -0
- package/corpus/templates/slides/app/global.css +3 -54
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/lib/deck-filter.ts +5 -2
- package/corpus/templates/slides/app/pages/Index.tsx +102 -88
- package/corpus/templates/slides/changelog/2026-10-01-filter-decks-by-owner.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-02-hide-recent-until-decks-available.md +6 -0
- package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +8 -0
- package/corpus/templates/slides/server/plugins/auth.ts +2 -1
- package/corpus/templates/slides/server/plugins/otel.ts +6 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +9 -2
- package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +12 -7
- package/package.json +1 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useCodeMode } from "@agent-native/core/client/agent-chat";
|
|
2
|
-
import { agentNativePath } from "@agent-native/core/client/api-path";
|
|
3
2
|
import {
|
|
4
3
|
getBrowserTabId,
|
|
5
4
|
setClientAppState,
|
|
@@ -229,6 +228,8 @@ import {
|
|
|
229
228
|
} from "@/hooks/use-documents";
|
|
230
229
|
import { useLocalStorage } from "@/hooks/use-local-storage";
|
|
231
230
|
import { messagesByLocale } from "@/i18n-data";
|
|
231
|
+
import { readPageShapeHint, rememberPageShape } from "@/lib/page-startup-hints";
|
|
232
|
+
import { startupAnchor } from "@/lib/startup-timing";
|
|
232
233
|
import { cn } from "@/lib/utils";
|
|
233
234
|
|
|
234
235
|
import { resolveBuilderCmsWriteEffect } from "../../../../actions/_builder-cms-write-adapter.js";
|
|
@@ -299,9 +300,21 @@ import {
|
|
|
299
300
|
DatabaseTableGrid,
|
|
300
301
|
DatabaseTableLayout,
|
|
301
302
|
} from "./DatabaseTableGrid";
|
|
303
|
+
import {
|
|
304
|
+
DATABASE_VIEW_CLASS_NAME,
|
|
305
|
+
DATABASE_VIEW_CONSTRAINTS_ROW_CLASS_NAME,
|
|
306
|
+
DATABASE_VIEW_TABS_ROW_CLASS_NAME,
|
|
307
|
+
DatabaseViewSkeleton,
|
|
308
|
+
} from "./DatabaseViewSkeleton";
|
|
302
309
|
import { DatabaseFormView } from "./FormView";
|
|
303
310
|
import { DatabaseGalleryView } from "./GalleryView";
|
|
304
311
|
import { DatabaseListView } from "./ListView";
|
|
312
|
+
import {
|
|
313
|
+
DATABASE_NAVIGATION_VISIBLE_ITEM_LIMIT,
|
|
314
|
+
databaseNavigationStateFitsKeepaliveBudget,
|
|
315
|
+
databaseVisibleItemSummaries,
|
|
316
|
+
fitDatabaseNavigationState,
|
|
317
|
+
} from "./navigation-state";
|
|
305
318
|
import {
|
|
306
319
|
databaseItemCanDuplicate,
|
|
307
320
|
databaseItemCanRemoveFromDatabase,
|
|
@@ -895,6 +908,7 @@ function DatabaseTable({
|
|
|
895
908
|
const [hydratedDatabaseId, setHydratedDatabaseId] = useState<string | null>(
|
|
896
909
|
null,
|
|
897
910
|
);
|
|
911
|
+
const [drawnDatabaseId, setDrawnDatabaseId] = useState<string | null>(null);
|
|
898
912
|
const [viewConfig, setViewConfig] = useState<ContentDatabaseViewConfig>(
|
|
899
913
|
defaultDatabaseViewConfig(),
|
|
900
914
|
);
|
|
@@ -985,7 +999,7 @@ function DatabaseTable({
|
|
|
985
999
|
exactRequestedViewId,
|
|
986
1000
|
searchParams.get(viewSelectionSearchParam),
|
|
987
1001
|
);
|
|
988
|
-
const personalViewDatabaseId =
|
|
1002
|
+
const personalViewDatabaseId = databaseId;
|
|
989
1003
|
const newDatabaseRowLabel = isWorkspaceCatalog
|
|
990
1004
|
? t("sidebar.addWorkspace")
|
|
991
1005
|
: dbText("newPage");
|
|
@@ -1348,12 +1362,46 @@ function DatabaseTable({
|
|
|
1348
1362
|
clientQueryExpandedItemLimit,
|
|
1349
1363
|
data?.pagination?.limit ?? items.length,
|
|
1350
1364
|
);
|
|
1365
|
+
// A failed read has no rows to expand, so calendar and timeline views would
|
|
1366
|
+
// otherwise count it as an expansion still pending and never draw.
|
|
1351
1367
|
const isDatabaseViewLoading =
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1368
|
+
!database.itemsFailed &&
|
|
1369
|
+
(isDatabaseInitialLoading ||
|
|
1370
|
+
isClientQueryExpansionPending ||
|
|
1371
|
+
(database.isFetching && Boolean(tableQuery)));
|
|
1372
|
+
// Until the saved view resolves and its first rows land, the view draws its
|
|
1373
|
+
// placeholder; after that, later reads keep the view on screen.
|
|
1374
|
+
const firstViewPending =
|
|
1375
|
+
drawnDatabaseId !== databaseId &&
|
|
1376
|
+
!(
|
|
1377
|
+
hydratedDatabaseId === databaseId &&
|
|
1378
|
+
database.itemsSettled &&
|
|
1379
|
+
!isDatabaseViewLoading
|
|
1380
|
+
);
|
|
1381
|
+
const constraintsBarHeld = databaseConstraintsBarIsVisible({
|
|
1382
|
+
forceShow: false,
|
|
1383
|
+
constraintCount: visibleConstraintCount,
|
|
1384
|
+
filterCount: filters.length,
|
|
1385
|
+
hasPersonalQueryChanges: personalQueryDirty,
|
|
1386
|
+
});
|
|
1355
1387
|
useEffect(() => {
|
|
1356
|
-
if (
|
|
1388
|
+
if (firstViewPending) return;
|
|
1389
|
+
setDrawnDatabaseId(databaseId);
|
|
1390
|
+
if (renderMode === "page") {
|
|
1391
|
+
rememberPageShape(
|
|
1392
|
+
document.id,
|
|
1393
|
+
constraintsBarHeld ? "database-constrained" : "database",
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
}, [
|
|
1397
|
+
constraintsBarHeld,
|
|
1398
|
+
databaseId,
|
|
1399
|
+
document.id,
|
|
1400
|
+
firstViewPending,
|
|
1401
|
+
renderMode,
|
|
1402
|
+
]);
|
|
1403
|
+
useEffect(() => {
|
|
1404
|
+
if (isDatabaseViewLoading || firstViewPending) return;
|
|
1357
1405
|
window.document.documentElement.dataset.contentDatabaseRowsVisibleDocumentId =
|
|
1358
1406
|
document.id;
|
|
1359
1407
|
window.dispatchEvent(
|
|
@@ -1361,7 +1409,7 @@ function DatabaseTable({
|
|
|
1361
1409
|
detail: { documentId: document.id },
|
|
1362
1410
|
}),
|
|
1363
1411
|
);
|
|
1364
|
-
}, [document.id, isDatabaseViewLoading]);
|
|
1412
|
+
}, [document.id, firstViewPending, isDatabaseViewLoading]);
|
|
1365
1413
|
useEffect(() => {
|
|
1366
1414
|
if (clientQueryExpandedItemLimit === databaseRequestItemLimit) return;
|
|
1367
1415
|
setDatabaseRequestItemLimit(clientQueryExpandedItemLimit);
|
|
@@ -1786,17 +1834,23 @@ function DatabaseTable({
|
|
|
1786
1834
|
selectedItems,
|
|
1787
1835
|
previewItem,
|
|
1788
1836
|
});
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1837
|
+
// The route writes a bare navigation state to the same key from Root,
|
|
1838
|
+
// whose effects run after this one in the same commit. Writing after the
|
|
1839
|
+
// commit keeps this fuller state from being overwritten by it.
|
|
1840
|
+
const timer = setTimeout(() => {
|
|
1841
|
+
const navigationState = fitDatabaseNavigationState(state);
|
|
1842
|
+
void setClientAppState(
|
|
1843
|
+
`navigation:${getBrowserTabId()}`,
|
|
1844
|
+
navigationState,
|
|
1845
|
+
{
|
|
1846
|
+
keepalive:
|
|
1847
|
+
databaseNavigationStateFitsKeepaliveBudget(navigationState),
|
|
1848
|
+
},
|
|
1849
|
+
).catch(() => {
|
|
1850
|
+
// Navigation sync is best-effort; the next view change rewrites it.
|
|
1851
|
+
});
|
|
1852
|
+
});
|
|
1853
|
+
return () => clearTimeout(timer);
|
|
1800
1854
|
}, [
|
|
1801
1855
|
activeView,
|
|
1802
1856
|
effectiveFrozenColumnIds,
|
|
@@ -2796,21 +2850,28 @@ function DatabaseTable({
|
|
|
2796
2850
|
orderedProperties,
|
|
2797
2851
|
visibleItems,
|
|
2798
2852
|
]);
|
|
2853
|
+
// The page read already carries the saved views, so the view resolves
|
|
2854
|
+
// without waiting for the rows, and the first rows read is the saved view's.
|
|
2855
|
+
const viewSourceDatabase =
|
|
2856
|
+
data?.database ??
|
|
2857
|
+
(document.database?.id === expectedDatabaseId
|
|
2858
|
+
? document.database
|
|
2859
|
+
: undefined);
|
|
2799
2860
|
useEffect(() => {
|
|
2800
|
-
if (!
|
|
2861
|
+
if (!viewSourceDatabase) return;
|
|
2801
2862
|
if (personalView.isLoading) return;
|
|
2802
2863
|
const localSharedConfig = personalQueryDirty
|
|
2803
2864
|
? databaseViewConfigWithSavedQueryState(viewConfig, savedViewConfig)
|
|
2804
2865
|
: viewConfig;
|
|
2805
2866
|
if (
|
|
2806
|
-
hydratedDatabaseIdRef.current ===
|
|
2807
|
-
databaseViewStateKey(
|
|
2808
|
-
databaseViewStateKey(
|
|
2867
|
+
hydratedDatabaseIdRef.current === viewSourceDatabase.id &&
|
|
2868
|
+
databaseViewStateKey(viewSourceDatabase.id, localSharedConfig) !==
|
|
2869
|
+
databaseViewStateKey(viewSourceDatabase.id, savedViewConfig)
|
|
2809
2870
|
)
|
|
2810
2871
|
return;
|
|
2811
|
-
hydratedDatabaseIdRef.current =
|
|
2872
|
+
hydratedDatabaseIdRef.current = viewSourceDatabase.id;
|
|
2812
2873
|
const nextSavedViewConfig = normalizeClientDatabaseViewConfig(
|
|
2813
|
-
|
|
2874
|
+
viewSourceDatabase.viewConfig,
|
|
2814
2875
|
);
|
|
2815
2876
|
const personalViewConfig = applyPersonalDatabaseViewOverrides(
|
|
2816
2877
|
nextSavedViewConfig,
|
|
@@ -2838,12 +2899,12 @@ function DatabaseTable({
|
|
|
2838
2899
|
);
|
|
2839
2900
|
}
|
|
2840
2901
|
const nextKey = databaseViewStateKey(
|
|
2841
|
-
|
|
2902
|
+
viewSourceDatabase.id,
|
|
2842
2903
|
reconciled.viewConfig,
|
|
2843
2904
|
);
|
|
2844
|
-
setHydratedDatabaseId(
|
|
2845
|
-
const mutationContract = data
|
|
2846
|
-
if (mutationContract && data.configurationRevision) {
|
|
2905
|
+
setHydratedDatabaseId(viewSourceDatabase.id);
|
|
2906
|
+
const mutationContract = data?.mutationContract;
|
|
2907
|
+
if (data && mutationContract && data.configurationRevision) {
|
|
2847
2908
|
const { authorityScope: _authorityScope, ...target } =
|
|
2848
2909
|
mutationContract.target;
|
|
2849
2910
|
viewSetupRevisionRef.current = {
|
|
@@ -2865,13 +2926,14 @@ function DatabaseTable({
|
|
|
2865
2926
|
),
|
|
2866
2927
|
);
|
|
2867
2928
|
setViewConfig((current) =>
|
|
2868
|
-
databaseViewStateKey(
|
|
2929
|
+
databaseViewStateKey(viewSourceDatabase.id, current) === nextKey
|
|
2869
2930
|
? current
|
|
2870
2931
|
: reconciled.viewConfig,
|
|
2871
2932
|
);
|
|
2872
2933
|
}, [
|
|
2934
|
+
viewSourceDatabase?.id,
|
|
2935
|
+
viewSourceDatabase?.viewConfig,
|
|
2873
2936
|
data?.database.id,
|
|
2874
|
-
data?.database.viewConfig,
|
|
2875
2937
|
data?.configurationRevision,
|
|
2876
2938
|
data?.mutationContract,
|
|
2877
2939
|
personalView.data?.overrides,
|
|
@@ -2934,15 +2996,10 @@ function DatabaseTable({
|
|
|
2934
2996
|
viewConfig,
|
|
2935
2997
|
]);
|
|
2936
2998
|
|
|
2937
|
-
const exactViewUnavailable =
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
(!!data &&
|
|
2942
|
-
!resolveRequestedDatabaseView(
|
|
2943
|
-
normalizeClientDatabaseViewConfig(data.database.viewConfig),
|
|
2944
|
-
exactRequestedViewId,
|
|
2945
|
-
)));
|
|
2999
|
+
const exactViewUnavailable = exactRequestedDatabaseViewUnavailable(
|
|
3000
|
+
exactRequestedViewId,
|
|
3001
|
+
database.data,
|
|
3002
|
+
);
|
|
2946
3003
|
useRecordContentVisit(
|
|
2947
3004
|
{ documentId: document.id, databaseId, viewId: activeView.id },
|
|
2948
3005
|
foreground &&
|
|
@@ -3032,9 +3089,38 @@ function DatabaseTable({
|
|
|
3032
3089
|
);
|
|
3033
3090
|
}
|
|
3034
3091
|
|
|
3092
|
+
if (firstViewPending) {
|
|
3093
|
+
// An exact view the page read does not list resolves only from the
|
|
3094
|
+
// collection read, so a failed first read would otherwise hold the
|
|
3095
|
+
// placeholder forever.
|
|
3096
|
+
if (database.itemsFailed && !personalView.isLoading) {
|
|
3097
|
+
return (
|
|
3098
|
+
<QueryErrorState
|
|
3099
|
+
compact
|
|
3100
|
+
onRetry={() => void database.retryItems()}
|
|
3101
|
+
retrying={database.itemsRetrying}
|
|
3102
|
+
/>
|
|
3103
|
+
);
|
|
3104
|
+
}
|
|
3105
|
+
return (
|
|
3106
|
+
<DatabaseViewSkeleton
|
|
3107
|
+
anchored={renderMode === "page"}
|
|
3108
|
+
constraints={
|
|
3109
|
+
hydratedDatabaseId === databaseId
|
|
3110
|
+
? constraintsBarHeld
|
|
3111
|
+
: renderMode === "page" &&
|
|
3112
|
+
readPageShapeHint(document.id) === "database-constrained"
|
|
3113
|
+
}
|
|
3114
|
+
/>
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3035
3118
|
return (
|
|
3036
|
-
<div className=
|
|
3037
|
-
<div
|
|
3119
|
+
<div className={DATABASE_VIEW_CLASS_NAME}>
|
|
3120
|
+
<div
|
|
3121
|
+
{...(renderMode === "page" ? startupAnchor("database-tabs") : {})}
|
|
3122
|
+
className={DATABASE_VIEW_TABS_ROW_CLASS_NAME}
|
|
3123
|
+
>
|
|
3038
3124
|
<DatabaseViewTabs
|
|
3039
3125
|
assetScopeDocumentId={databaseDocumentId}
|
|
3040
3126
|
viewConfig={viewConfig}
|
|
@@ -3293,7 +3379,13 @@ function DatabaseTable({
|
|
|
3293
3379
|
);
|
|
3294
3380
|
})}
|
|
3295
3381
|
|
|
3296
|
-
{
|
|
3382
|
+
{database.itemsFailed ? (
|
|
3383
|
+
<QueryErrorState
|
|
3384
|
+
compact
|
|
3385
|
+
onRetry={() => void database.retryItems()}
|
|
3386
|
+
retrying={database.itemsRetrying}
|
|
3387
|
+
/>
|
|
3388
|
+
) : activeView.type === "form" ? (
|
|
3297
3389
|
<DatabaseFormView
|
|
3298
3390
|
databaseId={databaseId}
|
|
3299
3391
|
databaseDocumentId={document.id}
|
|
@@ -3472,6 +3564,7 @@ function DatabaseTable({
|
|
|
3472
3564
|
/>
|
|
3473
3565
|
) : (
|
|
3474
3566
|
<DatabaseTableView
|
|
3567
|
+
startupAnchored={renderMode === "page"}
|
|
3475
3568
|
columnOrderIds={activeView.tableColumnOrderIds ?? []}
|
|
3476
3569
|
databaseId={databaseId}
|
|
3477
3570
|
databaseSystemRole={data?.database.systemRole}
|
|
@@ -3565,7 +3658,9 @@ function DatabaseTable({
|
|
|
3565
3658
|
/>
|
|
3566
3659
|
)}
|
|
3567
3660
|
|
|
3568
|
-
{hasMoreItems &&
|
|
3661
|
+
{hasMoreItems &&
|
|
3662
|
+
!isClientQueryExpansionPending &&
|
|
3663
|
+
!database.itemsFailed ? (
|
|
3569
3664
|
<div className="flex items-center justify-center border-t border-border/45 py-3">
|
|
3570
3665
|
<Button
|
|
3571
3666
|
type="button"
|
|
@@ -4056,33 +4151,7 @@ export function databaseViewSummaries(
|
|
|
4056
4151
|
}));
|
|
4057
4152
|
}
|
|
4058
4153
|
|
|
4059
|
-
export
|
|
4060
|
-
|
|
4061
|
-
export function databaseVisibleItemSummaries(
|
|
4062
|
-
items: ContentDatabaseItem[],
|
|
4063
|
-
visibleProperties: DocumentProperty[] = [],
|
|
4064
|
-
limit = DATABASE_NAVIGATION_VISIBLE_ITEM_LIMIT,
|
|
4065
|
-
) {
|
|
4066
|
-
return items.slice(0, limit).map((item) => ({
|
|
4067
|
-
itemId: item.id,
|
|
4068
|
-
documentId: item.document.id,
|
|
4069
|
-
title: databaseItemPreviewTitle(item),
|
|
4070
|
-
position: item.position,
|
|
4071
|
-
properties: visibleProperties.map((property) => {
|
|
4072
|
-
const itemProperty =
|
|
4073
|
-
item.properties.find(
|
|
4074
|
-
(candidate) => candidate.definition.id === property.definition.id,
|
|
4075
|
-
) ?? property;
|
|
4076
|
-
return {
|
|
4077
|
-
propertyId: property.definition.id,
|
|
4078
|
-
name: property.definition.name,
|
|
4079
|
-
type: property.definition.type,
|
|
4080
|
-
value: itemProperty.value,
|
|
4081
|
-
text: propertyValueText(itemProperty),
|
|
4082
|
-
};
|
|
4083
|
-
}),
|
|
4084
|
-
}));
|
|
4085
|
-
}
|
|
4154
|
+
export { DATABASE_NAVIGATION_VISIBLE_ITEM_LIMIT, databaseVisibleItemSummaries };
|
|
4086
4155
|
|
|
4087
4156
|
export function databaseCalculationSummaries(
|
|
4088
4157
|
calculations: Record<string, DatabaseColumnCalculation> | undefined,
|
|
@@ -5159,6 +5228,7 @@ function DatabaseTableView({
|
|
|
5159
5228
|
hasSearch,
|
|
5160
5229
|
totalCount,
|
|
5161
5230
|
constrained,
|
|
5231
|
+
startupAnchored,
|
|
5162
5232
|
rowsAreManuallyOrdered,
|
|
5163
5233
|
wrapCells,
|
|
5164
5234
|
columnWrapOverrides,
|
|
@@ -5219,6 +5289,7 @@ function DatabaseTableView({
|
|
|
5219
5289
|
hasSearch: boolean;
|
|
5220
5290
|
totalCount: number;
|
|
5221
5291
|
constrained: boolean;
|
|
5292
|
+
startupAnchored: boolean;
|
|
5222
5293
|
rowsAreManuallyOrdered: boolean;
|
|
5223
5294
|
wrapCells: boolean;
|
|
5224
5295
|
columnWrapOverrides: Record<string, boolean>;
|
|
@@ -5843,6 +5914,7 @@ function DatabaseTableView({
|
|
|
5843
5914
|
>
|
|
5844
5915
|
<DatabaseTableColumnOrder.Provider value={columnOrderIds}>
|
|
5845
5916
|
<div
|
|
5917
|
+
{...(startupAnchored ? startupAnchor("database-table") : {})}
|
|
5846
5918
|
ref={tableViewportRef}
|
|
5847
5919
|
className="relative w-full min-w-0 max-w-full"
|
|
5848
5920
|
>
|
|
@@ -6229,6 +6301,20 @@ export function databaseViewRequiresCompleteClientDataset(args: {
|
|
|
6229
6301
|
);
|
|
6230
6302
|
}
|
|
6231
6303
|
|
|
6304
|
+
export function databaseConstraintsBarIsVisible(args: {
|
|
6305
|
+
forceShow: boolean;
|
|
6306
|
+
constraintCount: number;
|
|
6307
|
+
filterCount: number;
|
|
6308
|
+
hasPersonalQueryChanges: boolean;
|
|
6309
|
+
}) {
|
|
6310
|
+
return (
|
|
6311
|
+
args.forceShow ||
|
|
6312
|
+
args.constraintCount > 0 ||
|
|
6313
|
+
args.filterCount > 0 ||
|
|
6314
|
+
args.hasPersonalQueryChanges
|
|
6315
|
+
);
|
|
6316
|
+
}
|
|
6317
|
+
|
|
6232
6318
|
function DatabaseActiveConstraintsBar({
|
|
6233
6319
|
documentId,
|
|
6234
6320
|
items,
|
|
@@ -6290,10 +6376,12 @@ function DatabaseActiveConstraintsBar({
|
|
|
6290
6376
|
}) {
|
|
6291
6377
|
const filterEntries = filters.map((filter, index) => ({ filter, index }));
|
|
6292
6378
|
if (
|
|
6293
|
-
!
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6379
|
+
!databaseConstraintsBarIsVisible({
|
|
6380
|
+
forceShow,
|
|
6381
|
+
constraintCount,
|
|
6382
|
+
filterCount: filters.length,
|
|
6383
|
+
hasPersonalQueryChanges,
|
|
6384
|
+
})
|
|
6297
6385
|
)
|
|
6298
6386
|
return null;
|
|
6299
6387
|
const hasSearchOrSortConstraints =
|
|
@@ -6308,7 +6396,9 @@ function DatabaseActiveConstraintsBar({
|
|
|
6308
6396
|
const hasSortFilterDivider = sorts.length > 0 && filterEntries.length > 0;
|
|
6309
6397
|
|
|
6310
6398
|
return (
|
|
6311
|
-
<ContentTableConstraintBar
|
|
6399
|
+
<ContentTableConstraintBar
|
|
6400
|
+
className={DATABASE_VIEW_CONSTRAINTS_ROW_CLASS_NAME}
|
|
6401
|
+
>
|
|
6312
6402
|
{sorts.map((sort, index) => (
|
|
6313
6403
|
<DatabaseInlineSortControl
|
|
6314
6404
|
key={`${sort.key}-${index}`}
|
|
@@ -13616,6 +13706,21 @@ export function resolveRequestedDatabaseView(
|
|
|
13616
13706
|
return selectDatabaseView(config, requestedViewId);
|
|
13617
13707
|
}
|
|
13618
13708
|
|
|
13709
|
+
export function exactRequestedDatabaseViewUnavailable(
|
|
13710
|
+
requestedViewId: string | null | undefined,
|
|
13711
|
+
data: ContentDatabaseResponse | undefined,
|
|
13712
|
+
): boolean {
|
|
13713
|
+
return (
|
|
13714
|
+
!!requestedViewId &&
|
|
13715
|
+
(isContentDatabaseUnavailable(data) ||
|
|
13716
|
+
(!!data &&
|
|
13717
|
+
!resolveRequestedDatabaseView(
|
|
13718
|
+
normalizeClientDatabaseViewConfig(data.database.viewConfig),
|
|
13719
|
+
requestedViewId,
|
|
13720
|
+
)))
|
|
13721
|
+
);
|
|
13722
|
+
}
|
|
13723
|
+
|
|
13619
13724
|
export function addDatabaseView(
|
|
13620
13725
|
config: ContentDatabaseViewConfig,
|
|
13621
13726
|
name: string,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
import { startupAnchor } from "@/lib/startup-timing";
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
export const DATABASE_VIEW_CLASS_NAME =
|
|
6
|
+
"mt-4 min-w-0 w-full max-w-[calc(100vw-var(--content-sidebar-width,0px)-1.5rem)]";
|
|
7
|
+
|
|
8
|
+
export const DATABASE_VIEW_TABS_ROW_CLASS_NAME =
|
|
9
|
+
"mb-1 flex min-h-8 flex-wrap items-center justify-between gap-x-3 gap-y-1 pb-1";
|
|
10
|
+
|
|
11
|
+
export const DATABASE_VIEW_CONSTRAINTS_ROW_CLASS_NAME =
|
|
12
|
+
"min-h-8 gap-1 py-0.5 text-muted-foreground";
|
|
13
|
+
|
|
14
|
+
const STARTUP_CONSTRAINTS_ROW_CLASS_NAME =
|
|
15
|
+
"hidden [html[data-content-page-shape=database-constrained]_&]:flex";
|
|
16
|
+
|
|
17
|
+
const PLACEHOLDER_ROW_WIDTHS = ["w-2/5", "w-1/3", "w-1/2", "w-1/4", "w-2/5"];
|
|
18
|
+
|
|
19
|
+
// A collection draws these boxes until its saved view and that view's first
|
|
20
|
+
// rows are in, so the tabs, the sort and filter row, and the table sit where
|
|
21
|
+
// the view will draw them. Rows from before the saved order arrives would
|
|
22
|
+
// draw in stored order and then jump.
|
|
23
|
+
export function DatabaseViewSkeleton({
|
|
24
|
+
constraints,
|
|
25
|
+
anchored = true,
|
|
26
|
+
}: {
|
|
27
|
+
constraints: boolean | "startup";
|
|
28
|
+
anchored?: boolean;
|
|
29
|
+
}) {
|
|
30
|
+
return (
|
|
31
|
+
<div className={DATABASE_VIEW_CLASS_NAME}>
|
|
32
|
+
<div
|
|
33
|
+
{...(anchored ? startupAnchor("database-tabs") : {})}
|
|
34
|
+
className={DATABASE_VIEW_TABS_ROW_CLASS_NAME}
|
|
35
|
+
>
|
|
36
|
+
<Skeleton className="h-5 w-24" />
|
|
37
|
+
<div className="flex min-h-8 items-center justify-end gap-1">
|
|
38
|
+
<Skeleton className="size-7 rounded-md" />
|
|
39
|
+
<Skeleton className="size-7 rounded-md" />
|
|
40
|
+
<Skeleton className="size-7 rounded-md" />
|
|
41
|
+
<Skeleton className="h-7 w-14 rounded-md" />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
{constraints ? (
|
|
45
|
+
<div
|
|
46
|
+
className={cn(
|
|
47
|
+
"flex min-w-0 items-center",
|
|
48
|
+
DATABASE_VIEW_CONSTRAINTS_ROW_CLASS_NAME,
|
|
49
|
+
constraints === "startup" && STARTUP_CONSTRAINTS_ROW_CLASS_NAME,
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
<Skeleton className="h-7 w-28 rounded" />
|
|
53
|
+
<Skeleton className="h-7 w-32 rounded" />
|
|
54
|
+
</div>
|
|
55
|
+
) : null}
|
|
56
|
+
<div
|
|
57
|
+
{...(anchored ? startupAnchor("database-table") : {})}
|
|
58
|
+
className="w-full min-w-0 border-t border-border/35"
|
|
59
|
+
>
|
|
60
|
+
<div className="flex h-8 items-center gap-6 border-b border-border/35 px-2">
|
|
61
|
+
<Skeleton className="h-3 w-16" />
|
|
62
|
+
<Skeleton className="h-3 w-20" />
|
|
63
|
+
<Skeleton className="h-3 w-14" />
|
|
64
|
+
</div>
|
|
65
|
+
{PLACEHOLDER_ROW_WIDTHS.map((width, index) => (
|
|
66
|
+
<div
|
|
67
|
+
key={index}
|
|
68
|
+
className="flex h-9 items-center border-b border-border/35 px-2"
|
|
69
|
+
>
|
|
70
|
+
<Skeleton className={cn("h-3.5", width)} />
|
|
71
|
+
</div>
|
|
72
|
+
))}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -39,6 +39,12 @@ export function databaseViewSummaries(
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export const DATABASE_NAVIGATION_VISIBLE_ITEM_LIMIT = 50;
|
|
42
|
+
export const DATABASE_NAVIGATION_CELL_TEXT_LIMIT = 200;
|
|
43
|
+
/**
|
|
44
|
+
* Navigation state is rewritten on every table change and read into the
|
|
45
|
+
* agent's context on every turn.
|
|
46
|
+
*/
|
|
47
|
+
export const DATABASE_NAVIGATION_STATE_MAX_BYTES = 48 * 1024;
|
|
42
48
|
|
|
43
49
|
export function databaseVisibleItemSummaries(
|
|
44
50
|
items: ContentDatabaseItem[],
|
|
@@ -55,17 +61,69 @@ export function databaseVisibleItemSummaries(
|
|
|
55
61
|
item.properties.find(
|
|
56
62
|
(candidate) => candidate.definition.id === property.definition.id,
|
|
57
63
|
) ?? property;
|
|
64
|
+
const text = propertyValueText(itemProperty);
|
|
65
|
+
const truncated = text.length > DATABASE_NAVIGATION_CELL_TEXT_LIMIT;
|
|
66
|
+
const value = itemProperty.value;
|
|
67
|
+
const valueRepeatsText =
|
|
68
|
+
(value === null || typeof value !== "object") &&
|
|
69
|
+
String(value ?? "") === text;
|
|
58
70
|
return {
|
|
59
71
|
propertyId: property.definition.id,
|
|
60
72
|
name: property.definition.name,
|
|
61
73
|
type: property.definition.type,
|
|
62
|
-
|
|
63
|
-
text:
|
|
74
|
+
...(valueRepeatsText ? {} : { value }),
|
|
75
|
+
text: truncated
|
|
76
|
+
? `${text.slice(0, DATABASE_NAVIGATION_CELL_TEXT_LIMIT)}…`
|
|
77
|
+
: text,
|
|
78
|
+
...(truncated ? { textTruncated: true } : {}),
|
|
64
79
|
};
|
|
65
80
|
}),
|
|
66
81
|
}));
|
|
67
82
|
}
|
|
68
83
|
|
|
84
|
+
function jsonByteLength(value: unknown) {
|
|
85
|
+
return new TextEncoder().encode(JSON.stringify(value)).length;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function databaseNavigationStateFitsKeepaliveBudget(value: unknown) {
|
|
89
|
+
return jsonByteLength(value) <= DATABASE_NAVIGATION_STATE_MAX_BYTES;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Keep the largest row prefix whose state fits the byte budget, and report
|
|
94
|
+
* the applied cap in `databaseVisibleItemLimit` so a trimmed summary is never
|
|
95
|
+
* mistaken for the whole visible slice. Rows are the only part that grows
|
|
96
|
+
* with the collection. The view's own settings stay whole even when they
|
|
97
|
+
* alone pass the budget: dropping a sort or filter would describe a
|
|
98
|
+
* different view to the agent.
|
|
99
|
+
*/
|
|
100
|
+
export function fitDatabaseNavigationState<
|
|
101
|
+
State extends {
|
|
102
|
+
databaseVisibleItems?: unknown[];
|
|
103
|
+
databaseSelectedItems?: unknown[];
|
|
104
|
+
databaseVisibleItemLimit?: number;
|
|
105
|
+
},
|
|
106
|
+
>(state: State, maxBytes = DATABASE_NAVIGATION_STATE_MAX_BYTES): State {
|
|
107
|
+
if (jsonByteLength(state) <= maxBytes) return state;
|
|
108
|
+
const withRowCap = (cap: number): State => ({
|
|
109
|
+
...state,
|
|
110
|
+
databaseVisibleItems: state.databaseVisibleItems?.slice(0, cap),
|
|
111
|
+
databaseSelectedItems: state.databaseSelectedItems?.slice(0, cap),
|
|
112
|
+
databaseVisibleItemLimit: cap,
|
|
113
|
+
});
|
|
114
|
+
let fits = 0;
|
|
115
|
+
let tooBig = Math.max(
|
|
116
|
+
state.databaseVisibleItems?.length ?? 0,
|
|
117
|
+
state.databaseSelectedItems?.length ?? 0,
|
|
118
|
+
);
|
|
119
|
+
while (tooBig - fits > 1) {
|
|
120
|
+
const cap = Math.floor((fits + tooBig) / 2);
|
|
121
|
+
if (jsonByteLength(withRowCap(cap)) <= maxBytes) fits = cap;
|
|
122
|
+
else tooBig = cap;
|
|
123
|
+
}
|
|
124
|
+
return withRowCap(fits);
|
|
125
|
+
}
|
|
126
|
+
|
|
69
127
|
export function databaseNavigationState({
|
|
70
128
|
document,
|
|
71
129
|
databaseId,
|