@agent-native/core 0.133.2 → 0.133.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/use-action.ts +6 -0
- package/corpus/templates/content/actions/_batch-utils.ts +33 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -81
- package/corpus/templates/content/actions/_content-files.ts +31 -21
- package/corpus/templates/content/actions/_database-source-utils.ts +653 -155
- package/corpus/templates/content/actions/_database-utils.ts +535 -41
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +291 -240
- package/corpus/templates/content/actions/add-database-item.ts +15 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +156 -58
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +2 -2
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +4 -1
- package/corpus/templates/content/actions/delete-database-items.ts +8 -2
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +2 -2
- package/corpus/templates/content/actions/duplicate-database-item.ts +15 -1
- package/corpus/templates/content/actions/duplicate-database-items.ts +19 -1
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +2 -1
- package/corpus/templates/content/actions/get-content-database.ts +12 -64
- package/corpus/templates/content/actions/move-database-item.ts +4 -1
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +1 -1
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +4 -8
- package/corpus/templates/content/actions/preview-content-database-source-attach.ts +92 -0
- package/corpus/templates/content/actions/process-builder-body-hydration.ts +2 -1
- package/corpus/templates/content/actions/query-content-database-items.ts +64 -0
- package/corpus/templates/content/actions/refresh-content-database-source.ts +7 -0
- package/corpus/templates/content/actions/review-content-database-source-change-set.ts +1 -1
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +1 -1
- package/corpus/templates/content/actions/stage-builder-revision.ts +1 -1
- package/corpus/templates/content/actions/update-content-database-personal-view.ts +29 -3
- package/corpus/templates/content/actions/update-content-database-view.ts +1 -1
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +3 -22
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +267 -105
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +82 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +285 -24
- package/corpus/templates/content/app/hooks/use-document-properties.ts +7 -6
- package/corpus/templates/content/app/i18n-data.ts +10 -0
- package/corpus/templates/content/changelog/2026-07-29-large-databases-keep-useful-rows-visible.md +6 -0
- package/corpus/templates/content/changelog/2026-07-30-builder-source-columns-now-appear-immediately-when-connected.md +6 -0
- package/corpus/templates/content/changelog/2026-07-30-large-builder-backed-tables-show-useful-rows-sooner-and-fini.md +6 -0
- package/corpus/templates/content/changelog/2026-08-01-large-builder-databases-now-show-rows-immediately-and-finish.md +6 -0
- package/corpus/templates/content/parity/matrix.md +2 -1
- package/corpus/templates/content/parity/matrix.ts +25 -0
- package/corpus/templates/content/shared/api.ts +54 -4
- package/corpus/templates/content/shared/database-query.ts +359 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +6 -0
- package/dist/client/use-action.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
- package/src/client/use-action.ts +6 -0
|
@@ -10,6 +10,7 @@ This generated matrix tracks whether high-value Content UI operations use the sa
|
|
|
10
10
|
| database.private-preview-drafts | database | Persist and reconcile a user's private database-page preview draft | action-backed | `get-preview-document-draft`, `update-preview-document-draft` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-documents.ts` | A user's private preview draft is read, saved, conflict-checked, or deleted without changing the shared database page until the normal save flow applies it. | These per-user editor-state actions are intentionally hidden from agent tools because preview drafts are a private UI recovery mechanism. | - | P1 | covered | `actions/preview-document-draft.db.test.ts` | - | - |
|
|
11
11
|
| database.properties-and-view-config | database | Configure properties, values, ordering, and saved views | action-backed | `configure-document-property`, `delete-document-property`, `duplicate-document-property`, `get-content-database-personal-view`, `list-document-properties`, `reorder-document-property`, `set-document-property`, `update-content-database-personal-view`, `update-content-database-view` | `app/components/editor/DocumentProperties.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-document-properties.ts` | Property schemas, property values, property order, filters, sorts, grouping, hidden columns, view type, and view settings are stored. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
|
|
12
12
|
| database.rows | database | Add, duplicate, move, open, and delete database rows | action-backed | `add-database-item`, `delete-database-items`, `delete-document`, `duplicate-database-items`, `duplicate-database-item`, `move-database-item`, `set-document-property` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx` | Database row backing documents and row ordering are created, duplicated, moved, edited, and deleted. | - | - | P0 | covered | `actions/database-row-batch-actions.db.test.ts`, `parity/__tests__/database-row-batch-reliability.test.ts` | `database-bulk-row-reliability` | - |
|
|
13
|
+
| database.table-query-page | database | Query one constrained page while retaining database metadata | action-backed | `query-content-database-items` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | - | This UI-only bounded projection is intentionally hidden with agentTool: false; agents use get-content-database for the complete database contract. | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `app/hooks/use-content-database.test.ts` | - | - |
|
|
13
14
|
| editor.agent-assist-prompts | editor | Ask AI from slash generation or comment context | client-assist | - | `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/CommentsSidebar.tsx` | No direct durable mutation; the prompt asks the agent to use document actions when it decides to write. | - | - | P1 | none | - | - | - |
|
|
14
15
|
| editor.client-formatting-and-insertions | editor | Rich text formatting, selection state, slash block insertion, and copy actions | client-only-ephemeral | - | `app/components/editor/BubbleToolbar.tsx`, `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/DocumentToolbar.tsx` | - | - | - | P1 | none | - | - | - |
|
|
15
16
|
| editor.document-body-and-title | editor | Edit document title, body, icon, image alt text, and precise text | action-backed | `edit-document`, `pull-document`, `set-image-alt-text`, `transcribe-media`, `update-document` | `app/components/editor/DocumentEditor.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/extensions/ImageBlock.tsx`, `app/components/editor/SlashCommandMenu.tsx` | Document content, title, icon, image metadata, and text replacements are saved to the same document source. | - | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `actions/_local-file-documents.test.ts` | `document-search-edit` | - |
|
|
@@ -26,7 +27,7 @@ This generated matrix tracks whether high-value Content UI operations use the sa
|
|
|
26
27
|
| source-sync.builder-cms-review-and-write-gates | source-sync | Review, stage, validate, cancel, and execute Builder CMS source writes | action-backed | `cancel-prepared-builder-source-update`, `execute-builder-source-batch`, `execute-builder-source-execution`, `prepare-builder-source-execution`, `prepare-builder-source-review`, `preview-builder-source-review`, `review-content-database-source-change-set`, `set-content-database-source-write-mode`, `stage-builder-source-bulk-update`, `stage-builder-revision`, `validate-builder-source-execution` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/components/editor/database-sources/BuilderSourceReviewDialog.tsx` | Builder source write mode, staged reviews, pre-dispatch cancellations, validation records, and bounded execution records are created through guarded actions. | - | - | P0 | covered | `actions/builder-source-review-gates.db.test.ts`, `actions/cancel-prepared-builder-source-update.db.test.ts`, `actions/execute-builder-source-execution.test.ts`, `actions/stage-builder-source-bulk-update.db.test.ts` | `builder-source-review-readonly` | - |
|
|
27
28
|
| source-sync.builder-documents | source-sync | List, pull, check, and push Builder docs/blog MDX documents | action-backed | `check-builder-doc`, `list-builder-docs`, `pull-builder-doc`, `push-builder-doc` | `actions/list-builder-docs.ts`, `actions/pull-builder-doc.ts`, `actions/check-builder-doc.ts`, `actions/push-builder-doc.ts` | Builder docs/blog entries can be read into Content, checked locally, and pushed through guarded Builder document actions. | - | - | P1 | seeded | - | - | - |
|
|
28
29
|
| source-sync.builder-required-field-materialization | source-sync | Add required Builder publishing fields to a connected collection | action-backed | `materialize-builder-required-fields` | `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Required Builder fields are materialized as editable Content properties in one local mutation. | This bounded safe-model setup action is intentionally hidden from the agent tool list; the visible source settings surface invokes it. | - | P1 | covered | `actions/materialize-builder-required-fields.test.ts` | - | - |
|
|
29
|
-
| source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `list-notion-database-sources`, `refresh-content-database-source`, `suggest-source-join-key`
|
|
30
|
+
| source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `list-notion-database-sources`, `preview-content-database-source-attach`, `refresh-content-database-source`, `suggest-source-join-key` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/DocumentProperties.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Mounted database source metadata, fields, source role, join keys, and source-field/property bindings are stored and refreshed. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
|
|
30
31
|
| source-sync.provider-api-and-staged-datasets | source-sync | Inspect provider APIs and stage/query/delete large provider datasets | action-backed | `delete-staged-dataset`, `list-staged-datasets`, `provider-api-catalog`, `provider-api-docs`, `provider-api-request`, `query-staged-dataset` | `actions/provider-api-catalog.ts`, `actions/provider-api-docs.ts`, `actions/provider-api-request.ts`, `actions/query-staged-dataset.ts` | Provider API metadata and staged dataset scratch storage support scoped agent/source analysis. | - | - | P1 | seeded | - | - | - |
|
|
31
32
|
| versions.history-and-restore | versions | Open version history and restore a previous document version | action-backed | `list-document-versions`, `restore-document-version` | `app/components/editor/VersionHistoryPanel.tsx`, `app/hooks/use-document-versions.ts` | Document versions are listed and selected versions can restore the document while snapshotting current state. | - | - | P0 | seeded | - | - | - |
|
|
32
33
|
| workspace.spaces-and-files-catalog | workspace | Provision, navigate, and delete Content spaces through Files and Workspaces with personal expansion state | action-backed | `backfill-content-files`, `create-content-space`, `delete-content-space`, `ensure-content-spaces`, `get-content-sidebar-state`, `list-content-spaces`, `update-content-sidebar-state` | `app/components/sidebar/DocumentSidebar.tsx`, `app/hooks/use-content-spaces.ts` | Personal and organization spaces, user-created workspaces, their canonical Files databases, the personal Workspaces catalog, and each user's sidebar expansion state are stored and reconciled in SQL; deleting a user-created workspace atomically removes its catalog row and contents. | - | - | P0 | covered | `actions/content-spaces.db.test.ts`, `actions/content-files.db.test.ts`, `actions/content-sidebar-state.test.ts` | - | - |
|
|
@@ -266,6 +266,30 @@ export const parityMatrix: ParityRow[] = [
|
|
|
266
266
|
coverageRefs: ["actions/content-database-lifecycle.db.test.ts"],
|
|
267
267
|
evalScenarioIds: ["database-source-scope"],
|
|
268
268
|
},
|
|
269
|
+
{
|
|
270
|
+
id: "database.table-query-page",
|
|
271
|
+
surface: "database",
|
|
272
|
+
label: "Query one constrained page while retaining database metadata",
|
|
273
|
+
uiEntrypoints: [
|
|
274
|
+
"app/components/editor/database/DatabaseView.tsx",
|
|
275
|
+
"app/hooks/use-content-database.ts",
|
|
276
|
+
],
|
|
277
|
+
durableEffect: null,
|
|
278
|
+
uiImplementation:
|
|
279
|
+
"The table view loads changed search, filter, and sort results through a page-only action while the base database response remains visible.",
|
|
280
|
+
status: "action-backed",
|
|
281
|
+
actions: ["query-content-database-items"],
|
|
282
|
+
exception:
|
|
283
|
+
"This UI-only bounded projection is intentionally hidden with agentTool: false; agents use get-content-database for the complete database contract.",
|
|
284
|
+
reliabilityRisk: "none",
|
|
285
|
+
spinePriority: "P0",
|
|
286
|
+
testCoverage: "covered",
|
|
287
|
+
followUpPR: null,
|
|
288
|
+
coverageRefs: [
|
|
289
|
+
"actions/content-database-lifecycle.db.test.ts",
|
|
290
|
+
"app/hooks/use-content-database.test.ts",
|
|
291
|
+
],
|
|
292
|
+
},
|
|
269
293
|
{
|
|
270
294
|
id: "database.form-submissions",
|
|
271
295
|
surface: "database",
|
|
@@ -402,6 +426,7 @@ export const parityMatrix: ParityRow[] = [
|
|
|
402
426
|
"get-content-database-source",
|
|
403
427
|
"list-builder-cms-models",
|
|
404
428
|
"list-notion-database-sources",
|
|
429
|
+
"preview-content-database-source-attach",
|
|
405
430
|
"refresh-content-database-source",
|
|
406
431
|
"suggest-source-join-key",
|
|
407
432
|
],
|
|
@@ -276,6 +276,13 @@ export interface ContentDatabaseFilter {
|
|
|
276
276
|
parentFilterGroupId?: string;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
export interface ContentDatabaseTableQuery {
|
|
280
|
+
search: string;
|
|
281
|
+
filters: ContentDatabaseFilter[];
|
|
282
|
+
sorts: ContentDatabaseSort[];
|
|
283
|
+
filterMode: ContentDatabaseFilterMode;
|
|
284
|
+
}
|
|
285
|
+
|
|
279
286
|
export type ContentDatabaseColumnCalculation =
|
|
280
287
|
| "count_all"
|
|
281
288
|
| "count_values"
|
|
@@ -707,6 +714,10 @@ export interface ContentDatabaseSource {
|
|
|
707
714
|
fields: ContentDatabaseSourceFieldMapping[];
|
|
708
715
|
rows: ContentDatabaseSourceRow[];
|
|
709
716
|
changeSets: ContentDatabaseSourceChangeSet[];
|
|
717
|
+
projection?: {
|
|
718
|
+
rows: "complete" | "page";
|
|
719
|
+
changeSets: "complete" | "page";
|
|
720
|
+
};
|
|
710
721
|
bodyHydration?: ContentDatabaseBodyHydrationSummary;
|
|
711
722
|
}
|
|
712
723
|
|
|
@@ -774,17 +785,32 @@ export interface ContentDatabaseResponse {
|
|
|
774
785
|
hasMore: boolean;
|
|
775
786
|
};
|
|
776
787
|
createdItemId?: string;
|
|
788
|
+
createdItem?: ContentDatabaseItem;
|
|
777
789
|
createdDocumentId?: string;
|
|
778
790
|
createdDocumentUpdatedAt?: string;
|
|
779
791
|
duplicatedItemId?: string;
|
|
780
792
|
duplicatedDocumentId?: string;
|
|
781
793
|
duplicatedItemIds?: string[];
|
|
794
|
+
duplicatedItems?: ContentDatabaseItem[];
|
|
782
795
|
duplicatedDocumentIds?: string[];
|
|
783
796
|
deletedItemIds?: string[];
|
|
784
797
|
deletedDocumentIds?: string[];
|
|
785
798
|
timings?: BuilderActionTiming[];
|
|
799
|
+
tableQueryMode?: "server" | "client-required";
|
|
800
|
+
/** Client-only optimistic state while real provider rows are being attached. */
|
|
801
|
+
attachPreview?: {
|
|
802
|
+
sourceTable: string;
|
|
803
|
+
fetchedAt: string;
|
|
804
|
+
importedItemCount?: number;
|
|
805
|
+
complete?: boolean;
|
|
806
|
+
};
|
|
786
807
|
}
|
|
787
808
|
|
|
809
|
+
export type ContentDatabaseItemsPageResponse = Pick<
|
|
810
|
+
ContentDatabaseResponse,
|
|
811
|
+
"items" | "source" | "sources" | "pagination" | "tableQueryMode"
|
|
812
|
+
>;
|
|
813
|
+
|
|
788
814
|
export interface BuilderActionTiming {
|
|
789
815
|
name: string;
|
|
790
816
|
durationMs: number;
|
|
@@ -897,6 +923,8 @@ export interface AttachContentDatabaseSourceRequest {
|
|
|
897
923
|
sourceType?: ContentDatabaseSourceType;
|
|
898
924
|
sourceName?: string;
|
|
899
925
|
sourceTable?: string;
|
|
926
|
+
/** Projected Builder model fields already visible in the model picker. */
|
|
927
|
+
builderFieldPaths?: string[];
|
|
900
928
|
/** "items" adds more rows; "details" joins fields onto existing rows. */
|
|
901
929
|
relationshipMode?: "items" | "details";
|
|
902
930
|
join?: ContentDatabaseSourceJoinRequest;
|
|
@@ -906,6 +934,31 @@ export interface AttachContentDatabaseSourceRequest {
|
|
|
906
934
|
offset?: number;
|
|
907
935
|
}
|
|
908
936
|
|
|
937
|
+
export interface ContentDatabaseSourceAttachmentAck {
|
|
938
|
+
responseProjection: "ack";
|
|
939
|
+
databaseId: string;
|
|
940
|
+
documentId: string;
|
|
941
|
+
sourceId: string;
|
|
942
|
+
sourceType: ContentDatabaseSourceType;
|
|
943
|
+
sourceTable: string;
|
|
944
|
+
importedItemCount: number;
|
|
945
|
+
fetchedAt: string;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export type ContentDatabaseSourceAttachmentResult =
|
|
949
|
+
| ContentDatabaseResponse
|
|
950
|
+
| ContentDatabaseSourceAttachmentAck;
|
|
951
|
+
|
|
952
|
+
export interface BuilderCmsAttachPreviewResponse {
|
|
953
|
+
databaseId: string;
|
|
954
|
+
documentId: string;
|
|
955
|
+
sourceTable: string;
|
|
956
|
+
base: ContentDatabaseResponse;
|
|
957
|
+
items: ContentDatabaseItem[];
|
|
958
|
+
fetchedAt: string;
|
|
959
|
+
hasMore: boolean;
|
|
960
|
+
}
|
|
961
|
+
|
|
909
962
|
export interface ChangeContentDatabaseSourceRoleRequest {
|
|
910
963
|
databaseId?: string;
|
|
911
964
|
documentId?: string;
|
|
@@ -985,6 +1038,7 @@ export interface RefreshContentDatabaseSourceRequest {
|
|
|
985
1038
|
documentId?: string;
|
|
986
1039
|
sourceId?: string;
|
|
987
1040
|
fullRefresh?: boolean;
|
|
1041
|
+
finishBuilderPagination?: boolean;
|
|
988
1042
|
expectedBuilderContinuationOffset?: number;
|
|
989
1043
|
}
|
|
990
1044
|
|
|
@@ -1259,10 +1313,6 @@ export interface PreviewBuilderSourceReviewResponse {
|
|
|
1259
1313
|
}
|
|
1260
1314
|
|
|
1261
1315
|
export interface PrepareBuilderSourceReviewResponse {
|
|
1262
|
-
database: ContentDatabase;
|
|
1263
|
-
properties: DocumentProperty[];
|
|
1264
|
-
items: ContentDatabaseItem[];
|
|
1265
|
-
source: ContentDatabaseSource | null;
|
|
1266
1316
|
review: ContentDatabaseSourceReviewPayload;
|
|
1267
1317
|
/**
|
|
1268
1318
|
* Maps the operator-selected diff identities to the immutable change-set
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ContentDatabaseFilter,
|
|
3
|
+
ContentDatabaseFilterMode,
|
|
4
|
+
ContentDatabaseItem,
|
|
5
|
+
ContentDatabaseSort,
|
|
6
|
+
ContentDatabaseTableQuery,
|
|
7
|
+
DocumentProperty,
|
|
8
|
+
} from "./api.js";
|
|
9
|
+
import { documentPropertyDatePart, formulaValueText } from "./properties.js";
|
|
10
|
+
|
|
11
|
+
export function applyContentDatabaseTableQuery(
|
|
12
|
+
items: ContentDatabaseItem[],
|
|
13
|
+
properties: DocumentProperty[],
|
|
14
|
+
query: ContentDatabaseTableQuery,
|
|
15
|
+
) {
|
|
16
|
+
const search = query.search.trim().toLowerCase();
|
|
17
|
+
const searched = search
|
|
18
|
+
? items.filter((item) =>
|
|
19
|
+
itemSearchText(item, properties).toLowerCase().includes(search),
|
|
20
|
+
)
|
|
21
|
+
: items;
|
|
22
|
+
const activeFilters = query.filters.filter(isActiveFilter);
|
|
23
|
+
const filtered = activeFilters.length
|
|
24
|
+
? searched.filter((item) =>
|
|
25
|
+
itemMatchesFilterTree(
|
|
26
|
+
item,
|
|
27
|
+
properties,
|
|
28
|
+
activeFilters,
|
|
29
|
+
query.filterMode,
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
: searched;
|
|
33
|
+
|
|
34
|
+
if (query.sorts.length === 0) return filtered;
|
|
35
|
+
return [...filtered].sort((left, right) => {
|
|
36
|
+
for (const sort of query.sorts) {
|
|
37
|
+
const comparison = compareSortValues(
|
|
38
|
+
itemSortValue(left, properties, sort),
|
|
39
|
+
itemSortValue(right, properties, sort),
|
|
40
|
+
);
|
|
41
|
+
if (comparison !== 0) {
|
|
42
|
+
return sort.direction === "asc" ? comparison : -comparison;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return 0;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function contentDatabaseTableQueryUsesProperties(
|
|
50
|
+
query: ContentDatabaseTableQuery,
|
|
51
|
+
propertyIds: ReadonlySet<string>,
|
|
52
|
+
) {
|
|
53
|
+
if (propertyIds.size === 0) return false;
|
|
54
|
+
if (query.search.trim()) return true;
|
|
55
|
+
return [...query.filters, ...query.sorts].some(
|
|
56
|
+
(constraint) =>
|
|
57
|
+
constraint.key !== "name" && propertyIds.has(constraint.key),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function itemMatchesFilterTree(
|
|
62
|
+
item: ContentDatabaseItem,
|
|
63
|
+
properties: DocumentProperty[],
|
|
64
|
+
filters: ContentDatabaseFilter[],
|
|
65
|
+
filterMode: ContentDatabaseFilterMode,
|
|
66
|
+
) {
|
|
67
|
+
const rootFilters = filters.filter((filter) => !filter.parentFilterGroupId);
|
|
68
|
+
const nestedGroups = new Map<string, ContentDatabaseFilter[]>();
|
|
69
|
+
for (const filter of filters) {
|
|
70
|
+
if (!filter.parentFilterGroupId || !filter.filterGroupId) continue;
|
|
71
|
+
nestedGroups.set(filter.filterGroupId, [
|
|
72
|
+
...(nestedGroups.get(filter.filterGroupId) ?? []),
|
|
73
|
+
filter,
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
const matches = [
|
|
77
|
+
...rootFilters.map((filter) => itemMatchesFilter(item, properties, filter)),
|
|
78
|
+
...[...nestedGroups.values()].map((group) =>
|
|
79
|
+
combineMatches(
|
|
80
|
+
group.map((filter) => itemMatchesFilter(item, properties, filter)),
|
|
81
|
+
filterMode,
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
];
|
|
85
|
+
return combineMatches(matches, filterMode);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function combineMatches(
|
|
89
|
+
matches: boolean[],
|
|
90
|
+
filterMode: ContentDatabaseFilterMode,
|
|
91
|
+
) {
|
|
92
|
+
if (matches.length === 0) return true;
|
|
93
|
+
return filterMode === "or" ? matches.some(Boolean) : matches.every(Boolean);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isActiveFilter(filter: ContentDatabaseFilter) {
|
|
97
|
+
if (
|
|
98
|
+
!["is_empty", "is_not_empty", "is_checked", "is_unchecked"].includes(
|
|
99
|
+
filter.operator,
|
|
100
|
+
)
|
|
101
|
+
) {
|
|
102
|
+
return selectedFilterValues(filter.value).length > 0;
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function itemMatchesFilter(
|
|
108
|
+
item: ContentDatabaseItem,
|
|
109
|
+
properties: DocumentProperty[],
|
|
110
|
+
filter: ContentDatabaseFilter,
|
|
111
|
+
) {
|
|
112
|
+
const value = itemFilterValue(item, properties, filter.key);
|
|
113
|
+
const property = itemFilterProperty(item, properties, filter.key);
|
|
114
|
+
if (filter.operator === "is_empty") return !value.trim();
|
|
115
|
+
if (filter.operator === "is_not_empty") return !!value.trim();
|
|
116
|
+
if (filter.operator === "is_checked") return property?.value === true;
|
|
117
|
+
if (filter.operator === "is_unchecked") return property?.value !== true;
|
|
118
|
+
|
|
119
|
+
if (filter.operator === "greater_than" || filter.operator === "less_than") {
|
|
120
|
+
const current = propertyNumberValue(property);
|
|
121
|
+
const target = Number(filter.value.trim());
|
|
122
|
+
if (!Number.isFinite(current) || !Number.isFinite(target)) return false;
|
|
123
|
+
return filter.operator === "greater_than"
|
|
124
|
+
? current > target
|
|
125
|
+
: current < target;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
filter.operator === "before" ||
|
|
130
|
+
filter.operator === "after" ||
|
|
131
|
+
filter.operator === "between"
|
|
132
|
+
) {
|
|
133
|
+
const current = propertyDateValue(property);
|
|
134
|
+
if (!Number.isFinite(current)) return false;
|
|
135
|
+
if (filter.operator === "between") {
|
|
136
|
+
const range = filterDateRange(filter.value);
|
|
137
|
+
return !!range && current >= range[0] && current <= range[1];
|
|
138
|
+
}
|
|
139
|
+
const target = new Date(filter.value.trim()).getTime();
|
|
140
|
+
if (!Number.isFinite(target)) return false;
|
|
141
|
+
return filter.operator === "before" ? current < target : current > target;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const candidateValues = itemFilterCandidateValues(
|
|
145
|
+
item,
|
|
146
|
+
properties,
|
|
147
|
+
filter.key,
|
|
148
|
+
).map((candidate) => candidate.trim().toLowerCase());
|
|
149
|
+
const selectedValues = selectedFilterValues(filter.value).map((candidate) =>
|
|
150
|
+
candidate.trim().toLowerCase(),
|
|
151
|
+
);
|
|
152
|
+
const normalizedValue = value.trim().toLowerCase();
|
|
153
|
+
const normalizedFilter = selectedValues[0] ?? "";
|
|
154
|
+
const usesDiscreteValues =
|
|
155
|
+
property?.definition.type === "select" ||
|
|
156
|
+
property?.definition.type === "status" ||
|
|
157
|
+
property?.definition.type === "multi_select" ||
|
|
158
|
+
property?.definition.type === "person";
|
|
159
|
+
if (
|
|
160
|
+
usesDiscreteValues &&
|
|
161
|
+
(filter.operator === "equals" || filter.operator === "contains")
|
|
162
|
+
) {
|
|
163
|
+
return selectedValues.some((filterValue) =>
|
|
164
|
+
candidateValues.includes(filterValue),
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (usesDiscreteValues && filter.operator === "does_not_equal") {
|
|
168
|
+
return selectedValues.every(
|
|
169
|
+
(filterValue) => !candidateValues.includes(filterValue),
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
if (filter.operator === "equals") {
|
|
173
|
+
return candidateValues.includes(normalizedFilter);
|
|
174
|
+
}
|
|
175
|
+
if (filter.operator === "does_not_equal") {
|
|
176
|
+
return !candidateValues.includes(normalizedFilter);
|
|
177
|
+
}
|
|
178
|
+
return normalizedValue.includes(normalizedFilter);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function selectedFilterValues(value: string) {
|
|
182
|
+
const trimmed = value.trim();
|
|
183
|
+
if (!trimmed) return [];
|
|
184
|
+
try {
|
|
185
|
+
const parsed = JSON.parse(trimmed) as unknown;
|
|
186
|
+
if (!Array.isArray(parsed)) return [trimmed];
|
|
187
|
+
return [
|
|
188
|
+
...new Set(
|
|
189
|
+
parsed
|
|
190
|
+
.filter((item): item is string => typeof item === "string")
|
|
191
|
+
.map((item) => item.trim())
|
|
192
|
+
.filter(Boolean),
|
|
193
|
+
),
|
|
194
|
+
];
|
|
195
|
+
} catch {
|
|
196
|
+
return [trimmed];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function filterDateRange(value: string): [number, number] | null {
|
|
201
|
+
const values = selectedFilterValues(value);
|
|
202
|
+
const start = new Date(values[0] ?? "").getTime();
|
|
203
|
+
const end = new Date(values[1] ?? "").getTime();
|
|
204
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
|
|
205
|
+
return start <= end ? [start, end] : [end, start];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function itemSearchText(
|
|
209
|
+
item: ContentDatabaseItem,
|
|
210
|
+
properties: DocumentProperty[],
|
|
211
|
+
) {
|
|
212
|
+
return [
|
|
213
|
+
item.document.title || "Untitled",
|
|
214
|
+
...properties.map((property) =>
|
|
215
|
+
propertyValueText(
|
|
216
|
+
item.properties.find(
|
|
217
|
+
(candidate) => candidate.definition.id === property.definition.id,
|
|
218
|
+
) ?? property,
|
|
219
|
+
),
|
|
220
|
+
),
|
|
221
|
+
].join(" ");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function itemSortValue(
|
|
225
|
+
item: ContentDatabaseItem,
|
|
226
|
+
properties: DocumentProperty[],
|
|
227
|
+
sort: ContentDatabaseSort,
|
|
228
|
+
) {
|
|
229
|
+
if (sort.key === "name") return item.document.title || "";
|
|
230
|
+
return propertyValueText(
|
|
231
|
+
item.properties.find((candidate) => candidate.definition.id === sort.key) ??
|
|
232
|
+
properties.find((candidate) => candidate.definition.id === sort.key) ??
|
|
233
|
+
null,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function itemFilterValue(
|
|
238
|
+
item: ContentDatabaseItem,
|
|
239
|
+
properties: DocumentProperty[],
|
|
240
|
+
key: string,
|
|
241
|
+
) {
|
|
242
|
+
if (key === "name") return item.document.title || "";
|
|
243
|
+
return propertyValueText(itemFilterProperty(item, properties, key));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function itemFilterProperty(
|
|
247
|
+
item: ContentDatabaseItem,
|
|
248
|
+
properties: DocumentProperty[],
|
|
249
|
+
key: string,
|
|
250
|
+
) {
|
|
251
|
+
if (key === "name") return null;
|
|
252
|
+
return (
|
|
253
|
+
item.properties.find((candidate) => candidate.definition.id === key) ??
|
|
254
|
+
properties.find((candidate) => candidate.definition.id === key) ??
|
|
255
|
+
null
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function itemFilterCandidateValues(
|
|
260
|
+
item: ContentDatabaseItem,
|
|
261
|
+
properties: DocumentProperty[],
|
|
262
|
+
key: string,
|
|
263
|
+
) {
|
|
264
|
+
if (key === "name") return [item.document.title || ""];
|
|
265
|
+
const property = itemFilterProperty(item, properties, key);
|
|
266
|
+
if (!property || property.value === null || property.value === undefined) {
|
|
267
|
+
return [""];
|
|
268
|
+
}
|
|
269
|
+
if (Array.isArray(property.value)) {
|
|
270
|
+
return property.value.flatMap((id) => {
|
|
271
|
+
const optionName =
|
|
272
|
+
property.definition.options.options?.find((option) => option.id === id)
|
|
273
|
+
?.name ?? id;
|
|
274
|
+
return [id, optionName];
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (
|
|
278
|
+
property.definition.type === "select" ||
|
|
279
|
+
property.definition.type === "status"
|
|
280
|
+
) {
|
|
281
|
+
const id = String(property.value);
|
|
282
|
+
const optionName =
|
|
283
|
+
property.definition.options.options?.find((option) => option.id === id)
|
|
284
|
+
?.name ?? id;
|
|
285
|
+
return [id, optionName];
|
|
286
|
+
}
|
|
287
|
+
return [propertyValueText(property)];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function propertyValueText(property: DocumentProperty | null | undefined) {
|
|
291
|
+
if (!property || property.value === null || property.value === undefined) {
|
|
292
|
+
return "";
|
|
293
|
+
}
|
|
294
|
+
if (Array.isArray(property.value)) {
|
|
295
|
+
return property.value
|
|
296
|
+
.map(
|
|
297
|
+
(id) =>
|
|
298
|
+
property.definition.options.options?.find(
|
|
299
|
+
(option) => option.id === id,
|
|
300
|
+
)?.name ?? id,
|
|
301
|
+
)
|
|
302
|
+
.join(" ");
|
|
303
|
+
}
|
|
304
|
+
if (
|
|
305
|
+
property.definition.type === "select" ||
|
|
306
|
+
property.definition.type === "status"
|
|
307
|
+
) {
|
|
308
|
+
return (
|
|
309
|
+
property.definition.options.options?.find(
|
|
310
|
+
(option) => option.id === String(property.value),
|
|
311
|
+
)?.name ?? String(property.value)
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
if (property.definition.type === "checkbox") {
|
|
315
|
+
return property.value ? "Checked" : "Unchecked";
|
|
316
|
+
}
|
|
317
|
+
return formulaValueText(property.value);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function compareSortValues(left: string, right: string) {
|
|
321
|
+
const leftNumber = Number(left);
|
|
322
|
+
const rightNumber = Number(right);
|
|
323
|
+
if (
|
|
324
|
+
left.trim() &&
|
|
325
|
+
right.trim() &&
|
|
326
|
+
Number.isFinite(leftNumber) &&
|
|
327
|
+
Number.isFinite(rightNumber)
|
|
328
|
+
) {
|
|
329
|
+
return leftNumber - rightNumber;
|
|
330
|
+
}
|
|
331
|
+
return left.localeCompare(right, undefined, {
|
|
332
|
+
numeric: true,
|
|
333
|
+
sensitivity: "base",
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function propertyNumberValue(property: DocumentProperty | null | undefined) {
|
|
338
|
+
if (
|
|
339
|
+
!property ||
|
|
340
|
+
property.value === null ||
|
|
341
|
+
property.value === undefined ||
|
|
342
|
+
property.value === ""
|
|
343
|
+
) {
|
|
344
|
+
return Number.NaN;
|
|
345
|
+
}
|
|
346
|
+
const value =
|
|
347
|
+
typeof property.value === "number"
|
|
348
|
+
? property.value
|
|
349
|
+
: Number(String(property.value).trim());
|
|
350
|
+
return Number.isFinite(value) ? value : Number.NaN;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function propertyDateValue(property: DocumentProperty | null | undefined) {
|
|
354
|
+
if (!property || !property.value) return Number.NaN;
|
|
355
|
+
const value = new Date(
|
|
356
|
+
documentPropertyDatePart(property.value, "start") || String(property.value),
|
|
357
|
+
).getTime();
|
|
358
|
+
return Number.isFinite(value) ? value : Number.NaN;
|
|
359
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-action.d.ts","sourceRoot":"","sources":["../../src/client/use-action.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAyC/B,mCAAmC;AACnC,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,OAAO,GACb,OAAO,CAaT;AAED,+CAA+C;AAC/C,eAAO,MAAM,8BAA8B,gCAA0B,CAAC;AAwBtE;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEzE;AAMD;;;;;GAKG;AACH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,yBAAyB;KAAG;CACvC;AAED,MAAM,WAAW,cAAe,SAAQ,yBAAyB;CAAG;AAEpE,2FAA2F;AAC3F,KAAK,UAAU,GAAG,MAAM,cAAc,SAAS,KAAK,GAChD,MAAM,GACN,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEpD,8EAA8E;AAC9E,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,cAAc,GAChE,cAAc,CAAC,CAAC,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC3C,CAAC,GACD,GAAG,GACL,GAAG,CAAC;AAER,iGAAiG;AACjG,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,MAAM,cAAc,GAChE,cAAc,CAAC,CAAC,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC3C,CAAC,GACD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACrB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,MAAM,CAMR;
|
|
1
|
+
{"version":3,"file":"use-action.d.ts","sourceRoot":"","sources":["../../src/client/use-action.ts"],"names":[],"mappings":"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"}
|
|
@@ -130,6 +130,12 @@ function appendActionQueryParam(qs, key, value) {
|
|
|
130
130
|
}
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
|
+
if (typeof value === "object") {
|
|
134
|
+
// defineAction restores JSON strings when the schema expects an object.
|
|
135
|
+
// Preserve nested GET params instead of collapsing them to "[object Object]".
|
|
136
|
+
qs.append(key, JSON.stringify(value));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
133
139
|
qs.append(key, String(value));
|
|
134
140
|
}
|
|
135
141
|
/**
|