({ workspaceId, tableId }: RowMutationContext)
| 863 | * Uses optimistic updates for instant UI feedback on inline cell edits. |
| 864 | */ |
| 865 | export function useUpdateTableRow({ workspaceId, tableId }: RowMutationContext) { |
| 866 | const queryClient = useQueryClient() |
| 867 | |
| 868 | return useMutation({ |
| 869 | mutationKey: tableKeys.rowWrites(tableId), |
| 870 | mutationFn: async ({ rowId, data }: UpdateTableRowParams) => { |
| 871 | return requestJson(updateTableRowContract, { |
| 872 | params: { tableId, rowId }, |
| 873 | body: { workspaceId, data: data as RowData }, |
| 874 | }) |
| 875 | }, |
| 876 | onMutate: async ({ rowId, data }) => { |
| 877 | await queryClient.cancelQueries({ queryKey: tableKeys.rowsRoot(tableId) }) |
| 878 | |
| 879 | const previousQueries = queryClient.getQueriesData< |
| 880 | InfiniteData<TableRowsResponse, TableRowsPageParam> |
| 881 | >({ |
| 882 | queryKey: tableKeys.rowsRoot(tableId), |
| 883 | }) |
| 884 | |
| 885 | const groups = |
| 886 | queryClient.getQueryData<TableDefinition>(tableKeys.detail(tableId))?.schema |
| 887 | .workflowGroups ?? [] |
| 888 | |
| 889 | const stampedByRow: Record<string, number> = {} |
| 890 | patchCachedRows(queryClient, tableId, (row) => { |
| 891 | if (row.id !== rowId) return row |
| 892 | const patch = data as Partial<RowData> |
| 893 | const nextExecutions = optimisticallyScheduleNewlyEligibleGroups(groups, row, patch) |
| 894 | if (nextExecutions) { |
| 895 | stampedByRow[row.id] = countNewlyInFlight(row.executions ?? {}, nextExecutions) |
| 896 | } |
| 897 | return { |
| 898 | ...row, |
| 899 | data: { ...row.data, ...patch } as RowData, |
| 900 | ...(nextExecutions ? { executions: nextExecutions } : {}), |
| 901 | } |
| 902 | }) |
| 903 | |
| 904 | const bumped = bumpRunState(queryClient, tableId, stampedByRow) |
| 905 | return { |
| 906 | previousQueries, |
| 907 | runStateSnapshot: bumped?.snapshot, |
| 908 | didBumpRunState: bumped !== null, |
| 909 | } |
| 910 | }, |
| 911 | onSuccess: (response, { rowId, data: mutatedData }) => { |
| 912 | const serverRow = response.data.row |
| 913 | const mutatedKeys = Object.keys(mutatedData) |
| 914 | patchCachedRows(queryClient, tableId, (row) => { |
| 915 | if (row.id !== rowId) return row |
| 916 | const merged: RowData = { ...row.data } |
| 917 | for (const key of mutatedKeys) { |
| 918 | merged[key] = (serverRow.data as RowData)[key] |
| 919 | } |
| 920 | return { |
| 921 | ...row, |
| 922 | data: merged, |
no test coverage detected