@osdk/react-components 0.24.0 → 0.24.1-main-4db9a03b6264a0ca7e3e37005540ccfecbf13722
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/CHANGELOG.md +11 -0
- package/build/browser/object-table/ObjectTable.js +16 -1
- package/build/browser/object-table/ObjectTable.js.map +1 -1
- package/build/browser/object-table/ObjectTableApi.js.map +1 -1
- package/build/browser/object-table/hooks/useFunctionColumnsData.js +6 -3
- package/build/browser/object-table/hooks/useFunctionColumnsData.js.map +1 -1
- package/build/browser/object-table/hooks/useObjectTableSnapshotHandle.js +177 -0
- package/build/browser/object-table/hooks/useObjectTableSnapshotHandle.js.map +1 -0
- package/build/browser/object-table/utils/createObjectTableSnapshot.js +86 -0
- package/build/browser/object-table/utils/createObjectTableSnapshot.js.map +1 -0
- package/build/browser/public/experimental/object-table.js.map +1 -1
- package/build/browser/util/UserAgent.js +1 -1
- package/build/browser/util/UserAgent.js.map +1 -1
- package/build/cjs/{chunk-WHQK6LGF.cjs → chunk-7OQ3LWDF.cjs} +4 -4
- package/build/cjs/{chunk-WHQK6LGF.cjs.map → chunk-7OQ3LWDF.cjs.map} +1 -1
- package/build/cjs/{chunk-6VBIVG2S.cjs → chunk-7VOHYM4X.cjs} +4 -4
- package/build/cjs/{chunk-6VBIVG2S.cjs.map → chunk-7VOHYM4X.cjs.map} +1 -1
- package/build/cjs/{chunk-3RQ7SMB7.cjs → chunk-A4X3STEA.cjs} +4 -4
- package/build/cjs/{chunk-3RQ7SMB7.cjs.map → chunk-A4X3STEA.cjs.map} +1 -1
- package/build/cjs/{chunk-VNAQANJG.cjs → chunk-BFQAXTYX.cjs} +4 -4
- package/build/cjs/{chunk-VNAQANJG.cjs.map → chunk-BFQAXTYX.cjs.map} +1 -1
- package/build/cjs/chunk-DWOFAX5C.cjs +11 -0
- package/build/cjs/{chunk-2LYRSORA.cjs.map → chunk-DWOFAX5C.cjs.map} +1 -1
- package/build/cjs/chunk-FUYI343G.cjs +11 -0
- package/build/cjs/{chunk-ZU2UCM2A.cjs.map → chunk-FUYI343G.cjs.map} +1 -1
- package/build/cjs/{chunk-4ZROSLAX.cjs → chunk-JXSEANSA.cjs} +204 -5
- package/build/cjs/chunk-JXSEANSA.cjs.map +1 -0
- package/build/cjs/chunk-KGYGCCIY.cjs +11 -0
- package/build/cjs/{chunk-MO3ERVIS.cjs.map → chunk-KGYGCCIY.cjs.map} +1 -1
- package/build/cjs/{chunk-SNBRMM5V.cjs → chunk-LDH2MMWA.cjs} +4 -4
- package/build/cjs/{chunk-SNBRMM5V.cjs.map → chunk-LDH2MMWA.cjs.map} +1 -1
- package/build/cjs/{chunk-LCLY2BUG.cjs → chunk-M2WI6XDM.cjs} +3 -3
- package/build/cjs/chunk-M2WI6XDM.cjs.map +1 -0
- package/build/cjs/chunk-MA2ALX4L.cjs +11 -0
- package/build/cjs/{chunk-SHVB3GB6.cjs.map → chunk-MA2ALX4L.cjs.map} +1 -1
- package/build/cjs/chunk-T2U4XHCW.cjs +11 -0
- package/build/cjs/{chunk-3NU4IKPJ.cjs.map → chunk-T2U4XHCW.cjs.map} +1 -1
- package/build/cjs/{chunk-XAAQTDES.cjs → chunk-WOM7LHKX.cjs} +4 -4
- package/build/cjs/{chunk-XAAQTDES.cjs.map → chunk-WOM7LHKX.cjs.map} +1 -1
- package/build/cjs/public/experimental/action-form.cjs +4 -4
- package/build/cjs/public/experimental/document-viewer.cjs +4 -4
- package/build/cjs/public/experimental/email-viewer.cjs +3 -3
- package/build/cjs/public/experimental/excel-viewer.cjs +3 -3
- package/build/cjs/public/experimental/filter-list.cjs +14 -14
- package/build/cjs/public/experimental/image-viewer.cjs +3 -3
- package/build/cjs/public/experimental/markdown-renderer.cjs +3 -3
- package/build/cjs/public/experimental/object-table.cjs +8 -8
- package/build/cjs/public/experimental/object-table.d.cts +70 -2
- package/build/cjs/public/experimental/pdf-viewer.cjs +7 -7
- package/build/cjs/public/experimental/tiff-renderer.cjs +3 -3
- package/build/cjs/public/experimental/video-viewer.cjs +3 -3
- package/build/cjs/public/experimental/xml-viewer.cjs +3 -3
- package/build/cjs/public/experimental.cjs +47 -47
- package/build/cjs/public/experimental.d.cts +1 -1
- package/build/esm/object-table/ObjectTable.js +16 -1
- package/build/esm/object-table/ObjectTable.js.map +1 -1
- package/build/esm/object-table/ObjectTableApi.js.map +1 -1
- package/build/esm/object-table/hooks/useFunctionColumnsData.js +6 -3
- package/build/esm/object-table/hooks/useFunctionColumnsData.js.map +1 -1
- package/build/esm/object-table/hooks/useObjectTableSnapshotHandle.js +177 -0
- package/build/esm/object-table/hooks/useObjectTableSnapshotHandle.js.map +1 -0
- package/build/esm/object-table/utils/createObjectTableSnapshot.js +86 -0
- package/build/esm/object-table/utils/createObjectTableSnapshot.js.map +1 -0
- package/build/esm/public/experimental/object-table.js.map +1 -1
- package/build/esm/util/UserAgent.js +1 -1
- package/build/esm/util/UserAgent.js.map +1 -1
- package/build/types/object-table/ObjectTable.d.ts +1 -1
- package/build/types/object-table/ObjectTable.d.ts.map +1 -1
- package/build/types/object-table/ObjectTableApi.d.ts +77 -0
- package/build/types/object-table/ObjectTableApi.d.ts.map +1 -1
- package/build/types/object-table/hooks/useObjectTableSnapshotHandle.d.ts +38 -0
- package/build/types/object-table/hooks/useObjectTableSnapshotHandle.d.ts.map +1 -0
- package/build/types/object-table/utils/createObjectTableSnapshot.d.ts +18 -0
- package/build/types/object-table/utils/createObjectTableSnapshot.d.ts.map +1 -0
- package/build/types/public/experimental/object-table.d.ts +1 -1
- package/build/types/public/experimental/object-table.d.ts.map +1 -1
- package/package.json +8 -8
- package/build/cjs/chunk-2LYRSORA.cjs +0 -11
- package/build/cjs/chunk-3NU4IKPJ.cjs +0 -11
- package/build/cjs/chunk-4ZROSLAX.cjs.map +0 -1
- package/build/cjs/chunk-LCLY2BUG.cjs.map +0 -1
- package/build/cjs/chunk-MO3ERVIS.cjs +0 -11
- package/build/cjs/chunk-SHVB3GB6.cjs +0 -11
- package/build/cjs/chunk-ZU2UCM2A.cjs +0 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @osdk/react-components
|
|
2
2
|
|
|
3
|
+
## 0.24.1-main-4db9a03b6264a0ca7e3e37005540ccfecbf13722
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4db9a03: Add an ObjectTable tableRef snapshot API for reading visible row data and explicitly fetching up to a row limit.
|
|
8
|
+
- c660ee6: ObjectTable: clear a function/derived-property cell when its value disappears from a resolved query result instead of retaining the stale previous value.
|
|
9
|
+
- Updated dependencies [08e921c]
|
|
10
|
+
- @osdk/api@2.29.0-main-4db9a03b6264a0ca7e3e37005540ccfecbf13722
|
|
11
|
+
- @osdk/client@2.29.0-main-4db9a03b6264a0ca7e3e37005540ccfecbf13722
|
|
12
|
+
- @osdk/react@2.29.0-main-4db9a03b6264a0ca7e3e37005540ccfecbf13722
|
|
13
|
+
|
|
3
14
|
## 0.24.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
|
@@ -22,12 +22,14 @@ import { useColumnResize } from "./hooks/useColumnResize.js";
|
|
|
22
22
|
import { useColumnVisibility } from "./hooks/useColumnVisibility.js";
|
|
23
23
|
import { useEditableTable } from "./hooks/useEditableTable.js";
|
|
24
24
|
import { useObjectTableData } from "./hooks/useObjectTableData.js";
|
|
25
|
+
import { useObjectTableSnapshotHandle } from "./hooks/useObjectTableSnapshotHandle.js";
|
|
25
26
|
import { useRowSelection } from "./hooks/useRowSelection.js";
|
|
26
27
|
import { useSelectionColumn } from "./hooks/useSelectionColumn.js";
|
|
27
28
|
import { useTableSorting } from "./hooks/useTableSorting.js";
|
|
28
29
|
import { BaseTable } from "./Table.js";
|
|
29
30
|
import { getRowId } from "./utils/getRowId.js";
|
|
30
31
|
const EMPTY_ARRAY = [];
|
|
32
|
+
|
|
31
33
|
/**
|
|
32
34
|
* ObjectTable - A headless table component for displaying OSDK object sets
|
|
33
35
|
*
|
|
@@ -67,6 +69,7 @@ export function ObjectTable({
|
|
|
67
69
|
enableColumnResizing = true,
|
|
68
70
|
enableColumnConfig = true,
|
|
69
71
|
editMode = "manual",
|
|
72
|
+
tableRef,
|
|
70
73
|
...props
|
|
71
74
|
}) {
|
|
72
75
|
const {
|
|
@@ -86,8 +89,10 @@ export function ObjectTable({
|
|
|
86
89
|
const {
|
|
87
90
|
data,
|
|
88
91
|
fetchMore,
|
|
92
|
+
hasMore,
|
|
89
93
|
isLoading,
|
|
90
94
|
error,
|
|
95
|
+
totalCount,
|
|
91
96
|
objectSet: resultingObjectSet
|
|
92
97
|
} = useObjectTableData(objectType, columnDefinitions, filter, sorting, objectSet, objectSetOptions, dedupeIntervalMs, pageSize, streamUpdates);
|
|
93
98
|
const {
|
|
@@ -202,6 +207,16 @@ export function ObjectTable({
|
|
|
202
207
|
return renderCellContextMenu?.(row, cell.getValue());
|
|
203
208
|
}, [renderCellContextMenu]);
|
|
204
209
|
const handleColumnHeaderClick = useMemo(() => onColumnHeaderClick ? columnId => onColumnHeaderClick(columnId) : undefined, [onColumnHeaderClick]);
|
|
210
|
+
const isTableLoading = isLoading || isColumnsLoading;
|
|
211
|
+
useObjectTableSnapshotHandle({
|
|
212
|
+
tableRef,
|
|
213
|
+
table,
|
|
214
|
+
hasNextPage: hasMore,
|
|
215
|
+
isLoading: isTableLoading,
|
|
216
|
+
error,
|
|
217
|
+
totalCount,
|
|
218
|
+
fetchMore
|
|
219
|
+
});
|
|
205
220
|
const headerMenuFeatureFlags = useMemo(() => ({
|
|
206
221
|
showSortingItems: enableOrdering,
|
|
207
222
|
showPinningItems: enableColumnPinning,
|
|
@@ -210,7 +225,7 @@ export function ObjectTable({
|
|
|
210
225
|
}), [enableOrdering, enableColumnPinning, enableColumnResizing, enableColumnConfig]);
|
|
211
226
|
return /*#__PURE__*/React.createElement(BaseTable, {
|
|
212
227
|
table: table,
|
|
213
|
-
isLoading:
|
|
228
|
+
isLoading: isTableLoading,
|
|
214
229
|
fetchNextPage: fetchMore,
|
|
215
230
|
onRowClick: props.onRowClick,
|
|
216
231
|
onColumnHeaderClick: handleColumnHeaderClick,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectTable.js","names":["getCoreRowModel","useReactTable","React","useCallback","useMemo","useColumnDefs","useColumnPinning","useColumnResize","useColumnVisibility","useEditableTable","useObjectTableData","useRowSelection","useSelectionColumn","useTableSorting","BaseTable","getRowId","EMPTY_ARRAY","ObjectTable","objectType","objectSet","columnDefinitions","filter","objectSetOptions","dedupeIntervalMs","pageSize","streamUpdates","orderBy","defaultOrderBy","onOrderByChanged","onColumnsPinnedChanged","onColumnResize","onRowSelection","onRowSelectionChanged","onColumnHeaderClick","renderCellContextMenu","selectionMode","selectedRows","isAllSelected","isAllSelectedProp","onColumnVisibilityChanged","onCellValueChanged","onSubmitEdits","enableOrdering","enableColumnPinning","enableColumnResizing","enableColumnConfig","editMode","props","columnSizing","onColumnSizingChange","sorting","onSortingChange","data","fetchMore","isLoading","error","resultingObjectSet","columns","loading","isColumnsLoading","primaryKeyApiName","type","undefined","handleRowSelectionChanged","change","derivedObjectSet","isSelectAll","length","where","$in","map","r","$primaryKey","rowSelection","hasSelection","onToggleAll","onToggleRow","enableRowSelection","selectionColumn","columnVisibility","onColumnVisibilityChange","columnOrder","onColumnOrderChange","allColumns","columnPinning","onColumnPinningChange","hasSelectionColumn","editableConfig","table","state","enableSorting","columnResizeMode","columnResizeDirection","manualSorting","defaultColumn","minSize","meta","onCellEdit","onCellValidationError","clearCellValidationError","cellEdits","isInEditMode","editModeState","isActive","validationErrors","onRenderCellContextMenu","row","cell","getValue","handleColumnHeaderClick","columnId","headerMenuFeatureFlags","showSortingItems","showPinningItems","showResizeItem","showConfigItem","createElement","fetchNextPage","onRowClick","rowHeight","renderEmptyState","className","getRowAttributes","showEditFooter"],"sources":["ObjectTable.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n ObjectSet,\n Osdk,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport type { Cell } from \"@tanstack/react-table\";\nimport { getCoreRowModel, useReactTable } from \"@tanstack/react-table\";\nimport React, { useCallback, useMemo } from \"react\";\nimport { useColumnDefs } from \"./hooks/useColumnDefs.js\";\nimport { useColumnPinning } from \"./hooks/useColumnPinning.js\";\nimport { useColumnResize } from \"./hooks/useColumnResize.js\";\nimport { useColumnVisibility } from \"./hooks/useColumnVisibility.js\";\nimport { useEditableTable } from \"./hooks/useEditableTable.js\";\nimport { useObjectTableData } from \"./hooks/useObjectTableData.js\";\nimport type { UseRowSelectionChange } from \"./hooks/useRowSelection.js\";\nimport { useRowSelection } from \"./hooks/useRowSelection.js\";\nimport { useSelectionColumn } from \"./hooks/useSelectionColumn.js\";\nimport { useTableSorting } from \"./hooks/useTableSorting.js\";\nimport type { ObjectTableProps } from \"./ObjectTableApi.js\";\nimport { BaseTable } from \"./Table.js\";\nimport type { HeaderMenuFeatureFlags } from \"./TableHeaderWithPopover.js\";\nimport { getRowId } from \"./utils/getRowId.js\";\n\nconst EMPTY_ARRAY: [] = [];\nimport type { EditableConfig } from \"./utils/types.js\";\n\n/**\n * ObjectTable - A headless table component for displaying OSDK object sets\n *\n * @example\n * ```tsx\n * <ObjectTable objectType={MyObjectType} />\n * ```\n */\n\nexport function ObjectTable<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<\n string,\n never\n >,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>({\n objectType,\n objectSet,\n columnDefinitions,\n filter,\n objectSetOptions,\n dedupeIntervalMs,\n pageSize,\n streamUpdates,\n orderBy,\n defaultOrderBy,\n onOrderByChanged,\n onColumnsPinnedChanged,\n onColumnResize,\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- intentional pass-through to fire alongside onRowSelectionChanged for backwards compatibility\n onRowSelection,\n onRowSelectionChanged,\n onColumnHeaderClick,\n renderCellContextMenu,\n selectionMode = \"none\",\n selectedRows,\n isAllSelected: isAllSelectedProp,\n onColumnVisibilityChanged,\n onCellValueChanged,\n onSubmitEdits,\n enableOrdering = true,\n enableColumnPinning = true,\n enableColumnResizing = true,\n enableColumnConfig = true,\n editMode = \"manual\",\n ...props\n}: ObjectTableProps<Q, RDPs, FunctionColumns>): React.ReactElement {\n const { columnSizing, onColumnSizingChange } = useColumnResize({\n onColumnResize,\n });\n\n const { sorting, onSortingChange } = useTableSorting<\n Q,\n RDPs,\n FunctionColumns\n >(\n {\n orderBy,\n defaultOrderBy,\n onOrderByChanged,\n },\n );\n\n const { data, fetchMore, isLoading, error, objectSet: resultingObjectSet } =\n useObjectTableData<\n Q,\n RDPs,\n FunctionColumns\n >(\n objectType,\n columnDefinitions,\n filter,\n sorting,\n objectSet,\n objectSetOptions,\n dedupeIntervalMs,\n pageSize,\n streamUpdates,\n );\n\n const { columns, loading: isColumnsLoading } = useColumnDefs<\n Q,\n RDPs,\n FunctionColumns\n >(\n objectType,\n columnDefinitions,\n );\n\n const primaryKeyApiName = objectType.type === \"object\"\n ? objectType.primaryKeyApiName\n : undefined;\n\n const handleRowSelectionChanged = useCallback(\n (change: UseRowSelectionChange<Q, RDPs>) => {\n if (!onRowSelectionChanged) return;\n\n let derivedObjectSet: ObjectSet<Q, RDPs> | undefined;\n if (resultingObjectSet) {\n if (primaryKeyApiName) {\n derivedObjectSet =\n change.isSelectAll && change.selectedRows.length > 0\n ? resultingObjectSet\n : resultingObjectSet.where({\n [primaryKeyApiName]: {\n $in: change.selectedRows.map(r => r.$primaryKey),\n },\n } as WhereClause<Q, RDPs>);\n } else if (change.isSelectAll && change.selectedRows.length > 0) {\n derivedObjectSet = resultingObjectSet;\n }\n }\n\n onRowSelectionChanged({\n selectedRows: change.selectedRows,\n isSelectAll: change.isSelectAll,\n objectSet: derivedObjectSet,\n });\n },\n [\n onRowSelectionChanged,\n resultingObjectSet,\n primaryKeyApiName,\n ],\n );\n\n const {\n rowSelection,\n isAllSelected,\n hasSelection,\n onToggleAll,\n onToggleRow,\n enableRowSelection,\n } = useRowSelection<Q, RDPs>({\n selectionMode,\n selectedRows,\n isAllSelected: isAllSelectedProp,\n onRowSelection,\n onRowSelectionChanged: handleRowSelectionChanged,\n data,\n });\n\n const selectionColumn = useSelectionColumn<Q, RDPs>(\n {\n selectionMode,\n isAllSelected,\n hasSelection,\n onToggleAll,\n onToggleRow,\n },\n );\n\n const {\n columnVisibility,\n onColumnVisibilityChange,\n columnOrder,\n onColumnOrderChange,\n } = useColumnVisibility({\n allColumns: columns,\n onColumnVisibilityChanged,\n });\n\n const { columnPinning, onColumnPinningChange } = useColumnPinning({\n columnDefinitions,\n hasSelectionColumn: enableRowSelection,\n onColumnsPinnedChanged,\n });\n\n const allColumns = useMemo(() => {\n return selectionColumn ? [selectionColumn, ...columns] : columns;\n }, [selectionColumn, columns]);\n\n const editableConfig: EditableConfig<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n > = useEditableTable({\n editMode,\n onCellValueChanged,\n onSubmitEdits,\n });\n\n const table = useReactTable<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>\n >({\n data: data ?? EMPTY_ARRAY,\n columns: allColumns,\n getCoreRowModel: getCoreRowModel(),\n state: {\n columnVisibility,\n columnOrder,\n rowSelection,\n sorting,\n columnSizing,\n columnPinning,\n },\n onSortingChange,\n onColumnSizingChange,\n onColumnPinningChange,\n onColumnVisibilityChange,\n onColumnOrderChange,\n enableRowSelection,\n enableSorting: enableOrdering,\n columnResizeMode: \"onChange\",\n columnResizeDirection: \"ltr\",\n manualSorting: true, // Enable manual sorting to indicate server-side sorting\n defaultColumn: {\n minSize: 80,\n },\n getRowId,\n meta: {\n onCellEdit: editableConfig.onCellEdit,\n onCellValidationError: editableConfig.onCellValidationError,\n clearCellValidationError: editableConfig.clearCellValidationError,\n cellEdits: editableConfig.cellEdits,\n isInEditMode: editableConfig.editModeState.isActive,\n validationErrors: editableConfig.validationErrors,\n },\n });\n\n const onRenderCellContextMenu = useCallback(\n (\n row: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n cell: Cell<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >,\n ) => {\n return renderCellContextMenu?.(row, cell.getValue());\n },\n [renderCellContextMenu],\n );\n\n const handleColumnHeaderClick = useMemo(\n () =>\n onColumnHeaderClick\n ? (columnId: string) =>\n onColumnHeaderClick(\n columnId as\n | PropertyKeys<Q>\n | keyof RDPs\n | keyof FunctionColumns,\n )\n : undefined,\n [onColumnHeaderClick],\n );\n\n const isTableLoading = isLoading || isColumnsLoading;\n\n const headerMenuFeatureFlags: HeaderMenuFeatureFlags = useMemo(() => ({\n showSortingItems: enableOrdering,\n showPinningItems: enableColumnPinning,\n showResizeItem: enableColumnResizing,\n showConfigItem: enableColumnConfig,\n }), [\n enableOrdering,\n enableColumnPinning,\n enableColumnResizing,\n enableColumnConfig,\n ]);\n\n return (\n <BaseTable<Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>>\n table={table}\n isLoading={isTableLoading}\n fetchNextPage={fetchMore}\n onRowClick={props.onRowClick}\n onColumnHeaderClick={handleColumnHeaderClick}\n rowHeight={props.rowHeight}\n renderCellContextMenu={onRenderCellContextMenu}\n renderEmptyState={props.renderEmptyState}\n className={props.className}\n error={error}\n headerMenuFeatureFlags={headerMenuFeatureFlags}\n editableConfig={editableConfig}\n getRowAttributes={props.getRowAttributes}\n showEditFooter={props.showEditFooter}\n />\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ObjectTable.js","names":["getCoreRowModel","useReactTable","React","useCallback","useMemo","useColumnDefs","useColumnPinning","useColumnResize","useColumnVisibility","useEditableTable","useObjectTableData","useObjectTableSnapshotHandle","useRowSelection","useSelectionColumn","useTableSorting","BaseTable","getRowId","EMPTY_ARRAY","ObjectTable","objectType","objectSet","columnDefinitions","filter","objectSetOptions","dedupeIntervalMs","pageSize","streamUpdates","orderBy","defaultOrderBy","onOrderByChanged","onColumnsPinnedChanged","onColumnResize","onRowSelection","onRowSelectionChanged","onColumnHeaderClick","renderCellContextMenu","selectionMode","selectedRows","isAllSelected","isAllSelectedProp","onColumnVisibilityChanged","onCellValueChanged","onSubmitEdits","enableOrdering","enableColumnPinning","enableColumnResizing","enableColumnConfig","editMode","tableRef","props","columnSizing","onColumnSizingChange","sorting","onSortingChange","data","fetchMore","hasMore","isLoading","error","totalCount","resultingObjectSet","columns","loading","isColumnsLoading","primaryKeyApiName","type","undefined","handleRowSelectionChanged","change","derivedObjectSet","isSelectAll","length","where","$in","map","r","$primaryKey","rowSelection","hasSelection","onToggleAll","onToggleRow","enableRowSelection","selectionColumn","columnVisibility","onColumnVisibilityChange","columnOrder","onColumnOrderChange","allColumns","columnPinning","onColumnPinningChange","hasSelectionColumn","editableConfig","table","state","enableSorting","columnResizeMode","columnResizeDirection","manualSorting","defaultColumn","minSize","meta","onCellEdit","onCellValidationError","clearCellValidationError","cellEdits","isInEditMode","editModeState","isActive","validationErrors","onRenderCellContextMenu","row","cell","getValue","handleColumnHeaderClick","columnId","isTableLoading","hasNextPage","headerMenuFeatureFlags","showSortingItems","showPinningItems","showResizeItem","showConfigItem","createElement","fetchNextPage","onRowClick","rowHeight","renderEmptyState","className","getRowAttributes","showEditFooter"],"sources":["ObjectTable.tsx"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n ObjectSet,\n Osdk,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport type { Cell } from \"@tanstack/react-table\";\nimport { getCoreRowModel, useReactTable } from \"@tanstack/react-table\";\nimport React, { useCallback, useMemo } from \"react\";\nimport { useColumnDefs } from \"./hooks/useColumnDefs.js\";\nimport { useColumnPinning } from \"./hooks/useColumnPinning.js\";\nimport { useColumnResize } from \"./hooks/useColumnResize.js\";\nimport { useColumnVisibility } from \"./hooks/useColumnVisibility.js\";\nimport { useEditableTable } from \"./hooks/useEditableTable.js\";\nimport { useObjectTableData } from \"./hooks/useObjectTableData.js\";\nimport { useObjectTableSnapshotHandle } from \"./hooks/useObjectTableSnapshotHandle.js\";\nimport type { UseRowSelectionChange } from \"./hooks/useRowSelection.js\";\nimport { useRowSelection } from \"./hooks/useRowSelection.js\";\nimport { useSelectionColumn } from \"./hooks/useSelectionColumn.js\";\nimport { useTableSorting } from \"./hooks/useTableSorting.js\";\nimport type { ObjectTableProps } from \"./ObjectTableApi.js\";\nimport { BaseTable } from \"./Table.js\";\nimport type { HeaderMenuFeatureFlags } from \"./TableHeaderWithPopover.js\";\nimport { getRowId } from \"./utils/getRowId.js\";\nimport type { EditableConfig } from \"./utils/types.js\";\n\nconst EMPTY_ARRAY: [] = [];\n\n/**\n * ObjectTable - A headless table component for displaying OSDK object sets\n *\n * @example\n * ```tsx\n * <ObjectTable objectType={MyObjectType} />\n * ```\n */\n\nexport function ObjectTable<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<\n string,\n never\n >,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>({\n objectType,\n objectSet,\n columnDefinitions,\n filter,\n objectSetOptions,\n dedupeIntervalMs,\n pageSize,\n streamUpdates,\n orderBy,\n defaultOrderBy,\n onOrderByChanged,\n onColumnsPinnedChanged,\n onColumnResize,\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- intentional pass-through to fire alongside onRowSelectionChanged for backwards compatibility\n onRowSelection,\n onRowSelectionChanged,\n onColumnHeaderClick,\n renderCellContextMenu,\n selectionMode = \"none\",\n selectedRows,\n isAllSelected: isAllSelectedProp,\n onColumnVisibilityChanged,\n onCellValueChanged,\n onSubmitEdits,\n enableOrdering = true,\n enableColumnPinning = true,\n enableColumnResizing = true,\n enableColumnConfig = true,\n editMode = \"manual\",\n tableRef,\n ...props\n}: ObjectTableProps<Q, RDPs, FunctionColumns>): React.ReactElement {\n const { columnSizing, onColumnSizingChange } = useColumnResize({\n onColumnResize,\n });\n\n const { sorting, onSortingChange } = useTableSorting<\n Q,\n RDPs,\n FunctionColumns\n >(\n {\n orderBy,\n defaultOrderBy,\n onOrderByChanged,\n },\n );\n\n const {\n data,\n fetchMore,\n hasMore,\n isLoading,\n error,\n totalCount,\n objectSet: resultingObjectSet,\n } = useObjectTableData<\n Q,\n RDPs,\n FunctionColumns\n >(\n objectType,\n columnDefinitions,\n filter,\n sorting,\n objectSet,\n objectSetOptions,\n dedupeIntervalMs,\n pageSize,\n streamUpdates,\n );\n\n const { columns, loading: isColumnsLoading } = useColumnDefs<\n Q,\n RDPs,\n FunctionColumns\n >(\n objectType,\n columnDefinitions,\n );\n\n const primaryKeyApiName = objectType.type === \"object\"\n ? objectType.primaryKeyApiName\n : undefined;\n\n const handleRowSelectionChanged = useCallback(\n (change: UseRowSelectionChange<Q, RDPs>) => {\n if (!onRowSelectionChanged) return;\n\n let derivedObjectSet: ObjectSet<Q, RDPs> | undefined;\n if (resultingObjectSet) {\n if (primaryKeyApiName) {\n derivedObjectSet =\n change.isSelectAll && change.selectedRows.length > 0\n ? resultingObjectSet\n : resultingObjectSet.where({\n [primaryKeyApiName]: {\n $in: change.selectedRows.map(r => r.$primaryKey),\n },\n } as WhereClause<Q, RDPs>);\n } else if (change.isSelectAll && change.selectedRows.length > 0) {\n derivedObjectSet = resultingObjectSet;\n }\n }\n\n onRowSelectionChanged({\n selectedRows: change.selectedRows,\n isSelectAll: change.isSelectAll,\n objectSet: derivedObjectSet,\n });\n },\n [\n onRowSelectionChanged,\n resultingObjectSet,\n primaryKeyApiName,\n ],\n );\n\n const {\n rowSelection,\n isAllSelected,\n hasSelection,\n onToggleAll,\n onToggleRow,\n enableRowSelection,\n } = useRowSelection<Q, RDPs>({\n selectionMode,\n selectedRows,\n isAllSelected: isAllSelectedProp,\n onRowSelection,\n onRowSelectionChanged: handleRowSelectionChanged,\n data,\n });\n\n const selectionColumn = useSelectionColumn<Q, RDPs>(\n {\n selectionMode,\n isAllSelected,\n hasSelection,\n onToggleAll,\n onToggleRow,\n },\n );\n\n const {\n columnVisibility,\n onColumnVisibilityChange,\n columnOrder,\n onColumnOrderChange,\n } = useColumnVisibility({\n allColumns: columns,\n onColumnVisibilityChanged,\n });\n\n const { columnPinning, onColumnPinningChange } = useColumnPinning({\n columnDefinitions,\n hasSelectionColumn: enableRowSelection,\n onColumnsPinnedChanged,\n });\n\n const allColumns = useMemo(() => {\n return selectionColumn ? [selectionColumn, ...columns] : columns;\n }, [selectionColumn, columns]);\n\n const editableConfig: EditableConfig<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n > = useEditableTable({\n editMode,\n onCellValueChanged,\n onSubmitEdits,\n });\n\n const table = useReactTable<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>\n >({\n data: data ?? EMPTY_ARRAY,\n columns: allColumns,\n getCoreRowModel: getCoreRowModel(),\n state: {\n columnVisibility,\n columnOrder,\n rowSelection,\n sorting,\n columnSizing,\n columnPinning,\n },\n onSortingChange,\n onColumnSizingChange,\n onColumnPinningChange,\n onColumnVisibilityChange,\n onColumnOrderChange,\n enableRowSelection,\n enableSorting: enableOrdering,\n columnResizeMode: \"onChange\",\n columnResizeDirection: \"ltr\",\n manualSorting: true, // Enable manual sorting to indicate server-side sorting\n defaultColumn: {\n minSize: 80,\n },\n getRowId,\n meta: {\n onCellEdit: editableConfig.onCellEdit,\n onCellValidationError: editableConfig.onCellValidationError,\n clearCellValidationError: editableConfig.clearCellValidationError,\n cellEdits: editableConfig.cellEdits,\n isInEditMode: editableConfig.editModeState.isActive,\n validationErrors: editableConfig.validationErrors,\n },\n });\n\n const onRenderCellContextMenu = useCallback(\n (\n row: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n cell: Cell<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >,\n ) => {\n return renderCellContextMenu?.(row, cell.getValue());\n },\n [renderCellContextMenu],\n );\n\n const handleColumnHeaderClick = useMemo(\n () =>\n onColumnHeaderClick\n ? (columnId: string) =>\n onColumnHeaderClick(\n columnId as\n | PropertyKeys<Q>\n | keyof RDPs\n | keyof FunctionColumns,\n )\n : undefined,\n [onColumnHeaderClick],\n );\n\n const isTableLoading = isLoading || isColumnsLoading;\n\n useObjectTableSnapshotHandle({\n tableRef,\n table,\n hasNextPage: hasMore,\n isLoading: isTableLoading,\n error,\n totalCount,\n fetchMore,\n });\n\n const headerMenuFeatureFlags: HeaderMenuFeatureFlags = useMemo(() => ({\n showSortingItems: enableOrdering,\n showPinningItems: enableColumnPinning,\n showResizeItem: enableColumnResizing,\n showConfigItem: enableColumnConfig,\n }), [\n enableOrdering,\n enableColumnPinning,\n enableColumnResizing,\n enableColumnConfig,\n ]);\n\n return (\n <BaseTable<Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>>\n table={table}\n isLoading={isTableLoading}\n fetchNextPage={fetchMore}\n onRowClick={props.onRowClick}\n onColumnHeaderClick={handleColumnHeaderClick}\n rowHeight={props.rowHeight}\n renderCellContextMenu={onRenderCellContextMenu}\n renderEmptyState={props.renderEmptyState}\n className={props.className}\n error={error}\n headerMenuFeatureFlags={headerMenuFeatureFlags}\n editableConfig={editableConfig}\n getRowAttributes={props.getRowAttributes}\n showEditFooter={props.showEditFooter}\n />\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectTableApi.js","names":[],"sources":["ObjectTableApi.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n CompileTimeMetadata,\n DerivedProperty,\n ObjectOrInterfaceDefinition,\n ObjectSet,\n Osdk,\n PrimaryKeyType,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport type { QueryParameterType } from \"@osdk/client/observable\";\nimport type * as React from \"react\";\nimport type { CellEditInfo, EditFieldConfig } from \"./utils/types.js\";\n\nexport type { EditFieldConfig } from \"./utils/types.js\";\n\nexport type ColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> =\n | EditableColumnDefinition<Q, RDPs, FunctionColumns>\n | ReadonlyColumnDefinition<Q, RDPs, FunctionColumns>;\n\ninterface SharedColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n locator: ColumnDefinitionLocator<Q, RDPs, FunctionColumns>;\n\n /**\n * @default true\n */\n isVisible?: boolean;\n\n /**\n * @default none\n */\n pinned?: \"left\" | \"right\" | \"none\";\n width?: number;\n minWidth?: number;\n maxWidth?: number;\n resizable?: boolean;\n orderable?: boolean;\n filterable?: boolean;\n\n /**\n * Custom renderer for the cell value.\n *\n * Interaction with `editable` columns:\n * - When `editMode: \"manual\"` (default), `renderCell` is used while the\n * table is read-only (Edit Table button visible) and the editable cell\n * takes over once the user enters edit mode.\n * - When `editMode: \"always\"`, the editable cell always wins on editable\n * columns and `renderCell` is ignored — `editMode: \"always\"` opts the\n * column into a permanently-editable surface, leaving no read-only\n * state for `renderCell` to render. Use `editMode: \"manual\"` if you\n * need a custom display alongside editing.\n */\n renderCell?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n locator: ColumnDefinitionLocator<Q, RDPs, FunctionColumns>,\n ) => React.ReactNode;\n\n /**\n * If provided, this will be used in the column header.\n * If both columnName and renderHeader are provided, renderHeader will take precedence in the table header.\n * columnName will still be used in other parts where the column name is displayed.\n *\n * If not provided,\n * for a property column, the property displayName will be used\n * for other columns, the id will be used.\n */\n columnName?: string;\n\n /**\n * If provided, this will be used to render the header component.\n * When both columnName and renderHeader are provided, renderHeader will take precedence in the table header.\n */\n renderHeader?: () => React.ReactNode;\n}\n\ninterface EditableColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> extends SharedColumnDefinition<Q, RDPs, FunctionColumns> {\n /**\n * `editable` can be a boolean or a predicate that receives the row's object\n * and returns whether the cell is editable\n */\n editable:\n | true\n | ((\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => boolean);\n\n /**\n * Configuration for the cell editor component.\n *\n * When provided, the column uses the specified field component\n * (e.g. dropdown) instead of the default auto-detected text/number input.\n *\n * `getFieldComponentProps` receives the row's object and a map of any\n * pending edits for that row (keyed by column id), and returns the props to\n * pass to the field component. Editor configuration can depend on the\n * current row or on other in-progress edits within the row.\n */\n editFieldConfig?: EditFieldConfig<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>\n >;\n\n /**\n * Additional function to validate the cell value during edit.\n *\n * @param value the current cell value\n * @returns a promise that resolves to an error message string if validation fails, or undefined if validation succeeds\n */\n validateEdit?: (\n value: unknown,\n ) => Promise<string | undefined>;\n}\n\n/**\n * Column definition for a read-only column (default).\n * `editFieldConfig` and `validateEdit` are not available.\n */\ninterface ReadonlyColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> extends SharedColumnDefinition<Q, RDPs, FunctionColumns> {\n editable?: false;\n}\n\nexport type ExtractQueryParameters<\n Q extends QueryDefinition,\n> = CompileTimeMetadata<Q>[\"parameters\"] extends Record<string, never>\n ? undefined\n : QueryParameterType<CompileTimeMetadata<Q>[\"parameters\"]>;\n\nexport interface PropertyColumnLocator<Q extends ObjectOrInterfaceDefinition> {\n type: \"property\";\n id: PropertyKeys<Q>;\n}\n\n/**\n * Concrete function column locator for a single key K.\n * Correlates the id, queryDefinition, and getFunctionParams types.\n */\ninterface FunctionColumnLocatorForKey<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n FunctionColumns extends Record<string, QueryDefinition<{}>>,\n K extends keyof FunctionColumns,\n> {\n /**\n * This is equivalent to workshop's function-backed columns.\n * The function needs to meet the specifications stated in https://www.palantir.com/docs/foundry/workshop/widgets-object-table/#function-backed-columns\n */\n type: \"function\";\n id: K;\n queryDefinition: FunctionColumns[K];\n\n /**\n * The function will be called with the current object set to get the input parameters for the function query.\n * @param objectSet - The current object set.\n * @returns - The function's input parameters including the object set.\n */\n getFunctionParams: (\n objectSet: ObjectSet<Q, RDPs>,\n ) => ExtractQueryParameters<FunctionColumns[K]>;\n\n /**\n * Function to generate keys for looking up results in the FunctionsMap.\n * @param object - The object instance\n * @returns - The key to use for looking up this object's result in the FunctionsMap\n */\n getKey: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => string;\n\n /**\n * Function to extract the cell value from the raw cell data returned by the function.\n * This is useful when functions return custom types with multiple properties.\n * @param cellData - The raw data returned by the function for this object\n * @returns - The value to display in the cell\n */\n getValue?: (cellData?: unknown) => unknown;\n\n /**\n * Minimum time between re-fetches of the same function with the same parameters, in milliseconds.\n * Defaults to 5 minutes as it is expensive to fetch function columns for a large object set\n * and they are expected to be relatively static in the context of an object table\n *\n * @default 300_000 (5 minutes)\n */\n dedupeIntervalMs?: number;\n\n /**\n * Object type apiNames the function reads but doesn't take as a parameter (e.g.\n * linked object types the function traverses internally). The column auto-revalidates\n * when an action edits an object of any of these types. Param-derived types are\n * tracked automatically and don't need to be listed here.\n */\n dependsOn?: string[];\n}\n\n/**\n * Distributes over each key in FunctionColumns so that id, queryDefinition,\n * and getFunctionParams are correlated per key.\n */\nexport type FunctionColumnLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> = keyof FunctionColumns extends infer K\n ? K extends keyof FunctionColumns\n ? FunctionColumnLocatorForKey<Q, RDPs, FunctionColumns, K>\n : never\n : never;\n\nexport interface RdpColumnLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n type: \"rdp\";\n id: keyof RDPs;\n creator: DerivedProperty.Creator<Q, RDPs[keyof RDPs]>;\n}\n\nexport interface CustomColumnLocator {\n type: \"custom\";\n id: string;\n}\n\nexport type ColumnDefinitionLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> =\n | PropertyColumnLocator<Q>\n | FunctionColumnLocator<Q, RDPs, FunctionColumns>\n | RdpColumnLocator<Q, RDPs>\n | CustomColumnLocator;\n\nexport interface ObjectTableProps<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n /**\n * The object or interface type of the object\n * If objectSet is not provided, objects will be fetched based on this type.\n */\n objectType: Q;\n\n /**\n * The set of objects to show in the table.\n * If provided and the objectType is not an interface, the table will use objectSet to fetch objects instead of fetching based on objectType.\n */\n objectSet?: ObjectSet<Q>;\n\n objectSetOptions?: ObjectSetOptions<Q>;\n\n /**\n * Minimum time between fetch requests in milliseconds.\n * Increasing this value reduces redundant network calls when the same data\n * is requested multiple times in quick succession.\n *\n * @default 60_000 1 minute\n */\n dedupeIntervalMs?: number;\n\n /**\n * Enable streaming updates via websocket subscription.\n * When true, the table will automatically update when matching\n * objects are added, updated, or removed in Foundry.\n *\n * Limitations: `streamUpdates` cannot be used together with `pivotTo` or\n * `withProperties`. The server does not support websocket subscriptions\n * for link-traversal or derived-property queries. Those queries still\n * fetch data normally but won't receive real-time updates.\n *\n * @default false\n */\n streamUpdates?: boolean;\n\n /**\n * Number of objects to fetch per page.\n *\n * @default 50\n */\n pageSize?: number;\n\n /**\n * Ordered list of column definitions to show in the table\n *\n * If not provided, all of the properties of the object type will be shown in default order.\n */\n columnDefinitions?: Array<ColumnDefinition<Q, RDPs, FunctionColumns>>;\n\n /**\n * Whether the table is filterable by the user.\n *\n * @default true\n */\n enableFiltering?: boolean;\n\n /**\n * The current where clause to filter the objects in the table.\n * If provided, the filter is controlled.\n */\n filter?: WhereClause<Q, RDPs>;\n\n /**\n * Called when the where clause is changed.\n * Required when filter is controlled.\n *\n * @param newWhere The new where clause\n */\n onFilterChanged?: (newWhere: WhereClause<Q, RDPs>) => void;\n\n /**\n * Whether the table is sortable by the user.\n *\n * @default true\n */\n enableOrdering?: boolean;\n\n /**\n * Whether columns can be pinned by the user.\n *\n * @default true\n */\n enableColumnPinning?: boolean;\n\n /**\n * Whether columns can be resized by the user.\n *\n * @default true\n */\n enableColumnResizing?: boolean;\n\n /**\n * Whether the column configuration dialog for column visibility and ordering is available to the user.\n *\n * @default true\n */\n enableColumnConfig?: boolean;\n\n /**\n * Controls the edit mode behavior of the table.\n * - \"always\": Editable cells are immediately in edit mode on row clicked.\n * - \"manual\": User can toggle edit mode on/off via the Edit Table button.\n *\n * @default \"manual\"\n */\n editMode?: \"always\" | \"manual\";\n\n /**\n * Whether to render the bottom edit footer that hosts the\n * \"Edit Table\" / \"Cancel\" / \"Submit Edits\" buttons and the edit-state\n * indicators (modification count, validation errors).\n *\n * @default true whenever the table has at least one column declared\n * editable (i.e. any column with `editable: true` or `editable: (object) => boolean`).\n * When `false`, the \"Edit Table\" and \"Submit Edits\" buttons will not be shown.\n */\n showEditFooter?: boolean;\n\n /**\n * The default order by clause to sort the objects in the table.\n * If provided without orderBy prop, the sorting is uncontrolled.\n * If both orderBy and defaultOrderBy are provided, orderBy takes precedence.\n */\n defaultOrderBy?: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>;\n\n /**\n * The current order by clause to sort the objects in the table.\n * If provided, the sorting is controlled.\n * If both orderBy and defaultOrderBy are provided, orderBy takes precedence.\n */\n orderBy?: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>;\n\n /**\n * Called when the order by clause is changed.\n * Required when sorting is controlled.\n *\n * @param newOrderBy The new order by clause\n */\n onOrderByChanged?: (\n newOrderBy: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>,\n ) => void;\n\n /**\n * Called after the value of a cell is edited and committed by the user.\n *\n * @param info An object containing details about the cell that was edited,\n * including the rowId, columnId, new and old values, and the row data before the edit\n */\n onCellValueChanged?: (\n info: CellEditInfo<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >,\n ) => void;\n\n /**\n * If provided, the \"Submit Edits\" button will be shown in the edit footer.\n *\n * @param edits an array of edit info containing details about the edited cells\n * including the rowId, columnId, new and old values, and the row data before the edit\n * @return a promise that resolves to true if the edits were successfully submitted\n */\n onSubmitEdits?: (edits: CellEditInfo<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >[]) => Promise<boolean>;\n\n /**\n * Called when the column visibility or ordering changed.\n *\n * If provided, the table will allow the user to show/hide columns.\n *\n * @param newStates The columns sorted in their display order in the table and their visibility state.\n */\n onColumnVisibilityChanged?: (\n newStates: Array<{\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns;\n isVisible: boolean;\n }>,\n ) => void;\n\n /**\n * Called when the pinned columns change.\n *\n * If provided, the table will allow the user to pin/unpin columns.\n *\n * @param newStates The new list of column pin states\n */\n onColumnsPinnedChanged?: (\n newStates: Array<{\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns;\n pinned: \"left\" | \"right\" | \"none\";\n }>,\n ) => void;\n\n /**\n * Called when a column is resized.\n *\n * @param columnId The ID of the resized column\n * @param newWidth The new width of the column. When newWidth = null, the column size is reset.\n */\n onColumnResize?: (\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns,\n newWidth: number | null,\n ) => void;\n\n /**\n * Called when a row is clicked.\n *\n * @param object The object representing the clicked row\n */\n onRowClick?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => void;\n\n /**\n * Called when a column header is clicked.\n *\n * The columnId matches the `locator.id` configured on the column definition.\n * The dropdown menu trigger is excluded — clicking the chevron opens the\n * header menu instead of firing this callback.\n *\n * @param columnId The id of the clicked column\n */\n onColumnHeaderClick?: (\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns,\n ) => void;\n\n /**\n * Selection mode for the table rows.\n *\n * If multiple, a checkbox will be shown for each row to allow selecting multiple rows\n * as well as a top-level checkbox in the header to select all rows.\n *\n * @default \"none\"\n */\n selectionMode?: \"single\" | \"multiple\" | \"none\";\n\n /**\n * The currently selected rows in the table.\n * If provided, the row selection is controlled.\n */\n selectedRows?: PrimaryKeyType<Q>[];\n\n /**\n * Indicates whether all rows are selected in controlled mode.\n * When true, the table will show all rows as selected regardless of the selectedRows array.\n */\n isAllSelected?: boolean;\n\n /**\n * Called when the row selection changes.\n *\n * @deprecated Use {@link onRowSelectionChanged} instead. The new callback\n * delivers a {@link RowSelectionChange} object with `selectedRows`,\n * `isSelectAll`, and a derived `objectSet`. This legacy callback\n * continues to fire alongside the new one for backwards compatibility.\n *\n * @param selectedRowIds The primary keys of currently selected rows\n * @param isSelectAll Whether the change was triggered by a \"select all\" action. Defaults to false\n */\n onRowSelection?: (\n selectedRowIds: PrimaryKeyType<Q>[],\n isSelectAll?: boolean,\n ) => void;\n\n /**\n * Called when the row selection changes, with a {@link RowSelectionChange}\n * payload describing the new state.\n *\n * @param change The new selection state. See {@link RowSelectionChange}.\n */\n onRowSelectionChanged?: (\n change: RowSelectionChange<Q, RDPs>,\n ) => void;\n /**\n * If provided, will render this context menu when right clicking on a cell\n */\n renderCellContextMenu?: (\n row: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n cellValue: unknown,\n ) => React.ReactNode;\n\n /**\n * Render override for the empty state. Called when the table has no\n * rows and no error. When omitted, a default \"No Data\" indicator is\n * rendered.\n */\n renderEmptyState?: () => React.ReactNode;\n\n /**\n * The height of each row in pixels.\n *\n * @default 40\n */\n rowHeight?: number;\n\n /**\n * Returns extra HTML attributes (typically `data-*`) to apply to each\n * row element. Use this to drive conditional row styling\n */\n getRowAttributes?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => Record<string, string | undefined>;\n\n className?: string;\n}\n\n/**\n * Payload for {@link ObjectTableProps.onRowSelectionChanged}. Consolidates\n * the loaded row instances, the `isSelectAll` semantic intent, and an\n * `ObjectSet` covering the selection.\n */\nexport interface RowSelectionChange<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n /**\n * Loaded row instances currently selected. When `isSelectAll` is true,\n * this reflects only the rows currently in the table — pages not yet\n * fetched are absent. Use `objectSet` for the cross-page view, and\n * `selectedRows.map(r => r.$primaryKey)` if you need the primary keys.\n */\n selectedRows: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[];\n\n /**\n * True when the user invoked \"select all\" (header checkbox) or when\n * controlled mode supplies `isAllSelected={true}`. Distinct from \"every\n * loaded row happens to be selected\" — that condition is reflected by\n * `selectedRows.length` matching the visible row count but does not set\n * this flag.\n */\n isSelectAll: boolean;\n\n /**\n * An `ObjectSet` representing the selection.\n *\n * - \"Select all\" → the underlying `ObjectSet` (`objectSet` prop if\n * provided, otherwise derived from `objectType` via `client(...)`).\n * This includes rows not yet loaded into the table.\n * - Partial selection → the underlying `ObjectSet` narrowed to\n * `{ [primaryKeyApiName]: { $in: selectedRows.map(r => r.$primaryKey) } }`.\n * - \"Deselect all\" → an empty `ObjectSet` (`$in: []`).\n *\n * `undefined` for interface types without a resolvable\n * `primaryKeyApiName` when the selection is partial or empty (a\n * `$primaryKey`-style filter can't be expressed). For \"select all\" on\n * those types the underlying `ObjectSet` is still emitted.\n */\n objectSet: ObjectSet<Q, RDPs> | undefined;\n}\n\nexport interface ObjectSetOptions<\n Q extends ObjectOrInterfaceDefinition,\n> {\n /**\n * Object sets to union with\n */\n union?: ObjectSet<Q>[];\n\n /**\n * Object sets to intersect with\n */\n intersect?: ObjectSet<Q>[];\n\n /**\n * Object sets to subtract from\n */\n subtract?: ObjectSet<Q>[];\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"ObjectTableApi.js","names":[],"sources":["ObjectTableApi.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n CompileTimeMetadata,\n DerivedProperty,\n ObjectOrInterfaceDefinition,\n ObjectSet,\n Osdk,\n PrimaryKeyType,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport type { QueryParameterType } from \"@osdk/client/observable\";\nimport type * as React from \"react\";\nimport type { CellEditInfo, EditFieldConfig } from \"./utils/types.js\";\n\nexport type { EditFieldConfig } from \"./utils/types.js\";\n\nexport interface ObjectTableHandle<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n /**\n * Returns a point-in-time snapshot of ObjectTable's currently loaded data\n * and pagination state.\n *\n * The snapshot includes visible data columns only, excludes internal control\n * columns such as row selection, and does not fetch additional pages unless\n * a positive finite `rowLimit` is provided. `rowLimit` is a pagination\n * threshold, not a hard cap: the returned snapshot can contain more rows when\n * they were already loaded or when the final fetched page crosses the\n * threshold.\n * Cell values come from the table's accessor values, not from rendered React\n * content supplied by `renderCell`.\n *\n * `getSnapshot` always resolves, even when a paginated fetch fails: it returns\n * the rows loaded so far with the failure exposed on `snapshot.error`. Callers\n * that require a complete result (e.g. exporting all rows) must inspect\n * `snapshot.error` and `snapshot.hasNextPage` rather than assuming the snapshot\n * is complete.\n */\n getSnapshot: (\n options?: ObjectTableSnapshotOptions,\n ) => Promise<ObjectTableSnapshot<Q, RDPs>>;\n}\n\nexport interface ObjectTableSnapshotOptions {\n /**\n * Fetches additional pages until at least this many rows are loaded or\n * pagination stops.\n *\n * This is not a hard maximum. The returned snapshot can contain more rows\n * because ObjectTable keeps already-loaded rows and fetches full pages.\n */\n rowLimit?: number;\n}\n\nexport interface ObjectTableSnapshot<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n columns: ObjectTableDataColumn[];\n rows: ObjectTableDataRow<Q, RDPs>[];\n hasNextPage: boolean;\n isLoading: boolean;\n error: unknown | undefined;\n totalCount: string | undefined;\n}\n\nexport interface ObjectTableDataColumn {\n id: string;\n name: string;\n}\n\nexport interface ObjectTableDataRow<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n id: string;\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>;\n getValue: (columnId: string) => ObjectTableDataCell | undefined;\n}\n\nexport type ObjectTableDataCell =\n | { status: \"ready\"; value: unknown }\n | { status: \"loading\"; value: unknown | undefined }\n | { status: \"error\"; error: unknown; value: unknown | undefined };\n\nexport type ColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> =\n | EditableColumnDefinition<Q, RDPs, FunctionColumns>\n | ReadonlyColumnDefinition<Q, RDPs, FunctionColumns>;\n\ninterface SharedColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n locator: ColumnDefinitionLocator<Q, RDPs, FunctionColumns>;\n\n /**\n * @default true\n */\n isVisible?: boolean;\n\n /**\n * @default none\n */\n pinned?: \"left\" | \"right\" | \"none\";\n width?: number;\n minWidth?: number;\n maxWidth?: number;\n resizable?: boolean;\n orderable?: boolean;\n filterable?: boolean;\n\n /**\n * Custom renderer for the cell value.\n *\n * Interaction with `editable` columns:\n * - When `editMode: \"manual\"` (default), `renderCell` is used while the\n * table is read-only (Edit Table button visible) and the editable cell\n * takes over once the user enters edit mode.\n * - When `editMode: \"always\"`, the editable cell always wins on editable\n * columns and `renderCell` is ignored — `editMode: \"always\"` opts the\n * column into a permanently-editable surface, leaving no read-only\n * state for `renderCell` to render. Use `editMode: \"manual\"` if you\n * need a custom display alongside editing.\n */\n renderCell?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n locator: ColumnDefinitionLocator<Q, RDPs, FunctionColumns>,\n ) => React.ReactNode;\n\n /**\n * If provided, this will be used in the column header.\n * If both columnName and renderHeader are provided, renderHeader will take precedence in the table header.\n * columnName will still be used in other parts where the column name is displayed.\n *\n * If not provided,\n * for a property column, the property displayName will be used\n * for other columns, the id will be used.\n */\n columnName?: string;\n\n /**\n * If provided, this will be used to render the header component.\n * When both columnName and renderHeader are provided, renderHeader will take precedence in the table header.\n */\n renderHeader?: () => React.ReactNode;\n}\n\ninterface EditableColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> extends SharedColumnDefinition<Q, RDPs, FunctionColumns> {\n /**\n * `editable` can be a boolean or a predicate that receives the row's object\n * and returns whether the cell is editable\n */\n editable:\n | true\n | ((\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => boolean);\n\n /**\n * Configuration for the cell editor component.\n *\n * When provided, the column uses the specified field component\n * (e.g. dropdown) instead of the default auto-detected text/number input.\n *\n * `getFieldComponentProps` receives the row's object and a map of any\n * pending edits for that row (keyed by column id), and returns the props to\n * pass to the field component. Editor configuration can depend on the\n * current row or on other in-progress edits within the row.\n */\n editFieldConfig?: EditFieldConfig<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>\n >;\n\n /**\n * Additional function to validate the cell value during edit.\n *\n * @param value the current cell value\n * @returns a promise that resolves to an error message string if validation fails, or undefined if validation succeeds\n */\n validateEdit?: (\n value: unknown,\n ) => Promise<string | undefined>;\n}\n\n/**\n * Column definition for a read-only column (default).\n * `editFieldConfig` and `validateEdit` are not available.\n */\ninterface ReadonlyColumnDefinition<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> extends SharedColumnDefinition<Q, RDPs, FunctionColumns> {\n editable?: false;\n}\n\nexport type ExtractQueryParameters<\n Q extends QueryDefinition,\n> = CompileTimeMetadata<Q>[\"parameters\"] extends Record<string, never>\n ? undefined\n : QueryParameterType<CompileTimeMetadata<Q>[\"parameters\"]>;\n\nexport interface PropertyColumnLocator<Q extends ObjectOrInterfaceDefinition> {\n type: \"property\";\n id: PropertyKeys<Q>;\n}\n\n/**\n * Concrete function column locator for a single key K.\n * Correlates the id, queryDefinition, and getFunctionParams types.\n */\ninterface FunctionColumnLocatorForKey<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n FunctionColumns extends Record<string, QueryDefinition<{}>>,\n K extends keyof FunctionColumns,\n> {\n /**\n * This is equivalent to workshop's function-backed columns.\n * The function needs to meet the specifications stated in https://www.palantir.com/docs/foundry/workshop/widgets-object-table/#function-backed-columns\n */\n type: \"function\";\n id: K;\n queryDefinition: FunctionColumns[K];\n\n /**\n * The function will be called with the current object set to get the input parameters for the function query.\n * @param objectSet - The current object set.\n * @returns - The function's input parameters including the object set.\n */\n getFunctionParams: (\n objectSet: ObjectSet<Q, RDPs>,\n ) => ExtractQueryParameters<FunctionColumns[K]>;\n\n /**\n * Function to generate keys for looking up results in the FunctionsMap.\n * @param object - The object instance\n * @returns - The key to use for looking up this object's result in the FunctionsMap\n */\n getKey: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => string;\n\n /**\n * Function to extract the cell value from the raw cell data returned by the function.\n * This is useful when functions return custom types with multiple properties.\n * @param cellData - The raw data returned by the function for this object\n * @returns - The value to display in the cell\n */\n getValue?: (cellData?: unknown) => unknown;\n\n /**\n * Minimum time between re-fetches of the same function with the same parameters, in milliseconds.\n * Defaults to 5 minutes as it is expensive to fetch function columns for a large object set\n * and they are expected to be relatively static in the context of an object table\n *\n * @default 300_000 (5 minutes)\n */\n dedupeIntervalMs?: number;\n\n /**\n * Object type apiNames the function reads but doesn't take as a parameter (e.g.\n * linked object types the function traverses internally). The column auto-revalidates\n * when an action edits an object of any of these types. Param-derived types are\n * tracked automatically and don't need to be listed here.\n */\n dependsOn?: string[];\n}\n\n/**\n * Distributes over each key in FunctionColumns so that id, queryDefinition,\n * and getFunctionParams are correlated per key.\n */\nexport type FunctionColumnLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> = keyof FunctionColumns extends infer K\n ? K extends keyof FunctionColumns\n ? FunctionColumnLocatorForKey<Q, RDPs, FunctionColumns, K>\n : never\n : never;\n\nexport interface RdpColumnLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n type: \"rdp\";\n id: keyof RDPs;\n creator: DerivedProperty.Creator<Q, RDPs[keyof RDPs]>;\n}\n\nexport interface CustomColumnLocator {\n type: \"custom\";\n id: string;\n}\n\nexport type ColumnDefinitionLocator<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> =\n | PropertyColumnLocator<Q>\n | FunctionColumnLocator<Q, RDPs, FunctionColumns>\n | RdpColumnLocator<Q, RDPs>\n | CustomColumnLocator;\n\nexport interface ObjectTableProps<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n /**\n * The object or interface type of the object\n * If objectSet is not provided, objects will be fetched based on this type.\n */\n objectType: Q;\n\n /**\n * Ref-like handle for reading a point-in-time snapshot of the currently\n * loaded table data and pagination state.\n *\n * The handle is exposed as a named prop rather than React's reserved `ref`\n * prop so ObjectTable can preserve its generic component signature.\n */\n tableRef?: React.Ref<ObjectTableHandle<Q, RDPs>>;\n\n /**\n * The set of objects to show in the table.\n * If provided and the objectType is not an interface, the table will use objectSet to fetch objects instead of fetching based on objectType.\n */\n objectSet?: ObjectSet<Q>;\n\n objectSetOptions?: ObjectSetOptions<Q>;\n\n /**\n * Minimum time between fetch requests in milliseconds.\n * Increasing this value reduces redundant network calls when the same data\n * is requested multiple times in quick succession.\n *\n * @default 60_000 1 minute\n */\n dedupeIntervalMs?: number;\n\n /**\n * Enable streaming updates via websocket subscription.\n * When true, the table will automatically update when matching\n * objects are added, updated, or removed in Foundry.\n *\n * Limitations: `streamUpdates` cannot be used together with `pivotTo` or\n * `withProperties`. The server does not support websocket subscriptions\n * for link-traversal or derived-property queries. Those queries still\n * fetch data normally but won't receive real-time updates.\n *\n * @default false\n */\n streamUpdates?: boolean;\n\n /**\n * Number of objects to fetch per page.\n *\n * @default 50\n */\n pageSize?: number;\n\n /**\n * Ordered list of column definitions to show in the table\n *\n * If not provided, all of the properties of the object type will be shown in default order.\n */\n columnDefinitions?: Array<ColumnDefinition<Q, RDPs, FunctionColumns>>;\n\n /**\n * Whether the table is filterable by the user.\n *\n * @default true\n */\n enableFiltering?: boolean;\n\n /**\n * The current where clause to filter the objects in the table.\n * If provided, the filter is controlled.\n */\n filter?: WhereClause<Q, RDPs>;\n\n /**\n * Called when the where clause is changed.\n * Required when filter is controlled.\n *\n * @param newWhere The new where clause\n */\n onFilterChanged?: (newWhere: WhereClause<Q, RDPs>) => void;\n\n /**\n * Whether the table is sortable by the user.\n *\n * @default true\n */\n enableOrdering?: boolean;\n\n /**\n * Whether columns can be pinned by the user.\n *\n * @default true\n */\n enableColumnPinning?: boolean;\n\n /**\n * Whether columns can be resized by the user.\n *\n * @default true\n */\n enableColumnResizing?: boolean;\n\n /**\n * Whether the column configuration dialog for column visibility and ordering is available to the user.\n *\n * @default true\n */\n enableColumnConfig?: boolean;\n\n /**\n * Controls the edit mode behavior of the table.\n * - \"always\": Editable cells are immediately in edit mode on row clicked.\n * - \"manual\": User can toggle edit mode on/off via the Edit Table button.\n *\n * @default \"manual\"\n */\n editMode?: \"always\" | \"manual\";\n\n /**\n * Whether to render the bottom edit footer that hosts the\n * \"Edit Table\" / \"Cancel\" / \"Submit Edits\" buttons and the edit-state\n * indicators (modification count, validation errors).\n *\n * @default true whenever the table has at least one column declared\n * editable (i.e. any column with `editable: true` or `editable: (object) => boolean`).\n * When `false`, the \"Edit Table\" and \"Submit Edits\" buttons will not be shown.\n */\n showEditFooter?: boolean;\n\n /**\n * The default order by clause to sort the objects in the table.\n * If provided without orderBy prop, the sorting is uncontrolled.\n * If both orderBy and defaultOrderBy are provided, orderBy takes precedence.\n */\n defaultOrderBy?: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>;\n\n /**\n * The current order by clause to sort the objects in the table.\n * If provided, the sorting is controlled.\n * If both orderBy and defaultOrderBy are provided, orderBy takes precedence.\n */\n orderBy?: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>;\n\n /**\n * Called when the order by clause is changed.\n * Required when sorting is controlled.\n *\n * @param newOrderBy The new order by clause\n */\n onOrderByChanged?: (\n newOrderBy: Array<{\n property: PropertyKeys<Q> | keyof RDPs;\n direction: \"asc\" | \"desc\";\n }>,\n ) => void;\n\n /**\n * Called after the value of a cell is edited and committed by the user.\n *\n * @param info An object containing details about the cell that was edited,\n * including the rowId, columnId, new and old values, and the row data before the edit\n */\n onCellValueChanged?: (\n info: CellEditInfo<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >,\n ) => void;\n\n /**\n * If provided, the \"Submit Edits\" button will be shown in the edit footer.\n *\n * @param edits an array of edit info containing details about the edited cells\n * including the rowId, columnId, new and old values, and the row data before the edit\n * @return a promise that resolves to true if the edits were successfully submitted\n */\n onSubmitEdits?: (edits: CellEditInfo<\n Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n unknown\n >[]) => Promise<boolean>;\n\n /**\n * Called when the column visibility or ordering changed.\n *\n * If provided, the table will allow the user to show/hide columns.\n *\n * @param newStates The columns sorted in their display order in the table and their visibility state.\n */\n onColumnVisibilityChanged?: (\n newStates: Array<{\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns;\n isVisible: boolean;\n }>,\n ) => void;\n\n /**\n * Called when the pinned columns change.\n *\n * If provided, the table will allow the user to pin/unpin columns.\n *\n * @param newStates The new list of column pin states\n */\n onColumnsPinnedChanged?: (\n newStates: Array<{\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns;\n pinned: \"left\" | \"right\" | \"none\";\n }>,\n ) => void;\n\n /**\n * Called when a column is resized.\n *\n * @param columnId The ID of the resized column\n * @param newWidth The new width of the column. When newWidth = null, the column size is reset.\n */\n onColumnResize?: (\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns,\n newWidth: number | null,\n ) => void;\n\n /**\n * Called when a row is clicked.\n *\n * @param object The object representing the clicked row\n */\n onRowClick?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => void;\n\n /**\n * Called when a column header is clicked.\n *\n * The columnId matches the `locator.id` configured on the column definition.\n * The dropdown menu trigger is excluded — clicking the chevron opens the\n * header menu instead of firing this callback.\n *\n * @param columnId The id of the clicked column\n */\n onColumnHeaderClick?: (\n columnId: PropertyKeys<Q> | keyof RDPs | keyof FunctionColumns,\n ) => void;\n\n /**\n * Selection mode for the table rows.\n *\n * If multiple, a checkbox will be shown for each row to allow selecting multiple rows\n * as well as a top-level checkbox in the header to select all rows.\n *\n * @default \"none\"\n */\n selectionMode?: \"single\" | \"multiple\" | \"none\";\n\n /**\n * The currently selected rows in the table.\n * If provided, the row selection is controlled.\n */\n selectedRows?: PrimaryKeyType<Q>[];\n\n /**\n * Indicates whether all rows are selected in controlled mode.\n * When true, the table will show all rows as selected regardless of the selectedRows array.\n */\n isAllSelected?: boolean;\n\n /**\n * Called when the row selection changes.\n *\n * @deprecated Use {@link onRowSelectionChanged} instead. The new callback\n * delivers a {@link RowSelectionChange} object with `selectedRows`,\n * `isSelectAll`, and a derived `objectSet`. This legacy callback\n * continues to fire alongside the new one for backwards compatibility.\n *\n * @param selectedRowIds The primary keys of currently selected rows\n * @param isSelectAll Whether the change was triggered by a \"select all\" action. Defaults to false\n */\n onRowSelection?: (\n selectedRowIds: PrimaryKeyType<Q>[],\n isSelectAll?: boolean,\n ) => void;\n\n /**\n * Called when the row selection changes, with a {@link RowSelectionChange}\n * payload describing the new state.\n *\n * @param change The new selection state. See {@link RowSelectionChange}.\n */\n onRowSelectionChanged?: (\n change: RowSelectionChange<Q, RDPs>,\n ) => void;\n /**\n * If provided, will render this context menu when right clicking on a cell\n */\n renderCellContextMenu?: (\n row: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n cellValue: unknown,\n ) => React.ReactNode;\n\n /**\n * Render override for the empty state. Called when the table has no\n * rows and no error. When omitted, a default \"No Data\" indicator is\n * rendered.\n */\n renderEmptyState?: () => React.ReactNode;\n\n /**\n * The height of each row in pixels.\n *\n * @default 40\n */\n rowHeight?: number;\n\n /**\n * Returns extra HTML attributes (typically `data-*`) to apply to each\n * row element. Use this to drive conditional row styling\n */\n getRowAttributes?: (\n object: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>,\n ) => Record<string, string | undefined>;\n\n className?: string;\n}\n\n/**\n * Payload for {@link ObjectTableProps.onRowSelectionChanged}. Consolidates\n * the loaded row instances, the `isSelectAll` semantic intent, and an\n * `ObjectSet` covering the selection.\n */\nexport interface RowSelectionChange<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n /**\n * Loaded row instances currently selected. When `isSelectAll` is true,\n * this reflects only the rows currently in the table — pages not yet\n * fetched are absent. Use `objectSet` for the cross-page view, and\n * `selectedRows.map(r => r.$primaryKey)` if you need the primary keys.\n */\n selectedRows: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[];\n\n /**\n * True when the user invoked \"select all\" (header checkbox) or when\n * controlled mode supplies `isAllSelected={true}`. Distinct from \"every\n * loaded row happens to be selected\" — that condition is reflected by\n * `selectedRows.length` matching the visible row count but does not set\n * this flag.\n */\n isSelectAll: boolean;\n\n /**\n * An `ObjectSet` representing the selection.\n *\n * - \"Select all\" → the underlying `ObjectSet` (`objectSet` prop if\n * provided, otherwise derived from `objectType` via `client(...)`).\n * This includes rows not yet loaded into the table.\n * - Partial selection → the underlying `ObjectSet` narrowed to\n * `{ [primaryKeyApiName]: { $in: selectedRows.map(r => r.$primaryKey) } }`.\n * - \"Deselect all\" → an empty `ObjectSet` (`$in: []`).\n *\n * `undefined` for interface types without a resolvable\n * `primaryKeyApiName` when the selection is partial or empty (a\n * `$primaryKey`-style filter can't be expressed). For \"select all\" on\n * those types the underlying `ObjectSet` is still emitted.\n */\n objectSet: ObjectSet<Q, RDPs> | undefined;\n}\n\nexport interface ObjectSetOptions<\n Q extends ObjectOrInterfaceDefinition,\n> {\n /**\n * Object sets to union with\n */\n union?: ObjectSet<Q>[];\n\n /**\n * Object sets to intersect with\n */\n intersect?: ObjectSet<Q>[];\n\n /**\n * Object sets to subtract from\n */\n subtract?: ObjectSet<Q>[];\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -207,11 +207,14 @@ function resolveCell(result, objectKey, getValue, prevData) {
|
|
|
207
207
|
data: getValue ? getValue(rawData) : rawData
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
|
-
// Key not in results
|
|
211
|
-
//
|
|
210
|
+
// Key not in results. While the query is still loading, keep showing the
|
|
211
|
+
// previous data so the cell doesn't flash empty during a refetch. Once the
|
|
212
|
+
// query has resolved without an entry for this object, its value is gone —
|
|
213
|
+
// clear the cell instead of retaining the stale previous value (otherwise a
|
|
214
|
+
// cell whose derived value became null keeps displaying the old value).
|
|
212
215
|
return {
|
|
213
216
|
isLoading: result.isLoading,
|
|
214
|
-
data: prevData
|
|
217
|
+
data: result.isLoading ? prevData : undefined
|
|
215
218
|
};
|
|
216
219
|
}
|
|
217
220
|
const useStableObjects = objects => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFunctionColumnsData.js","names":["useOsdkClient","useOsdkFunctions","chunk","useMemo","useRef","createAsyncCellData","DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS","DEFAULT_MAX_CONCURRENT_REQUESTS","DEFAULT_PAGE_SIZE","isObjectType","objectOrInterfaceType","type","useFunctionColumnsData","objects","columnDefinitions","primaryKeyApiName","pageSize","client","prevDataRef","isObjectTypeDefinition","stableObjects","useStableObjects","baseObjectSet","undefined","functionColDefs","extractFunctionLocators","disabled","length","pagedObjectSets","buildPagedObjectSets","queryGrid","EMPTY_QUERY_GRID","buildQueryGrid","results","queries","enabled","maxConcurrent","mergedResults","mergePagedResults","numColumns","data","columnData","buildFunctionColumnData","current","filter","colDef","locator","map","objectSet","page","whereClause","$in","obj","$primaryKey","where","pagedObjects","pagedObjectSet","pageObjects","push","queryDefinition","options","params","getFunctionParams","dedupeIntervalMs","dependsOn","dependsOnObjects","merged","Array","from","isLoading","error","functionsMap","forEach","result","index","entry","pageData","Object","assign","prevColumnData","columnId","String","id","key","prevData","resolveCell","getKey","getValue","objectKey","rawData","JSON","stringify","item","$apiName","sort","a","b","localeCompare"],"sources":["useFunctionColumnsData.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport {\n type FunctionQueryParams,\n useOsdkClient,\n useOsdkFunctions,\n type UseOsdkFunctionsResult,\n} from \"@osdk/react\";\nimport { chunk } from \"lodash-es\";\nimport { useMemo, useRef } from \"react\";\nimport type {\n ColumnDefinition,\n FunctionColumnLocator,\n} from \"../ObjectTableApi.js\";\nimport {\n type AsyncCellData,\n createAsyncCellData,\n} from \"../utils/AsyncCellData.js\";\nimport {\n DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS,\n DEFAULT_MAX_CONCURRENT_REQUESTS,\n DEFAULT_PAGE_SIZE,\n} from \"../utils/constants.js\";\n\nexport interface FunctionColumnData {\n [columnId: string]: {\n [objectPrimaryKey: string]: AsyncCellData;\n };\n}\n\nexport interface UseFunctionColumnsDataOptions<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n objectOrInterfaceType: Q;\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined;\n columnDefinitions?: Array<ColumnDefinition<Q, RDPs, FunctionColumns>>;\n primaryKeyApiName?: string;\n pageSize?: number;\n}\n\nconst isObjectType = (\n objectOrInterfaceType: ObjectOrInterfaceDefinition,\n): objectOrInterfaceType is ObjectTypeDefinition => {\n return objectOrInterfaceType.type === \"object\";\n};\n\nexport function useFunctionColumnsData<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n {\n objectOrInterfaceType,\n objects,\n columnDefinitions,\n primaryKeyApiName,\n pageSize = DEFAULT_PAGE_SIZE,\n }: UseFunctionColumnsDataOptions<Q, RDPs, FunctionColumns>,\n): FunctionColumnData {\n const client = useOsdkClient();\n const prevDataRef = useRef<FunctionColumnData>({});\n\n const isObjectTypeDefinition = objectOrInterfaceType\n && isObjectType(objectOrInterfaceType);\n\n const stableObjects = useStableObjects(objects);\n\n const baseObjectSet: ObjectSet<Q, RDPs> | undefined = useMemo(\n () => {\n return isObjectTypeDefinition\n ? client(objectOrInterfaceType) as ObjectSet<Q, RDPs>\n : undefined;\n },\n [client, isObjectTypeDefinition, objectOrInterfaceType],\n );\n\n const functionColDefs = useMemo(\n () => extractFunctionLocators<Q, RDPs, FunctionColumns>(columnDefinitions),\n [columnDefinitions],\n );\n\n const disabled = !baseObjectSet || !stableObjects?.length\n || functionColDefs.length === 0;\n\n // Construct object sets using the base object set (constructed with object type only)\n // + filter with primary keys of each page's objects\n //\n // When a new page loads, only that page's queries fire — old pages\n // hit the dedupeIntervalMs cache since their params are unchanged.\n const pagedObjectSets = useMemo(() => {\n if (!baseObjectSet || !stableObjects?.length) return [];\n\n return buildPagedObjectSets(\n baseObjectSet,\n stableObjects,\n primaryKeyApiName,\n pageSize,\n );\n }, [baseObjectSet, stableObjects, primaryKeyApiName, pageSize]);\n\n const queryGrid = useMemo(() => {\n if (pagedObjectSets.length === 0 || functionColDefs.length === 0) {\n return EMPTY_QUERY_GRID;\n }\n return buildQueryGrid<Q, RDPs, FunctionColumns>(\n pagedObjectSets,\n functionColDefs,\n );\n }, [pagedObjectSets, functionColDefs]);\n\n const results = useOsdkFunctions({\n queries: queryGrid.queries,\n enabled: !disabled,\n maxConcurrent: DEFAULT_MAX_CONCURRENT_REQUESTS,\n });\n\n const mergedResults = useMemo(\n () => mergePagedResults(results, queryGrid.numColumns),\n [results, queryGrid.numColumns],\n );\n\n const data = useMemo(() => {\n const columnData = buildFunctionColumnData(\n mergedResults,\n functionColDefs,\n stableObjects,\n disabled,\n prevDataRef.current,\n );\n prevDataRef.current = columnData;\n return columnData;\n }, [mergedResults, functionColDefs, stableObjects, disabled]);\n\n return data;\n}\n\n/**\n * Pairs a flat queries array with the layout metadata needed to recover per-column\n * results back into per-column groups. The numColumns value is produced by\n * the same function that builds the queries, so the two are always in sync.\n */\ninterface QueryGrid {\n queries: FunctionQueryParams<QueryDefinition<unknown>>[];\n numColumns: number;\n}\n\ninterface MergedResult {\n isLoading: boolean;\n error: unknown;\n functionsMap: Record<string, unknown>;\n}\n\nconst EMPTY_QUERY_GRID: QueryGrid = { queries: [], numColumns: 0 };\n\n/** Filters columnDefinitions down to only function-backed locators. */\nfunction extractFunctionLocators<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n columnDefinitions:\n | Array<ColumnDefinition<Q, RDPs, FunctionColumns>>\n | undefined,\n): FunctionColumnLocator<Q, RDPs, FunctionColumns>[] {\n if (!columnDefinitions) return [];\n\n return columnDefinitions\n .filter(colDef => colDef.locator.type === \"function\")\n .map(colDef =>\n colDef.locator as FunctionColumnLocator<Q, RDPs, FunctionColumns>\n );\n}\n\n/** A page's filtered ObjectSet paired with the row objects it covers. */\ninterface PagedObjects<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n objectSet: ObjectSet<Q, RDPs>;\n objects: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[];\n}\n\n/** Chunks objects into pages and creates a filtered ObjectSet per page. */\nfunction buildPagedObjectSets<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n>(\n objectSet: ObjectSet<Q, RDPs>,\n objects: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[],\n primaryKeyApiName: string | undefined,\n pageSize: number,\n): PagedObjects<Q, RDPs>[] {\n if (!primaryKeyApiName) {\n return [{ objectSet, objects }];\n }\n\n return chunk(objects, pageSize).map(page => {\n const whereClause = {\n [primaryKeyApiName]: {\n $in: page.map(obj => obj.$primaryKey),\n },\n } as WhereClause<Q, RDPs>;\n\n return { objectSet: objectSet.where(whereClause), objects: page };\n });\n}\n\n/**\n * Builds a flat query array and the layout metadata needed to recover per-column results.\n *\n * Layout: [page0_col0, page0_col1, ..., page1_col0, page1_col1, ...]\n * Page-first ordering ensures first concurrent queries prioritizes the first page,\n * so visible rows get all their columns populated before later pages.\n *\n * Each query carries `dependsOnObjects` (the page's row instances) so that\n * editing any of those rows fans out to invalidate this function query, and\n * `dependsOn` from the locator so that linked-type edits also invalidate.\n */\nfunction buildQueryGrid<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n pagedObjects: PagedObjects<Q, RDPs>[],\n functionColDefs: FunctionColumnLocator<Q, RDPs, FunctionColumns>[],\n): QueryGrid {\n const queries: FunctionQueryParams<QueryDefinition<unknown>>[] = [];\n\n for (\n const { objectSet: pagedObjectSet, objects: pageObjects } of pagedObjects\n ) {\n for (const locator of functionColDefs) {\n queries.push({\n queryDefinition: locator.queryDefinition,\n options: {\n params: locator.getFunctionParams(pagedObjectSet),\n dedupeIntervalMs: locator.dedupeIntervalMs\n ?? DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS,\n dependsOn: locator.dependsOn,\n dependsOnObjects: pageObjects,\n } as FunctionQueryParams<QueryDefinition<unknown>>[\"options\"],\n });\n }\n }\n\n return { queries, numColumns: functionColDefs.length };\n}\n\n/**\n * Merges paged results into one merged result per column.\n * Each column has results spread across pages — this combines their\n * functionsMaps so buildFunctionColumnData can look up any object by key.\n *\n * Relies on QueryGrid layout: results[i] belongs to column (i % numColumns).\n * i.e. the first N results are the first page of each column, the next N results are the second page, etc.\n */\nfunction mergePagedResults(\n results: UseOsdkFunctionsResult,\n numColumns: number,\n): MergedResult[] {\n if (numColumns === 0) return [];\n\n const merged: MergedResult[] = Array.from(\n { length: numColumns },\n () => ({ isLoading: false, error: undefined, functionsMap: {} }),\n );\n\n results.forEach((result, index) => {\n const columnIndex = index % numColumns;\n const entry = merged[columnIndex];\n\n if (result.isLoading) {\n entry.isLoading = true;\n }\n if (result.error) {\n entry.error = result.error;\n }\n const pageData = result.data as Record<string, unknown> | undefined;\n if (pageData) {\n Object.assign(entry.functionsMap, pageData);\n }\n });\n\n return merged;\n}\n\nfunction buildFunctionColumnData<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n results: MergedResult[],\n functionColDefs: FunctionColumnLocator<Q, RDPs, FunctionColumns>[],\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined,\n disabled: boolean,\n prevColumnData: FunctionColumnData,\n): FunctionColumnData {\n const columnData: FunctionColumnData = {};\n\n if (disabled || !objects) return columnData;\n\n results.forEach((result, index) => {\n const locator = functionColDefs[index];\n if (!locator) return;\n\n const columnId = String(locator.id);\n\n columnData[columnId] = {};\n\n objects.forEach(obj => {\n const key = String(obj.$primaryKey);\n const prevData = prevColumnData[columnId]?.[key]?.data;\n\n columnData[columnId][key] = createAsyncCellData(\n resolveCell(\n result,\n locator.getKey(obj),\n locator.getValue,\n prevData,\n ),\n );\n });\n });\n\n return columnData;\n}\n\n/** Resolves the cell state: error, loaded, or loading with previous data. */\nfunction resolveCell(\n result: MergedResult,\n objectKey: string,\n getValue: ((cellData: unknown) => unknown) | undefined,\n prevData: unknown,\n): Omit<AsyncCellData, \"__asyncCell\"> {\n if (result.error) {\n return { isLoading: false, error: result.error };\n }\n if (objectKey in result.functionsMap) {\n const rawData = result.functionsMap[objectKey];\n return { isLoading: false, data: getValue ? getValue(rawData) : rawData };\n }\n // Key not in results — still loading, or query returned no data for this object\n // Return with previous data\n return { isLoading: result.isLoading, data: prevData };\n}\n\nconst useStableObjects = <\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n>(\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined,\n):\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined =>\n{\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => objects, [\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(\n (objects ?? []).map(item => ({\n $apiName: item.$apiName,\n $primaryKey: item.$primaryKey,\n })).sort((a, b) => {\n if (a.$apiName !== b.$apiName) {\n return a.$apiName.localeCompare(b.$apiName);\n }\n return String(a.$primaryKey).localeCompare(String(b.$primaryKey));\n }),\n ),\n ]);\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"useFunctionColumnsData.js","names":["useOsdkClient","useOsdkFunctions","chunk","useMemo","useRef","createAsyncCellData","DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS","DEFAULT_MAX_CONCURRENT_REQUESTS","DEFAULT_PAGE_SIZE","isObjectType","objectOrInterfaceType","type","useFunctionColumnsData","objects","columnDefinitions","primaryKeyApiName","pageSize","client","prevDataRef","isObjectTypeDefinition","stableObjects","useStableObjects","baseObjectSet","undefined","functionColDefs","extractFunctionLocators","disabled","length","pagedObjectSets","buildPagedObjectSets","queryGrid","EMPTY_QUERY_GRID","buildQueryGrid","results","queries","enabled","maxConcurrent","mergedResults","mergePagedResults","numColumns","data","columnData","buildFunctionColumnData","current","filter","colDef","locator","map","objectSet","page","whereClause","$in","obj","$primaryKey","where","pagedObjects","pagedObjectSet","pageObjects","push","queryDefinition","options","params","getFunctionParams","dedupeIntervalMs","dependsOn","dependsOnObjects","merged","Array","from","isLoading","error","functionsMap","forEach","result","index","entry","pageData","Object","assign","prevColumnData","columnId","String","id","key","prevData","resolveCell","getKey","getValue","objectKey","rawData","JSON","stringify","item","$apiName","sort","a","b","localeCompare"],"sources":["useFunctionColumnsData.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n PropertyKeys,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n} from \"@osdk/api\";\nimport {\n type FunctionQueryParams,\n useOsdkClient,\n useOsdkFunctions,\n type UseOsdkFunctionsResult,\n} from \"@osdk/react\";\nimport { chunk } from \"lodash-es\";\nimport { useMemo, useRef } from \"react\";\nimport type {\n ColumnDefinition,\n FunctionColumnLocator,\n} from \"../ObjectTableApi.js\";\nimport {\n type AsyncCellData,\n createAsyncCellData,\n} from \"../utils/AsyncCellData.js\";\nimport {\n DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS,\n DEFAULT_MAX_CONCURRENT_REQUESTS,\n DEFAULT_PAGE_SIZE,\n} from \"../utils/constants.js\";\n\nexport interface FunctionColumnData {\n [columnId: string]: {\n [objectPrimaryKey: string]: AsyncCellData;\n };\n}\n\nexport interface UseFunctionColumnsDataOptions<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n> {\n objectOrInterfaceType: Q;\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined;\n columnDefinitions?: Array<ColumnDefinition<Q, RDPs, FunctionColumns>>;\n primaryKeyApiName?: string;\n pageSize?: number;\n}\n\nconst isObjectType = (\n objectOrInterfaceType: ObjectOrInterfaceDefinition,\n): objectOrInterfaceType is ObjectTypeDefinition => {\n return objectOrInterfaceType.type === \"object\";\n};\n\nexport function useFunctionColumnsData<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n {\n objectOrInterfaceType,\n objects,\n columnDefinitions,\n primaryKeyApiName,\n pageSize = DEFAULT_PAGE_SIZE,\n }: UseFunctionColumnsDataOptions<Q, RDPs, FunctionColumns>,\n): FunctionColumnData {\n const client = useOsdkClient();\n const prevDataRef = useRef<FunctionColumnData>({});\n\n const isObjectTypeDefinition = objectOrInterfaceType\n && isObjectType(objectOrInterfaceType);\n\n const stableObjects = useStableObjects(objects);\n\n const baseObjectSet: ObjectSet<Q, RDPs> | undefined = useMemo(\n () => {\n return isObjectTypeDefinition\n ? client(objectOrInterfaceType) as ObjectSet<Q, RDPs>\n : undefined;\n },\n [client, isObjectTypeDefinition, objectOrInterfaceType],\n );\n\n const functionColDefs = useMemo(\n () => extractFunctionLocators<Q, RDPs, FunctionColumns>(columnDefinitions),\n [columnDefinitions],\n );\n\n const disabled = !baseObjectSet || !stableObjects?.length\n || functionColDefs.length === 0;\n\n // Construct object sets using the base object set (constructed with object type only)\n // + filter with primary keys of each page's objects\n //\n // When a new page loads, only that page's queries fire — old pages\n // hit the dedupeIntervalMs cache since their params are unchanged.\n const pagedObjectSets = useMemo(() => {\n if (!baseObjectSet || !stableObjects?.length) return [];\n\n return buildPagedObjectSets(\n baseObjectSet,\n stableObjects,\n primaryKeyApiName,\n pageSize,\n );\n }, [baseObjectSet, stableObjects, primaryKeyApiName, pageSize]);\n\n const queryGrid = useMemo(() => {\n if (pagedObjectSets.length === 0 || functionColDefs.length === 0) {\n return EMPTY_QUERY_GRID;\n }\n return buildQueryGrid<Q, RDPs, FunctionColumns>(\n pagedObjectSets,\n functionColDefs,\n );\n }, [pagedObjectSets, functionColDefs]);\n\n const results = useOsdkFunctions({\n queries: queryGrid.queries,\n enabled: !disabled,\n maxConcurrent: DEFAULT_MAX_CONCURRENT_REQUESTS,\n });\n\n const mergedResults = useMemo(\n () => mergePagedResults(results, queryGrid.numColumns),\n [results, queryGrid.numColumns],\n );\n\n const data = useMemo(() => {\n const columnData = buildFunctionColumnData(\n mergedResults,\n functionColDefs,\n stableObjects,\n disabled,\n prevDataRef.current,\n );\n prevDataRef.current = columnData;\n return columnData;\n }, [mergedResults, functionColDefs, stableObjects, disabled]);\n\n return data;\n}\n\n/**\n * Pairs a flat queries array with the layout metadata needed to recover per-column\n * results back into per-column groups. The numColumns value is produced by\n * the same function that builds the queries, so the two are always in sync.\n */\ninterface QueryGrid {\n queries: FunctionQueryParams<QueryDefinition<unknown>>[];\n numColumns: number;\n}\n\ninterface MergedResult {\n isLoading: boolean;\n error: unknown;\n functionsMap: Record<string, unknown>;\n}\n\nconst EMPTY_QUERY_GRID: QueryGrid = { queries: [], numColumns: 0 };\n\n/** Filters columnDefinitions down to only function-backed locators. */\nfunction extractFunctionLocators<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n columnDefinitions:\n | Array<ColumnDefinition<Q, RDPs, FunctionColumns>>\n | undefined,\n): FunctionColumnLocator<Q, RDPs, FunctionColumns>[] {\n if (!columnDefinitions) return [];\n\n return columnDefinitions\n .filter(colDef => colDef.locator.type === \"function\")\n .map(colDef =>\n colDef.locator as FunctionColumnLocator<Q, RDPs, FunctionColumns>\n );\n}\n\n/** A page's filtered ObjectSet paired with the row objects it covers. */\ninterface PagedObjects<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n> {\n objectSet: ObjectSet<Q, RDPs>;\n objects: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[];\n}\n\n/** Chunks objects into pages and creates a filtered ObjectSet per page. */\nfunction buildPagedObjectSets<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n>(\n objectSet: ObjectSet<Q, RDPs>,\n objects: Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[],\n primaryKeyApiName: string | undefined,\n pageSize: number,\n): PagedObjects<Q, RDPs>[] {\n if (!primaryKeyApiName) {\n return [{ objectSet, objects }];\n }\n\n return chunk(objects, pageSize).map(page => {\n const whereClause = {\n [primaryKeyApiName]: {\n $in: page.map(obj => obj.$primaryKey),\n },\n } as WhereClause<Q, RDPs>;\n\n return { objectSet: objectSet.where(whereClause), objects: page };\n });\n}\n\n/**\n * Builds a flat query array and the layout metadata needed to recover per-column results.\n *\n * Layout: [page0_col0, page0_col1, ..., page1_col0, page1_col1, ...]\n * Page-first ordering ensures first concurrent queries prioritizes the first page,\n * so visible rows get all their columns populated before later pages.\n *\n * Each query carries `dependsOnObjects` (the page's row instances) so that\n * editing any of those rows fans out to invalidate this function query, and\n * `dependsOn` from the locator so that linked-type edits also invalidate.\n */\nfunction buildQueryGrid<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n pagedObjects: PagedObjects<Q, RDPs>[],\n functionColDefs: FunctionColumnLocator<Q, RDPs, FunctionColumns>[],\n): QueryGrid {\n const queries: FunctionQueryParams<QueryDefinition<unknown>>[] = [];\n\n for (\n const { objectSet: pagedObjectSet, objects: pageObjects } of pagedObjects\n ) {\n for (const locator of functionColDefs) {\n queries.push({\n queryDefinition: locator.queryDefinition,\n options: {\n params: locator.getFunctionParams(pagedObjectSet),\n dedupeIntervalMs: locator.dedupeIntervalMs\n ?? DEFAULT_FUNCTION_COLUMN_DEDUPE_INTERVAL_MS,\n dependsOn: locator.dependsOn,\n dependsOnObjects: pageObjects,\n } as FunctionQueryParams<QueryDefinition<unknown>>[\"options\"],\n });\n }\n }\n\n return { queries, numColumns: functionColDefs.length };\n}\n\n/**\n * Merges paged results into one merged result per column.\n * Each column has results spread across pages — this combines their\n * functionsMaps so buildFunctionColumnData can look up any object by key.\n *\n * Relies on QueryGrid layout: results[i] belongs to column (i % numColumns).\n * i.e. the first N results are the first page of each column, the next N results are the second page, etc.\n */\nfunction mergePagedResults(\n results: UseOsdkFunctionsResult,\n numColumns: number,\n): MergedResult[] {\n if (numColumns === 0) return [];\n\n const merged: MergedResult[] = Array.from(\n { length: numColumns },\n () => ({ isLoading: false, error: undefined, functionsMap: {} }),\n );\n\n results.forEach((result, index) => {\n const columnIndex = index % numColumns;\n const entry = merged[columnIndex];\n\n if (result.isLoading) {\n entry.isLoading = true;\n }\n if (result.error) {\n entry.error = result.error;\n }\n const pageData = result.data as Record<string, unknown> | undefined;\n if (pageData) {\n Object.assign(entry.functionsMap, pageData);\n }\n });\n\n return merged;\n}\n\nfunction buildFunctionColumnData<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n FunctionColumns extends Record<string, QueryDefinition<{}>> = Record<\n string,\n never\n >,\n>(\n results: MergedResult[],\n functionColDefs: FunctionColumnLocator<Q, RDPs, FunctionColumns>[],\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined,\n disabled: boolean,\n prevColumnData: FunctionColumnData,\n): FunctionColumnData {\n const columnData: FunctionColumnData = {};\n\n if (disabled || !objects) return columnData;\n\n results.forEach((result, index) => {\n const locator = functionColDefs[index];\n if (!locator) return;\n\n const columnId = String(locator.id);\n\n columnData[columnId] = {};\n\n objects.forEach(obj => {\n const key = String(obj.$primaryKey);\n const prevData = prevColumnData[columnId]?.[key]?.data;\n\n columnData[columnId][key] = createAsyncCellData(\n resolveCell(\n result,\n locator.getKey(obj),\n locator.getValue,\n prevData,\n ),\n );\n });\n });\n\n return columnData;\n}\n\n/** Resolves the cell state: error, loaded, or loading with previous data. */\nfunction resolveCell(\n result: MergedResult,\n objectKey: string,\n getValue: ((cellData: unknown) => unknown) | undefined,\n prevData: unknown,\n): Omit<AsyncCellData, \"__asyncCell\"> {\n if (result.error) {\n return { isLoading: false, error: result.error };\n }\n if (objectKey in result.functionsMap) {\n const rawData = result.functionsMap[objectKey];\n return { isLoading: false, data: getValue ? getValue(rawData) : rawData };\n }\n // Key not in results. While the query is still loading, keep showing the\n // previous data so the cell doesn't flash empty during a refetch. Once the\n // query has resolved without an entry for this object, its value is gone —\n // clear the cell instead of retaining the stale previous value (otherwise a\n // cell whose derived value became null keeps displaying the old value).\n return {\n isLoading: result.isLoading,\n data: result.isLoading ? prevData : undefined,\n };\n}\n\nconst useStableObjects = <\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = Record<string, never>,\n>(\n objects:\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined,\n):\n | Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>[]\n | undefined =>\n{\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => objects, [\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(\n (objects ?? []).map(item => ({\n $apiName: item.$apiName,\n $primaryKey: item.$primaryKey,\n })).sort((a, b) => {\n if (a.$apiName !== b.$apiName) {\n return a.$apiName.localeCompare(b.$apiName);\n }\n return String(a.$primaryKey).localeCompare(String(b.$primaryKey));\n }),\n ),\n ]);\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { useCallback, useImperativeHandle, useLayoutEffect, useReducer, useRef } from "react";
|
|
18
|
+
import { createObjectTableSnapshot } from "../utils/createObjectTableSnapshot.js";
|
|
19
|
+
/**
|
|
20
|
+
* Exposes `getSnapshot` on `tableRef`. A snapshot is a point-in-time read of the
|
|
21
|
+
* table's committed rows and pagination state. When a caller passes a positive
|
|
22
|
+
* `rowLimit`, `getSnapshot` pages through `fetchMore` until it has at least
|
|
23
|
+
* that many rows (or the data set is exhausted / errors), then resolves.
|
|
24
|
+
* `rowLimit` is not a hard cap because ObjectTable keeps already-loaded rows
|
|
25
|
+
* and fetches complete pages.
|
|
26
|
+
*/
|
|
27
|
+
export function useObjectTableSnapshotHandle({
|
|
28
|
+
tableRef,
|
|
29
|
+
table,
|
|
30
|
+
hasNextPage,
|
|
31
|
+
isLoading,
|
|
32
|
+
error,
|
|
33
|
+
totalCount,
|
|
34
|
+
fetchMore
|
|
35
|
+
}) {
|
|
36
|
+
// Bumped to force a render so the layout effect below republishes the latest
|
|
37
|
+
// inputs. Used as a fallback after a fetch whose committed page arrived before
|
|
38
|
+
// the loop parked its waiter, guaranteeing the parked waiter still resolves.
|
|
39
|
+
const [, forceCommit] = useReducer(version => version + 1, 0);
|
|
40
|
+
|
|
41
|
+
// Latest committed inputs and fetchMore, refreshed on every commit. The
|
|
42
|
+
// imperative handle reads from these so it always sees current data without
|
|
43
|
+
// re-subscribing.
|
|
44
|
+
const inputsRef = useRef({
|
|
45
|
+
table,
|
|
46
|
+
hasNextPage,
|
|
47
|
+
isLoading,
|
|
48
|
+
error,
|
|
49
|
+
totalCount
|
|
50
|
+
});
|
|
51
|
+
const fetchMoreRef = useRef(fetchMore);
|
|
52
|
+
|
|
53
|
+
// Resolvers for in-flight getSnapshot loops parked until the next commit.
|
|
54
|
+
const commitWaitersRef = useRef([]);
|
|
55
|
+
const mountedRef = useRef(true);
|
|
56
|
+
// Resolves when the component unmounts, letting an awaiting fetch bail out
|
|
57
|
+
// instead of stranding the caller's promise forever.
|
|
58
|
+
const unmountedRef = useRef(createDeferred());
|
|
59
|
+
useLayoutEffect(function () {
|
|
60
|
+
inputsRef.current = {
|
|
61
|
+
table,
|
|
62
|
+
hasNextPage,
|
|
63
|
+
isLoading,
|
|
64
|
+
error,
|
|
65
|
+
totalCount
|
|
66
|
+
};
|
|
67
|
+
fetchMoreRef.current = fetchMore;
|
|
68
|
+
drainWaiters(commitWaitersRef);
|
|
69
|
+
});
|
|
70
|
+
useLayoutEffect(function () {
|
|
71
|
+
mountedRef.current = true;
|
|
72
|
+
unmountedRef.current = createDeferred();
|
|
73
|
+
return () => {
|
|
74
|
+
mountedRef.current = false;
|
|
75
|
+
unmountedRef.current.resolve();
|
|
76
|
+
drainWaiters(commitWaitersRef);
|
|
77
|
+
};
|
|
78
|
+
}, []);
|
|
79
|
+
const readSnapshot = useCallback(function () {
|
|
80
|
+
// Materializing a snapshot walks every row and visible column, so keep it
|
|
81
|
+
// lazy — ObjectTable renders never pay for it unless a caller asks.
|
|
82
|
+
return createObjectTableSnapshot(inputsRef.current);
|
|
83
|
+
}, []);
|
|
84
|
+
const waitForNextCommit = useCallback(function () {
|
|
85
|
+
if (!mountedRef.current) {
|
|
86
|
+
return Promise.resolve();
|
|
87
|
+
}
|
|
88
|
+
return new Promise(resolve => {
|
|
89
|
+
commitWaitersRef.current.push(resolve);
|
|
90
|
+
// fetchMore resolves once the store holds the next page, but its commit
|
|
91
|
+
// may have landed before we parked above (or the page was identical and
|
|
92
|
+
// produced none). Force a commit so this resolves either way.
|
|
93
|
+
forceCommit();
|
|
94
|
+
});
|
|
95
|
+
}, []);
|
|
96
|
+
const getSnapshot = useCallback(async function (options) {
|
|
97
|
+
const rowLimit = normalizeRowLimit(options?.rowLimit);
|
|
98
|
+
if (rowLimit == null) {
|
|
99
|
+
return readSnapshot();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check pagination state off the committed inputs directly rather than
|
|
103
|
+
// materializing a full snapshot each pass — the loop only needs the row
|
|
104
|
+
// count and terminal flags, so the row/cell walk happens once, at return.
|
|
105
|
+
let inputs = inputsRef.current;
|
|
106
|
+
while (countRows(inputs) < rowLimit && inputs.hasNextPage && inputs.error == null) {
|
|
107
|
+
// Read the live ref each iteration: fetchMore can flip to/from
|
|
108
|
+
// undefined as pages run out while the loop is awaiting.
|
|
109
|
+
const currentFetchMore = fetchMoreRef.current;
|
|
110
|
+
if (currentFetchMore == null) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
const rowsBefore = countRows(inputs);
|
|
114
|
+
let fetched;
|
|
115
|
+
try {
|
|
116
|
+
// Race unmount so a fetch that never resolves can't strand the caller.
|
|
117
|
+
fetched = await Promise.race([currentFetchMore().then(() => true), unmountedRef.current.promise.then(() => false)]);
|
|
118
|
+
} catch (fetchError) {
|
|
119
|
+
// The underlying table hook normally surfaces fetch failures through
|
|
120
|
+
// committed error state and resolves, in which case the loop exits via
|
|
121
|
+
// `inputs.error` and the snapshot already carries that error. A
|
|
122
|
+
// *rejecting* fetchMore bypasses that committed state, so the latest
|
|
123
|
+
// snapshot wouldn't reflect the failure. Attach it explicitly so
|
|
124
|
+
// paginated callers (e.g. CSV export) can detect an incomplete result
|
|
125
|
+
// via `snapshot.error` instead of silently receiving partial rows.
|
|
126
|
+
const snapshot = readSnapshot();
|
|
127
|
+
return snapshot.error != null ? snapshot : {
|
|
128
|
+
...snapshot,
|
|
129
|
+
error: fetchError
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (!fetched || !mountedRef.current) {
|
|
133
|
+
return readSnapshot();
|
|
134
|
+
}
|
|
135
|
+
await waitForNextCommit();
|
|
136
|
+
inputs = inputsRef.current;
|
|
137
|
+
|
|
138
|
+
// A fetch that does not increase the committed row count means we can't
|
|
139
|
+
// make reliable progress toward the limit — stop rather than spin.
|
|
140
|
+
if (countRows(inputs) <= rowsBefore) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return readSnapshot();
|
|
145
|
+
}, [readSnapshot, waitForNextCommit]);
|
|
146
|
+
useImperativeHandle(tableRef, () => ({
|
|
147
|
+
getSnapshot
|
|
148
|
+
}), [getSnapshot]);
|
|
149
|
+
}
|
|
150
|
+
function createDeferred() {
|
|
151
|
+
let resolve;
|
|
152
|
+
const promise = new Promise(resolvePromise => {
|
|
153
|
+
resolve = resolvePromise;
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
promise,
|
|
157
|
+
resolve: () => resolve()
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function countRows(inputs) {
|
|
161
|
+
// getRowModel is memoized by TanStack, so this is cheap to call per loop pass.
|
|
162
|
+
return inputs.table.getRowModel().rows.length;
|
|
163
|
+
}
|
|
164
|
+
function drainWaiters(waitersRef) {
|
|
165
|
+
const waiters = waitersRef.current;
|
|
166
|
+
waitersRef.current = [];
|
|
167
|
+
for (const resolve of waiters) {
|
|
168
|
+
resolve();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function normalizeRowLimit(rowLimit) {
|
|
172
|
+
if (rowLimit == null || rowLimit <= 0 || !Number.isFinite(rowLimit)) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return rowLimit;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=useObjectTableSnapshotHandle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useObjectTableSnapshotHandle.js","names":["useCallback","useImperativeHandle","useLayoutEffect","useReducer","useRef","createObjectTableSnapshot","useObjectTableSnapshotHandle","tableRef","table","hasNextPage","isLoading","error","totalCount","fetchMore","forceCommit","version","inputsRef","fetchMoreRef","commitWaitersRef","mountedRef","unmountedRef","createDeferred","current","drainWaiters","resolve","readSnapshot","waitForNextCommit","Promise","push","getSnapshot","options","rowLimit","normalizeRowLimit","inputs","countRows","currentFetchMore","rowsBefore","fetched","race","then","promise","fetchError","snapshot","resolvePromise","getRowModel","rows","length","waitersRef","waiters","Number","isFinite","undefined"],"sources":["useObjectTableSnapshotHandle.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n Osdk,\n PropertyKeys,\n SimplePropertyDef,\n} from \"@osdk/api\";\nimport type { Table } from \"@tanstack/react-table\";\nimport type { Ref } from \"react\";\nimport {\n useCallback,\n useImperativeHandle,\n useLayoutEffect,\n useReducer,\n useRef,\n} from \"react\";\nimport type {\n ObjectTableHandle,\n ObjectTableSnapshot,\n ObjectTableSnapshotOptions,\n} from \"../ObjectTableApi.js\";\nimport { createObjectTableSnapshot } from \"../utils/createObjectTableSnapshot.js\";\n\ntype ObjectTableRow<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n> = Osdk.Instance<Q, \"$allBaseProperties\", PropertyKeys<Q>, RDPs>;\n\ninterface SnapshotInputs<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n> {\n table: Table<ObjectTableRow<Q, RDPs>>;\n hasNextPage: boolean;\n isLoading: boolean;\n error: unknown;\n totalCount: string | undefined;\n}\n\ninterface UseObjectTableSnapshotHandleParams<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n> extends SnapshotInputs<Q, RDPs> {\n tableRef?: Ref<ObjectTableHandle<Q, RDPs>>;\n fetchMore: (() => Promise<unknown>) | undefined;\n}\n\n/**\n * Exposes `getSnapshot` on `tableRef`. A snapshot is a point-in-time read of the\n * table's committed rows and pagination state. When a caller passes a positive\n * `rowLimit`, `getSnapshot` pages through `fetchMore` until it has at least\n * that many rows (or the data set is exhausted / errors), then resolves.\n * `rowLimit` is not a hard cap because ObjectTable keeps already-loaded rows\n * and fetches complete pages.\n */\nexport function useObjectTableSnapshotHandle<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n>({\n tableRef,\n table,\n hasNextPage,\n isLoading,\n error,\n totalCount,\n fetchMore,\n}: UseObjectTableSnapshotHandleParams<Q, RDPs>): void {\n // Bumped to force a render so the layout effect below republishes the latest\n // inputs. Used as a fallback after a fetch whose committed page arrived before\n // the loop parked its waiter, guaranteeing the parked waiter still resolves.\n const [, forceCommit] = useReducer((version: number) => version + 1, 0);\n\n // Latest committed inputs and fetchMore, refreshed on every commit. The\n // imperative handle reads from these so it always sees current data without\n // re-subscribing.\n const inputsRef = useRef<SnapshotInputs<Q, RDPs>>({\n table,\n hasNextPage,\n isLoading,\n error,\n totalCount,\n });\n const fetchMoreRef = useRef(fetchMore);\n\n // Resolvers for in-flight getSnapshot loops parked until the next commit.\n const commitWaitersRef = useRef<Array<() => void>>([]);\n\n const mountedRef = useRef(true);\n // Resolves when the component unmounts, letting an awaiting fetch bail out\n // instead of stranding the caller's promise forever.\n const unmountedRef = useRef<Deferred>(createDeferred());\n\n useLayoutEffect(function publishCommit() {\n inputsRef.current = { table, hasNextPage, isLoading, error, totalCount };\n fetchMoreRef.current = fetchMore;\n drainWaiters(commitWaitersRef);\n });\n\n useLayoutEffect(function trackMounted() {\n mountedRef.current = true;\n unmountedRef.current = createDeferred();\n return () => {\n mountedRef.current = false;\n unmountedRef.current.resolve();\n drainWaiters(commitWaitersRef);\n };\n }, []);\n\n const readSnapshot = useCallback(\n function readSnapshot(): ObjectTableSnapshot<Q, RDPs> {\n // Materializing a snapshot walks every row and visible column, so keep it\n // lazy — ObjectTable renders never pay for it unless a caller asks.\n return createObjectTableSnapshot<Q, RDPs>(inputsRef.current);\n },\n [],\n );\n\n const waitForNextCommit = useCallback(function waitForNextCommit(): Promise<\n void\n > {\n if (!mountedRef.current) {\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n commitWaitersRef.current.push(resolve);\n // fetchMore resolves once the store holds the next page, but its commit\n // may have landed before we parked above (or the page was identical and\n // produced none). Force a commit so this resolves either way.\n forceCommit();\n });\n }, []);\n\n const getSnapshot = useCallback(\n async function getSnapshot(\n options?: ObjectTableSnapshotOptions,\n ): Promise<ObjectTableSnapshot<Q, RDPs>> {\n const rowLimit = normalizeRowLimit(options?.rowLimit);\n if (rowLimit == null) {\n return readSnapshot();\n }\n\n // Check pagination state off the committed inputs directly rather than\n // materializing a full snapshot each pass — the loop only needs the row\n // count and terminal flags, so the row/cell walk happens once, at return.\n let inputs = inputsRef.current;\n while (\n countRows(inputs) < rowLimit\n && inputs.hasNextPage\n && inputs.error == null\n ) {\n // Read the live ref each iteration: fetchMore can flip to/from\n // undefined as pages run out while the loop is awaiting.\n const currentFetchMore = fetchMoreRef.current;\n if (currentFetchMore == null) {\n break;\n }\n\n const rowsBefore = countRows(inputs);\n\n let fetched: boolean;\n try {\n // Race unmount so a fetch that never resolves can't strand the caller.\n fetched = await Promise.race([\n currentFetchMore().then(() => true),\n unmountedRef.current.promise.then(() => false),\n ]);\n } catch (fetchError: unknown) {\n // The underlying table hook normally surfaces fetch failures through\n // committed error state and resolves, in which case the loop exits via\n // `inputs.error` and the snapshot already carries that error. A\n // *rejecting* fetchMore bypasses that committed state, so the latest\n // snapshot wouldn't reflect the failure. Attach it explicitly so\n // paginated callers (e.g. CSV export) can detect an incomplete result\n // via `snapshot.error` instead of silently receiving partial rows.\n const snapshot = readSnapshot();\n return snapshot.error != null\n ? snapshot\n : { ...snapshot, error: fetchError };\n }\n if (!fetched || !mountedRef.current) {\n return readSnapshot();\n }\n\n await waitForNextCommit();\n inputs = inputsRef.current;\n\n // A fetch that does not increase the committed row count means we can't\n // make reliable progress toward the limit — stop rather than spin.\n if (countRows(inputs) <= rowsBefore) {\n break;\n }\n }\n\n return readSnapshot();\n },\n [readSnapshot, waitForNextCommit],\n );\n\n useImperativeHandle(tableRef, () => ({ getSnapshot }), [getSnapshot]);\n}\n\ninterface Deferred {\n promise: Promise<void>;\n resolve: () => void;\n}\n\nfunction createDeferred(): Deferred {\n let resolve: () => void;\n const promise = new Promise<void>((resolvePromise) => {\n resolve = resolvePromise;\n });\n return { promise, resolve: () => resolve() };\n}\n\nfunction countRows<\n Q extends ObjectOrInterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef>,\n>(inputs: SnapshotInputs<Q, RDPs>): number {\n // getRowModel is memoized by TanStack, so this is cheap to call per loop pass.\n return inputs.table.getRowModel().rows.length;\n}\n\nfunction drainWaiters(waitersRef: { current: Array<() => void> }): void {\n const waiters = waitersRef.current;\n waitersRef.current = [];\n for (const resolve of waiters) {\n resolve();\n }\n}\n\nfunction normalizeRowLimit(rowLimit: number | undefined): number | undefined {\n if (rowLimit == null || rowLimit <= 0 || !Number.isFinite(rowLimit)) {\n return undefined;\n }\n return rowLimit;\n}\n"],"mappings":"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","ignoreList":[]}
|