streaksheet
Advanced tools
Comparing version 0.8.36 to 0.9.0
@@ -72,15 +72,2 @@ import type { ComponentType } from 'react'; | ||
} | ||
export declare type RowMutation<T> = RowAddMutation<T> | RowDeleteMutation; | ||
export interface RowAddMutation<T> { | ||
type: 'ADD'; | ||
sectionKey: string; | ||
rowKey: string; | ||
rowData: T; | ||
afterRowKey?: string; | ||
} | ||
export interface RowDeleteMutation { | ||
type: 'DELETE'; | ||
sectionKey: string; | ||
rowKey: string; | ||
} | ||
interface BaseStartedRowsRequest { | ||
@@ -98,6 +85,2 @@ direction: 'forward' | 'backward'; | ||
} | ||
export interface LocalStartedRowsRequest<T> extends BaseStartedRowsRequest { | ||
type: 'LOCAL'; | ||
rows: Row<T>[]; | ||
} | ||
export interface ResolvedStartedRowsRequest<T> extends BaseStartedRowsRequest { | ||
@@ -109,3 +92,3 @@ type: 'RESOLVED'; | ||
} | ||
export declare type StartedRowsRequest = UnresolvedStartedRowsRequest | ResolvedStartedRowsRequest<any> | LocalStartedRowsRequest<any>; | ||
export declare type StartedRowsRequest = UnresolvedStartedRowsRequest | ResolvedStartedRowsRequest<any>; | ||
export interface StartedRowsRequests { | ||
@@ -112,0 +95,0 @@ [sectionKey: string]: Array<StartedRowsRequest>; |
@@ -46,3 +46,2 @@ "use strict"; | ||
// We're assuming the local row should affect offsets and such, i.e. that the write had succeeded | ||
case 'LOCAL': | ||
case 'UNRESOLVED': | ||
@@ -49,0 +48,0 @@ { |
@@ -1,4 +0,5 @@ | ||
import { RowMutation, RowsBySection, StartedRowsRequests, UnresolvedStartedRowsRequest } from './internalTypes'; | ||
import { DataHandler, ExposedRowsResult, Section } from './useSheetData'; | ||
import { RowsBySection, StartedRowsRequests, UnresolvedStartedRowsRequest } from './internalTypes'; | ||
import { DataHandler, ExposedRowsResult, LocalRowMutation, Section } from './useSheetData'; | ||
export interface RowsBySectionOptions<T> { | ||
mutations: Array<LocalRowMutation<T>>; | ||
sections: Array<Section>; | ||
@@ -14,9 +15,6 @@ dataHandler: DataHandler<T>; | ||
rowsBySection: RowsBySection<T>; | ||
addRowData(sectionKey: string, rowKey: string, rowData: T, afterRowKey?: string): boolean; | ||
deleteRowData(sectionKey: string, rowKey: string): boolean; | ||
setRowData(rowKey: string, rowData: T): void; | ||
getRowData(sectionKey: string, rowKey: string): T | undefined; | ||
getEffectiveSectionRemoteRowCount(section: Section): number; | ||
getEffectiveSectionRowCount(section: Section): number; | ||
} | ||
export declare type LocalRowMutations<T> = ReadonlyArray<RowMutation<T>>; | ||
export default function useRowsBySection<T>({ sections, dataHandler, refreshColumnAndOverviewData, }: RowsBySectionOptions<T>): RowsBySectionResult<T>; | ||
export default function useRowsBySection<T>({ mutations, sections, dataHandler, refreshColumnAndOverviewData, }: RowsBySectionOptions<T>): RowsBySectionResult<T>; |
"use strict"; | ||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); | ||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); | ||
@@ -16,4 +18,8 @@ | ||
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); | ||
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); | ||
var _immer = _interopRequireWildcard(require("immer")); | ||
var _lodash = require("lodash"); | ||
@@ -25,2 +31,8 @@ | ||
var _baseGetEffectiveSectionRowCount = _interopRequireDefault(require("./baseGetEffectiveSectionRowCount")); | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } | ||
@@ -32,12 +44,13 @@ | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
function useRowsBySection(_ref) { | ||
var sections = _ref.sections, | ||
var mutations = _ref.mutations, | ||
sections = _ref.sections, | ||
dataHandler = _ref.dataHandler, | ||
refreshColumnAndOverviewData = _ref.refreshColumnAndOverviewData; | ||
var loadRows = dataHandler.loadRows, | ||
unloadRows = dataHandler.unloadRows; // Changes to this don't need to trigger re-renders, so we just mutate the object in-place. | ||
unloadRows = dataHandler.unloadRows; // StartedRowsRequests is the source of truth for async data. | ||
// Changes to it don't trigger re-renders. When we have new | ||
// async data, we manually call recalculateRemoteRowsBySection, | ||
// which calculates the lastest remoteRowsBySection based off | ||
// of startedRowsRequests. | ||
@@ -48,26 +61,10 @@ var startedRowsRequests = (0, _react.useRef)({}); | ||
_useState2 = (0, _slicedToArray2["default"])(_useState, 2), | ||
rowsBySection = _useState2[0], | ||
_setRowsBySection = _useState2[1]; // Relative is a delta on top of the current estimated height | ||
remoteRowsBySection = _useState2[0], | ||
setRemoteRowsBySection = _useState2[1]; // Used for de-duplicating remote row data | ||
var _useState3 = (0, _react.useState)({}), | ||
_useState4 = (0, _slicedToArray2["default"])(_useState3, 2), | ||
relativeSectionLengthDeltas = _useState4[0], | ||
setRelativeSectionLengthDeltas = _useState4[1]; | ||
var incrementSectionLengthDelta = (0, _react.useCallback)(function (sectionKey, amount) { | ||
setRelativeSectionLengthDeltas(function (deltas) { | ||
return _objectSpread(_objectSpread({}, deltas), {}, (0, _defineProperty2["default"])({}, sectionKey, (deltas[sectionKey] || 0) + amount)); | ||
}); | ||
}, []); | ||
var loadedRowKeysBySection = (0, _react.useRef)({}); // We want: | ||
// 1) Row chunk request resolution and local edits to cause re-renders and update rowsBySection for rendering | ||
// 2) Row chunk request creation and local edits to synchronously update startedRowsRequests for requesting | ||
// To consolidate the logic here, we make the mutable startedRowsRequests the source of truth, and | ||
// tell the sheet to re-render when situations affecting goal 1 occur. | ||
var recalculateRowsBySection = (0, _react.useCallback)(function () { | ||
var loadedRemoteRowKeysBySection = (0, _react.useRef)({}); | ||
var recalculateRemoteRowsBySection = (0, _react.useCallback)(function () { | ||
var newRowsBySection = {}; | ||
var newLoadedRowKeysBySection = {}; | ||
var dataByRowKey = {}; | ||
loadedRemoteRowKeysBySection.current = {}; | ||
@@ -94,4 +91,4 @@ var _loop = function _loop() { | ||
if (!(sectionKey in newLoadedRowKeysBySection)) { | ||
newLoadedRowKeysBySection[sectionKey] = new Set(); | ||
if (!(sectionKey in loadedRemoteRowKeysBySection.current)) { | ||
loadedRemoteRowKeysBySection.current[sectionKey] = new Set(); | ||
} | ||
@@ -104,8 +101,7 @@ | ||
}, | ||
expectMoreRowsAfter: _request.type === 'RESOLVED' && Boolean(_request.nextCursor) | ||
expectMoreRowsAfter: _request.type === 'RESOLVED' && !!_request.nextCursor | ||
}); | ||
_request.rows.forEach(function (row) { | ||
newLoadedRowKeysBySection[sectionKey].add(row.key); | ||
dataByRowKey[row.key] = row.data; | ||
return loadedRemoteRowKeysBySection.current[sectionKey].add(row.key); | ||
}); | ||
@@ -122,261 +118,469 @@ } | ||
_loop(); | ||
} // If this is slow then we can store sets on the request | ||
} | ||
setRemoteRowsBySection(newRowsBySection); | ||
}, []); // We combine RemoteRowsBySection with LocalEdits to produce | ||
// the rowsBySection object which will be used outside of | ||
// useRowsBySection for rendering. | ||
var _iterator2 = _createForOfIteratorHelper(sections), | ||
_step2; | ||
var _useMemo = (0, _react.useMemo)(function () { | ||
// Going to remove uncessary mutations and sequence | ||
// dependent actions in such a way that this can be done | ||
// in O(M + N) where M in the number of mutations, and N | ||
// is the number of async-loaded rows | ||
var droppedIndexesSet = new Set(); // Check local edits for double adds/deletes | ||
try { | ||
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { | ||
var _section = _step2.value; | ||
var newSet = newLoadedRowKeysBySection[_section.key] || new Set(); | ||
var oldSet = loadedRowKeysBySection.current[_section.key] || new Set(); | ||
var addedRowKeys = []; | ||
var droppedRowKeys = []; | ||
var mutationIndexesBySectionByRow = {}; | ||
var _iterator3 = _createForOfIteratorHelper(newSet), | ||
_step3; | ||
for (var i = 0; i < mutations.length; i++) { | ||
var mutation = mutations[i]; | ||
try { | ||
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { | ||
var newKey = _step3.value; | ||
if (!Object.prototype.hasOwnProperty.call(mutationIndexesBySectionByRow, mutation.sectionKey)) { | ||
mutationIndexesBySectionByRow[mutation.sectionKey] = {}; | ||
} | ||
if (!oldSet.has(newKey)) { | ||
addedRowKeys.push(newKey); | ||
var sectionMutations = mutationIndexesBySectionByRow[mutation.sectionKey]; | ||
if (!Object.prototype.hasOwnProperty.call(sectionMutations, mutation.rowKey)) { | ||
sectionMutations[mutation.rowKey] = i; | ||
continue; | ||
} | ||
var prevMutationIndex = sectionMutations[mutation.rowKey]; | ||
var prevMutation = mutations[prevMutationIndex]; | ||
if (prevMutation.type === mutation.type) { | ||
// Double delete or double add, ignore the first one | ||
droppedIndexesSet.add(prevMutationIndex); | ||
sectionMutations[mutation.rowKey] = i; | ||
} else { | ||
// Cancelled out deletes and adds | ||
// This could be undesireable because perhaps the user | ||
// has some intent to ADD a row after some afterRowKey | ||
// which we're going to lose here. | ||
delete sectionMutations[mutation.rowKey]; | ||
droppedIndexesSet.add(prevMutationIndex); | ||
droppedIndexesSet.add(i); | ||
} | ||
} | ||
var dependentMutationIndexesBySectionByRow = {}; | ||
for (var _i2 = 0; _i2 < mutations.length; _i2++) { | ||
if (droppedIndexesSet.has(_i2)) { | ||
continue; | ||
} | ||
var _mutation = mutations[_i2]; | ||
if (!Object.prototype.hasOwnProperty.call(dependentMutationIndexesBySectionByRow, _mutation.sectionKey)) { | ||
dependentMutationIndexesBySectionByRow[_mutation.sectionKey] = { | ||
dependsOnSectionStart: [], | ||
dependsOnRows: {} | ||
}; | ||
} | ||
var _sectionMutations = dependentMutationIndexesBySectionByRow[_mutation.sectionKey]; | ||
switch (_mutation.type) { | ||
case 'ADD': | ||
{ | ||
if (_mutation.afterRowKey) { | ||
if (!Object.prototype.hasOwnProperty.call(_sectionMutations, _mutation.afterRowKey)) { | ||
_sectionMutations.dependsOnRows[_mutation.afterRowKey] = []; | ||
} | ||
_sectionMutations.dependsOnRows[_mutation.afterRowKey].push(_i2); | ||
} else { | ||
_sectionMutations.dependsOnSectionStart.push(_i2); | ||
} | ||
break; | ||
} | ||
} catch (err) { | ||
_iterator3.e(err); | ||
} finally { | ||
_iterator3.f(); | ||
} | ||
var _iterator4 = _createForOfIteratorHelper(oldSet), | ||
_step4; | ||
case 'DELETE': | ||
{ | ||
if (!Object.prototype.hasOwnProperty.call(_sectionMutations, _mutation.rowKey)) { | ||
_sectionMutations.dependsOnRows[_mutation.rowKey] = []; | ||
} | ||
try { | ||
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { | ||
var oldKey = _step4.value; | ||
_sectionMutations.dependsOnRows[_mutation.rowKey].push(_i2); | ||
if (!newSet.has(oldKey)) { | ||
droppedRowKeys.push(oldKey); | ||
if (_sectionMutations.dependsOnRows[_mutation.rowKey].length > 1) { | ||
throw new Error('Should not happen: delete in a chain of mutations for a row'); | ||
} | ||
break; | ||
} | ||
} catch (err) { | ||
_iterator4.e(err); | ||
} finally { | ||
_iterator4.f(); | ||
} | ||
if (addedRowKeys.length > 0) { | ||
loadRows === null || loadRows === void 0 ? void 0 : loadRows(_section.key, addedRowKeys.map(function (rowKey) { | ||
return { | ||
key: rowKey, | ||
data: dataByRowKey[rowKey] | ||
}; | ||
})); | ||
default: | ||
(0, _assertNever["default"])(_mutation); | ||
} | ||
} | ||
var usedIndexesSet = new Set(); | ||
var rowsBySection = (0, _immer["default"])(remoteRowsBySection, function (draft) { | ||
// First pass just to remove rows that will be duplicated otherwise | ||
for (var _i3 = 0, _Object$entries2 = Object.entries(draft); _i3 < _Object$entries2.length; _i3++) { | ||
var _Object$entries2$_i = (0, _slicedToArray2["default"])(_Object$entries2[_i3], 2), | ||
_sectionKey = _Object$entries2$_i[0], | ||
rowChunks = _Object$entries2$_i[1]; | ||
if (!rowChunks) { | ||
continue; | ||
} | ||
if (droppedRowKeys.length > 0) { | ||
unloadRows === null || unloadRows === void 0 ? void 0 : unloadRows(_section.key, droppedRowKeys); | ||
if (!Object.prototype.hasOwnProperty.call(mutationIndexesBySectionByRow, _sectionKey)) { | ||
continue; | ||
} | ||
} | ||
} catch (err) { | ||
_iterator2.e(err); | ||
} finally { | ||
_iterator2.f(); | ||
} | ||
loadedRowKeysBySection.current = newLoadedRowKeysBySection; | ||
var _sectionMutations2 = mutationIndexesBySectionByRow[_sectionKey]; | ||
var dedupedCount = 0; | ||
var _i4 = 0; | ||
_setRowsBySection(newRowsBySection); | ||
}, [loadRows, sections, unloadRows]); // TODO: loadRows / unloadRows | ||
// unmount cleanup | ||
while (_i4 < rowChunks.length) { | ||
var rowChunk = rowChunks[_i4]; | ||
rowChunk.startIndex -= dedupedCount; | ||
var j = 0; | ||
(0, _react.useEffect)(function () { | ||
return function () { | ||
for (var _i2 = 0, _Object$values = Object.values(startedRowsRequests.current); _i2 < _Object$values.length; _i2++) { | ||
var requests = _Object$values[_i2]; | ||
while (j < rowChunk.rowsResult.rows.length) { | ||
var key = rowChunk.rowsResult.rows[j].key; | ||
var _iterator5 = _createForOfIteratorHelper(requests), | ||
_step5; | ||
if (!Object.prototype.hasOwnProperty.call(_sectionMutations2, key)) { | ||
j++; | ||
continue; | ||
} | ||
try { | ||
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { | ||
var _request2 = _step5.value; | ||
var _mutation2 = mutations[_sectionMutations2[key]]; | ||
if (_request2.type === 'UNRESOLVED') { | ||
var _request2$abortContro; | ||
if (_mutation2.type !== 'ADD') { | ||
j++; | ||
continue; | ||
} | ||
(_request2$abortContro = _request2.abortController) === null || _request2$abortContro === void 0 ? void 0 : _request2$abortContro.abort(); | ||
} | ||
rowChunk.rowsResult.rows.splice(j, 1); | ||
dedupedCount++; | ||
} | ||
} catch (err) { | ||
_iterator5.e(err); | ||
} finally { | ||
_iterator5.f(); | ||
if (rowChunk.rowsResult.rows.length === 0) { | ||
rowChunks.splice(_i4, 1); | ||
} else { | ||
_i4++; | ||
} | ||
} | ||
} | ||
}; | ||
}, [startedRowsRequests]); | ||
var getEffectiveSectionRowCount = (0, _react.useCallback)(function (section) { | ||
var key = section.key, | ||
rowCountHint = section.rowCountHint, | ||
isHidden = section.isHidden; | ||
var sectionRows = rowsBySection[key]; | ||
if (isHidden) { | ||
return 0; | ||
} | ||
if (rowChunks.length === 0) { | ||
delete draft[_sectionKey]; | ||
} | ||
} // Second pass to apply mutations | ||
var sectionCountOverride = relativeSectionLengthDeltas[key]; | ||
var sectionDerivedCount = Math.max(0, rowCountHint + (sectionCountOverride || 0)); | ||
if (!sectionRows) { | ||
return sectionDerivedCount; | ||
} | ||
var _iterator2 = _createForOfIteratorHelper(sections), | ||
_step2; | ||
var lastChunk = sectionRows[sectionRows.length - 1]; | ||
var rowCount = lastChunk.rowsResult.rows.length; | ||
var rowDerivedCount = lastChunk.startIndex + rowCount + (lastChunk.expectMoreRowsAfter ? 1 : 0); | ||
return Math.max(rowDerivedCount, sectionDerivedCount); | ||
}, [relativeSectionLengthDeltas, rowsBySection]); | ||
var getRequestIndexesForRowKey = (0, _react.useCallback)(function (sectionKey, rowKey) { | ||
var _loadedRowKeysBySecti; | ||
try { | ||
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { | ||
var _sectionKey2 = _step2.value.key; | ||
if (!((_loadedRowKeysBySecti = loadedRowKeysBySection.current[sectionKey]) === null || _loadedRowKeysBySecti === void 0 ? void 0 : _loadedRowKeysBySecti.has(rowKey))) { | ||
return undefined; | ||
} | ||
if (!Object.prototype.hasOwnProperty.call(dependentMutationIndexesBySectionByRow, _sectionKey2)) { | ||
continue; | ||
} | ||
var sectionRequests = startedRowsRequests.current[sectionKey] || []; | ||
var _sectionMutations3 = dependentMutationIndexesBySectionByRow[_sectionKey2]; | ||
for (var i = 0; i < sectionRequests.length; i++) { | ||
var _request3 = sectionRequests[i]; | ||
if (!draft[_sectionKey2]) { | ||
draft[_sectionKey2] = []; | ||
} | ||
if (_request3.type === 'UNRESOLVED') { | ||
continue; | ||
} | ||
if (_sectionMutations3.dependsOnSectionStart.length > 0) { | ||
(function () { | ||
var newLeadingRowChunk = { | ||
startIndex: 0, | ||
rowsResult: { | ||
rows: _sectionMutations3.dependsOnSectionStart.map(function (mutationIndex) { | ||
usedIndexesSet.add(mutationIndex); | ||
var mutation = mutations[mutationIndex]; | ||
var foundRowIndex = (0, _lodash.findIndex)(_request3.rows, function (row) { | ||
return row.key === rowKey; | ||
}); | ||
if (mutation.type === 'DELETE') { | ||
throw new Error('delete cannot be in dependsOnSectionStart'); | ||
} | ||
if (foundRowIndex >= 0) { | ||
return [i, foundRowIndex]; | ||
} | ||
} | ||
return { | ||
key: mutation.rowKey, | ||
data: mutation.rowData | ||
}; | ||
}) | ||
}, | ||
expectMoreRowsAfter: true | ||
}; | ||
return undefined; | ||
}, []); | ||
var handleNewLocalRowMutation = (0, _react.useCallback)(function (mutation) { | ||
var indexes = getRequestIndexesForRowKey(mutation.sectionKey, mutation.rowKey); | ||
var rowExists = !!indexes; | ||
draft[_sectionKey2].forEach(function (chunk) { | ||
chunk.startIndex = chunk.startIndex + newLeadingRowChunk.rowsResult.rows.length; | ||
}); | ||
if (mutation.type === 'ADD' && rowExists || mutation.type === 'DELETE' && !rowExists) { | ||
return false; | ||
} | ||
draft[_sectionKey2].splice(0, 0, (0, _immer.castDraft)(newLeadingRowChunk)); | ||
})(); | ||
} | ||
switch (mutation.type) { | ||
case 'ADD': | ||
{ | ||
var sectionRequests = startedRowsRequests.current[mutation.sectionKey] || []; | ||
var addAtRequestIndex; | ||
var addAtRowIndex; | ||
if (Object.keys(_sectionMutations3.dependsOnRows).length === 0) { | ||
continue; | ||
} | ||
if (mutation.afterRowKey) { | ||
var _indexes = getRequestIndexesForRowKey(mutation.sectionKey, mutation.afterRowKey); | ||
var accumulatedShift = 0; | ||
var _i5 = 0; | ||
if (!_indexes) { | ||
return false; | ||
while (_i5 < draft[_sectionKey2].length) { | ||
var _rowChunk = draft[_sectionKey2][_i5]; | ||
_rowChunk.startIndex += accumulatedShift; | ||
var _j = 0; | ||
while (_j < _rowChunk.rowsResult.rows.length) { | ||
var _key = _rowChunk.rowsResult.rows[_j].key; | ||
var mutationIndexesOnRow = _sectionMutations3.dependsOnRows[_key]; | ||
if (!mutationIndexesOnRow) { | ||
_j++; | ||
continue; | ||
} | ||
var _iterator3 = _createForOfIteratorHelper(mutationIndexesOnRow), | ||
_step3; | ||
try { | ||
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { | ||
var mutationIndex = _step3.value; | ||
var _mutation3 = mutations[mutationIndex]; | ||
switch (_mutation3.type) { | ||
case 'ADD': | ||
{ | ||
_rowChunk.rowsResult.rows.splice(_j + 1, 0, { | ||
key: _mutation3.rowKey, | ||
data: (0, _immer.castDraft)(_mutation3.rowData) | ||
}); | ||
accumulatedShift++; | ||
_j++; | ||
break; | ||
} | ||
case 'DELETE': | ||
{ | ||
_rowChunk.rowsResult.rows.splice(_j, 1); | ||
accumulatedShift--; | ||
break; | ||
} | ||
default: | ||
(0, _assertNever["default"])(_mutation3); | ||
} | ||
usedIndexesSet.add(mutationIndex); | ||
} | ||
} catch (err) { | ||
_iterator3.e(err); | ||
} finally { | ||
_iterator3.f(); | ||
} | ||
} | ||
addAtRequestIndex = _indexes[0]; | ||
addAtRowIndex = _indexes[1] + 1; | ||
} else { | ||
// if the section is empty, make a local request | ||
if (sectionRequests.length === 0) { | ||
startedRowsRequests.current[mutation.sectionKey] = [{ | ||
type: 'LOCAL', | ||
startIndex: 0, | ||
limit: 0, | ||
direction: 'forward', | ||
cursor: 'invalid', | ||
offset: 0, | ||
isSelected: false, | ||
rows: [] | ||
}]; | ||
sectionRequests = startedRowsRequests.current[mutation.sectionKey]; | ||
if (_rowChunk.rowsResult.rows.length === 0) { | ||
draft[_sectionKey2].splice(_i5, 1); | ||
} else { | ||
_i5++; | ||
} | ||
} | ||
addAtRequestIndex = sectionRequests.length - 1; | ||
var _request5 = sectionRequests[addAtRequestIndex]; | ||
addAtRowIndex = _request5.rows.length; | ||
if (draft[_sectionKey2].length === 0) { | ||
delete draft[_sectionKey2]; | ||
} | ||
} | ||
} catch (err) { | ||
_iterator2.e(err); | ||
} finally { | ||
_iterator2.f(); | ||
} | ||
}); // If the mutation was never used, that means that | ||
// rows it depends do not exist so the mutation | ||
// should be destroyed | ||
// IE a delete mutation for row A should | ||
// be dropped if we've unloaded row A | ||
var _request4 = sectionRequests[addAtRequestIndex]; | ||
var newRowChunk = { | ||
data: mutation.rowData, | ||
key: mutation.rowKey | ||
}; | ||
for (var _i6 = 0; _i6 < mutations.length; _i6++) { | ||
if (!usedIndexesSet.has(_i6)) { | ||
droppedIndexesSet.add(_i6); | ||
} | ||
} | ||
_request4.rows.splice(addAtRowIndex, 0, newRowChunk); | ||
return { | ||
rowsBySection: rowsBySection, | ||
droppedMutations: (0, _toConsumableArray2["default"])(droppedIndexesSet).map(function (mutationIndex) { | ||
return mutations[mutationIndex]; | ||
}) | ||
}; | ||
}, [remoteRowsBySection, mutations, sections]), | ||
rowsBySection = _useMemo.rowsBySection, | ||
droppedMutations = _useMemo.droppedMutations; | ||
_request4.limit++; // We don't call incrementSectionLengthDelta(mutation.sectionKey, 1); | ||
// because overviewdata should be locally udpdated | ||
{ | ||
var loadedRowKeysBySection = (0, _react.useRef)({}); | ||
(0, _react.useEffect)(function () { | ||
var newLoadedRowKeysBySection = {}; | ||
var rowsBySectionRowKey = {}; | ||
for (var i = addAtRequestIndex + 1; i < sectionRequests.length; i++) { | ||
var shiftedRequest = sectionRequests[i]; | ||
for (var _i7 = 0, _Object$entries3 = Object.entries(rowsBySection); _i7 < _Object$entries3.length; _i7++) { | ||
var _Object$entries3$_i = (0, _slicedToArray2["default"])(_Object$entries3[_i7], 2), | ||
_sectionKey3 = _Object$entries3$_i[0], | ||
rowChunks = _Object$entries3$_i[1]; | ||
if (shiftedRequest.type === 'UNRESOLVED') { | ||
// This request is stale | ||
shiftedRequest.abortController.abort(); | ||
} else { | ||
shiftedRequest.startIndex++; | ||
newLoadedRowKeysBySection[_sectionKey3] = new Set(); | ||
rowsBySectionRowKey[_sectionKey3] = {}; | ||
var _iterator4 = _createForOfIteratorHelper(rowChunks), | ||
_step4; | ||
try { | ||
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { | ||
var rowChunk = _step4.value; | ||
var _iterator5 = _createForOfIteratorHelper(rowChunk.rowsResult.rows), | ||
_step5; | ||
try { | ||
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { | ||
var row = _step5.value; | ||
newLoadedRowKeysBySection[_sectionKey3].add(row.key); | ||
rowsBySectionRowKey[_sectionKey3][row.key] = row; | ||
} | ||
} catch (err) { | ||
_iterator5.e(err); | ||
} finally { | ||
_iterator5.f(); | ||
} | ||
} | ||
break; | ||
} catch (err) { | ||
_iterator4.e(err); | ||
} finally { | ||
_iterator4.f(); | ||
} | ||
} | ||
case 'DELETE': | ||
{ | ||
var _ref2 = indexes, | ||
_ref3 = (0, _slicedToArray2["default"])(_ref2, 2), | ||
requestIndex = _ref3[0], | ||
rowIndex = _ref3[1]; | ||
var _iterator6 = _createForOfIteratorHelper(sections), | ||
_step6; | ||
var _sectionRequests = startedRowsRequests.current[mutation.sectionKey]; | ||
var _request6 = _sectionRequests[requestIndex]; | ||
try { | ||
var _loop2 = function _loop2() { | ||
var section = _step6.value; | ||
var newSet = newLoadedRowKeysBySection[section.key] || new Set(); | ||
var oldSet = loadedRowKeysBySection.current[section.key] || new Set(); | ||
var addedRowKeys = []; | ||
var droppedRowKeys = []; | ||
_request6.rows.splice(rowIndex, 1); | ||
var _iterator7 = _createForOfIteratorHelper(newSet), | ||
_step7; | ||
_request6.limit--; // We don't call incrementSectionLengthDelta(mutation.sectionKey, -11); | ||
// because overviewdata should be locally udpdated | ||
try { | ||
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { | ||
var newKey = _step7.value; | ||
for (var _i3 = requestIndex + 1; _i3 < _sectionRequests.length; _i3++) { | ||
var _shiftedRequest = _sectionRequests[_i3]; | ||
if (!oldSet.has(newKey)) { | ||
addedRowKeys.push(newKey); | ||
} | ||
} | ||
} catch (err) { | ||
_iterator7.e(err); | ||
} finally { | ||
_iterator7.f(); | ||
} | ||
if (_shiftedRequest.type === 'UNRESOLVED') { | ||
// This request is stale | ||
_shiftedRequest.abortController.abort(); | ||
} else { | ||
_shiftedRequest.startIndex--; | ||
var _iterator8 = _createForOfIteratorHelper(oldSet), | ||
_step8; | ||
try { | ||
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { | ||
var oldKey = _step8.value; | ||
if (!newSet.has(oldKey)) { | ||
droppedRowKeys.push(oldKey); | ||
} | ||
} | ||
} catch (err) { | ||
_iterator8.e(err); | ||
} finally { | ||
_iterator8.f(); | ||
} | ||
if (_request6.limit === 0) { | ||
_sectionRequests.splice(requestIndex, 1); | ||
if (addedRowKeys.length > 0) { | ||
loadRows === null || loadRows === void 0 ? void 0 : loadRows(section.key, addedRowKeys.map(function (rowKey) { | ||
return rowsBySectionRowKey[section.key][rowKey]; | ||
})); | ||
} | ||
break; | ||
if (droppedRowKeys.length > 0) { | ||
unloadRows === null || unloadRows === void 0 ? void 0 : unloadRows(section.key, droppedRowKeys); | ||
} | ||
loadedRowKeysBySection.current = newLoadedRowKeysBySection; | ||
}; | ||
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { | ||
_loop2(); | ||
} | ||
} catch (err) { | ||
_iterator6.e(err); | ||
} finally { | ||
_iterator6.f(); | ||
} | ||
}, [loadRows, rowsBySection, sections, unloadRows]); | ||
} | ||
{ | ||
var droppedMutationsJSON = JSON.stringify(droppedMutations); | ||
(0, _react.useEffect)(function () { | ||
droppedMutations.forEach(function (mutation) { | ||
var _mutation$destroy; | ||
default: | ||
(0, _assertNever["default"])(mutation); | ||
} | ||
(_mutation$destroy = mutation.destroy) === null || _mutation$destroy === void 0 ? void 0 : _mutation$destroy.call(mutation); | ||
}); // eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [droppedMutationsJSON]); | ||
} // unmount cleanup | ||
recalculateRowsBySection(); | ||
refreshColumnAndOverviewData(); | ||
return true; | ||
}, [getRequestIndexesForRowKey, recalculateRowsBySection, refreshColumnAndOverviewData]); | ||
(0, _react.useEffect)(function () { | ||
return function () { | ||
for (var _i8 = 0, _Object$values = Object.values(startedRowsRequests.current); _i8 < _Object$values.length; _i8++) { | ||
var requests = _Object$values[_i8]; | ||
var _iterator9 = _createForOfIteratorHelper(requests), | ||
_step9; | ||
try { | ||
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { | ||
var _request2 = _step9.value; | ||
if (_request2.type === 'UNRESOLVED') { | ||
var _request2$abortContro; | ||
(_request2$abortContro = _request2.abortController) === null || _request2$abortContro === void 0 ? void 0 : _request2$abortContro.abort(); | ||
} | ||
} | ||
} catch (err) { | ||
_iterator9.e(err); | ||
} finally { | ||
_iterator9.f(); | ||
} | ||
} | ||
}; | ||
}, [startedRowsRequests]); // This function only counts remote rows, NOT mutations | ||
// This should be used for request logic | ||
var getEffectiveSectionRemoteRowCount = (0, _react.useCallback)(function (section) { | ||
return (0, _baseGetEffectiveSectionRowCount["default"])(section, remoteRowsBySection); | ||
}, [remoteRowsBySection]); // This is the same as getEffectiveSectionRemoteRowCount, except it includes mutations | ||
// This should be used for rendering | ||
var getEffectiveSectionRowCount = (0, _react.useCallback)(function (section) { | ||
return (0, _baseGetEffectiveSectionRowCount["default"])(section, rowsBySection); | ||
}, [rowsBySection]); | ||
var releaseRowsRequests = (0, _react.useCallback)(function (sectionKey, requestIndexes) { | ||
@@ -409,8 +613,6 @@ var recalcNeeded = false; | ||
if (recalcNeeded) { | ||
recalculateRowsBySection(); | ||
recalculateRemoteRowsBySection(); | ||
} | ||
}, [recalculateRowsBySection]); | ||
}, [recalculateRemoteRowsBySection]); | ||
var rightShiftRequests = (0, _react.useCallback)(function (sectionKey, rightShiftAmount) { | ||
var startingRequestIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; | ||
if (rightShiftAmount <= 0) { | ||
@@ -420,24 +622,11 @@ return; | ||
var invalidIndexes = []; | ||
for (var i = startingRequestIndex; i < (startedRowsRequests.current[sectionKey] || []).length; i++) { | ||
var _request7 = startedRowsRequests.current[sectionKey][i]; | ||
if (_request7.type === 'UNRESOLVED') { | ||
invalidIndexes.push(i); | ||
} else { | ||
_request7.startIndex += rightShiftAmount; | ||
} | ||
for (var i = 0; i < (startedRowsRequests.current[sectionKey] || []).length; i++) { | ||
var _request3 = startedRowsRequests.current[sectionKey][i]; | ||
_request3.startIndex += rightShiftAmount; | ||
} | ||
if (invalidIndexes.length > 0) { | ||
releaseRowsRequests(sectionKey, invalidIndexes); | ||
} | ||
refreshColumnAndOverviewData(); | ||
}, [refreshColumnAndOverviewData, releaseRowsRequests]); | ||
}, []); | ||
var removeDuplicates = (0, _react.useCallback)(function (sectionKey, rowsResult) { | ||
return _objectSpread(_objectSpread({}, rowsResult), {}, { | ||
rows: rowsResult.rows.filter(function (row) { | ||
var loadedRowKeysSet = loadedRowKeysBySection.current[sectionKey] || new Set(); | ||
var loadedRowKeysSet = loadedRemoteRowKeysBySection.current[sectionKey] || new Set(); | ||
return !loadedRowKeysSet.has(row.key); | ||
@@ -447,3 +636,3 @@ }) | ||
}, []); | ||
var storeRowsForRequest = (0, _react.useCallback)(function (_rowsResult, sectionKey, unresolvedRequest) { | ||
var storeRowsForRequest = (0, _react.useCallback)(function (rowsResultWithDuplicates, sectionKey, unresolvedRequest) { | ||
if (unresolvedRequest.abortController.signal.aborted) { | ||
@@ -454,15 +643,15 @@ return; | ||
if (unresolvedRequest.limit < _rowsResult.rows.length) { | ||
if (unresolvedRequest.limit < rowsResultWithDuplicates.rows.length) { | ||
throw new Error('cannot return more rows than limit'); | ||
} | ||
if (unresolvedRequest.limit > _rowsResult.rows.length && (unresolvedRequest.direction === 'forward' && _rowsResult.nextPageCursor || unresolvedRequest.direction === 'backward' && _rowsResult.previousPageCursor)) { | ||
if (unresolvedRequest.limit > rowsResultWithDuplicates.rows.length && (unresolvedRequest.direction === 'forward' && rowsResultWithDuplicates.nextPageCursor || unresolvedRequest.direction === 'backward' && rowsResultWithDuplicates.previousPageCursor)) { | ||
throw new Error('cannot return cursors without exhausting limit of requested rows'); | ||
} | ||
if (unresolvedRequest.cursor === dataHandler.firstPageCursor && _rowsResult.previousPageCursor && unresolvedRequest.offset === 0) { | ||
if (unresolvedRequest.cursor === dataHandler.firstPageCursor && rowsResultWithDuplicates.previousPageCursor && unresolvedRequest.offset === 0) { | ||
throw new Error('first page cursor cannot return results with previousPageCursor defined'); | ||
} | ||
if (unresolvedRequest.cursor === dataHandler.lastPageCursor && _rowsResult.nextPageCursor && unresolvedRequest.offset === 0) { | ||
if (unresolvedRequest.cursor === dataHandler.lastPageCursor && rowsResultWithDuplicates.nextPageCursor && unresolvedRequest.offset === 0) { | ||
throw new Error('last page cursor cannot return results with lastPageCursor defined'); | ||
@@ -486,52 +675,45 @@ } | ||
var rowsResult = removeDuplicates(sectionKey, _rowsResult); // The number of originally-requested rows subtracting any rows removed for duplicates | ||
var rowsResult = removeDuplicates(sectionKey, rowsResultWithDuplicates); // Step 3. Handle length of results so it fits with other knowledge about the section | ||
// Case 1: we want to right shift the startIndex so that the responded rows are flush with adjacent requests | ||
var expectedNumberOfRows = unresolvedRequest.limit - (_rowsResult.rows.length - rowsResult.rows.length); // Step 3. Handle length of results so it fits with other knowledge about the section | ||
// The indexes of requests can shift if: | ||
// 1. We request beyond the bounds of the section and find results | ||
// 2. We find less results in a chunk than we expected when the request resolved | ||
// 3. We find more results in the section than we expected | ||
// In these cases we need to shift already-loaded data, and cancel outbound requests that are now invalid | ||
// Case 1: Need to shift everything right if we requested into the negative and got results that | ||
if (unresolvedRequest.direction === 'backward' && unresolvedRequest.limit > rowsResult.rows.length) { | ||
unresolvedRequest.startIndex += unresolvedRequest.limit - rowsResult.rows.length; | ||
} // Case 2: Need to shift everything right if we requested into the negative and got results that | ||
// would have negative indexes | ||
var indexOfFirstRow = unresolvedRequest.startIndex + expectedNumberOfRows - rowsResult.rows.length; | ||
if (unresolvedRequest.startIndex < 0 && indexOfFirstRow < 0) { | ||
var rightShiftAmount = Math.abs(indexOfFirstRow); | ||
rightShiftRequests(sectionKey, rightShiftAmount, 1); | ||
} // Case 2: We need to shift results (or throw away) when a request brings information | ||
// that the section is emptier than we thought | ||
if (unresolvedRequest.startIndex < 0) { | ||
rightShiftRequests(sectionKey, -unresolvedRequest.startIndex); | ||
} // Case 3: | ||
// If we're missing a cursor in either direction, we need to throw away | ||
// (and possibly shift) data in either direction. | ||
var overEstimatedChunk = expectedNumberOfRows > rowsResult.rows.length; | ||
if (overEstimatedChunk) { | ||
{ | ||
var invalidIndexes = []; | ||
if (unresolvedRequest.direction === 'forward') { | ||
if (!rowsResult.nextPageCursor) { | ||
for (var i = 0; i < (startedRowsRequests.current[sectionKey] || []).length; i++) { | ||
var _request8 = startedRowsRequests.current[sectionKey][i]; | ||
var _request4 = startedRowsRequests.current[sectionKey][i]; | ||
if (_request8.startIndex > unresolvedRequest.startIndex) { | ||
if (_request4.startIndex > unresolvedRequest.startIndex) { | ||
invalidIndexes.push(i); | ||
} | ||
} | ||
} | ||
var missedAmount = getEffectiveSectionRowCount(section) - rowsResult.rows.length - unresolvedRequest.startIndex; | ||
incrementSectionLengthDelta(sectionKey, -missedAmount); | ||
} else { | ||
var leftShiftAmount = indexOfFirstRow; // In the backwards regime we have to release invalidated requests and left shift | ||
if (!rowsResult.previousPageCursor) { | ||
// If there's no previousPageCursor we also need to left shift, in | ||
// addition to releasing requests | ||
var startIndexOfUnresolvedRequest = unresolvedRequest.startIndex; | ||
for (var _i4 = 0; _i4 < (startedRowsRequests.current[sectionKey] || []).length; _i4++) { | ||
var _request9 = startedRowsRequests.current[sectionKey][_i4]; | ||
for (var _i9 = 0; _i9 < (startedRowsRequests.current[sectionKey] || []).length; _i9++) { | ||
var _request5 = startedRowsRequests.current[sectionKey][_i9]; | ||
if (_request9.startIndex < unresolvedRequest.startIndex) { | ||
invalidIndexes.push(_i4); | ||
if (_request5.startIndex < startIndexOfUnresolvedRequest) { | ||
invalidIndexes.push(_i9); | ||
} else { | ||
_request9.startIndex = Math.max(_request9.startIndex - leftShiftAmount, 0); | ||
_request5.startIndex = _request5.startIndex - startIndexOfUnresolvedRequest; | ||
} | ||
} | ||
incrementSectionLengthDelta(sectionKey, -leftShiftAmount); | ||
} | ||
@@ -541,7 +723,10 @@ | ||
releaseRowsRequests(sectionKey, invalidIndexes); | ||
refreshColumnAndOverviewData(); | ||
} | ||
refreshColumnAndOverviewData(); | ||
} // Case 3: We need to shift all results to the right by one if | ||
} // Case 4: We need to shift all results to the right by one if | ||
// a cursor adjacent to the front of the section has an unexpected prevPage | ||
// we also need to refresh columnAndOverviewData. | ||
// We also refresh columnAndOverviewData when checking the similar case on | ||
// end of the section. | ||
// | ||
// More information: | ||
@@ -551,15 +736,15 @@ // This is to indicate to the user that data needs to be requested at the | ||
// kick off a request to get the outstanding data | ||
var underEstimatedSection = Boolean(rowsResult.nextPageCursor) && getEffectiveSectionRowCount(section) <= unresolvedRequest.startIndex + expectedNumberOfRows || Boolean(rowsResult.previousPageCursor) && unresolvedRequest.startIndex <= 0; | ||
if (underEstimatedSection) { | ||
refreshColumnAndOverviewData(); | ||
} // We only handle the single row addition here for the front of the section | ||
// We only handle the single row addition here for the front of the section | ||
// the case where we can find extra data at the end of the section | ||
// is handled in getEffectiveSectionRowCount | ||
if (rowsResult.previousPageCursor && unresolvedRequest.startIndex === 0) { | ||
rightShiftRequests(sectionKey, 1); | ||
refreshColumnAndOverviewData(); | ||
} else if (rowsResult.nextPageCursor && section.rowCountHint < unresolvedRequest.startIndex + rowsResult.rows.length) { | ||
refreshColumnAndOverviewData(); | ||
} | ||
if (underEstimatedSection && unresolvedRequest.direction === 'backward') { | ||
rightShiftRequests(sectionKey, 1); | ||
if (unresolvedRequest.startIndex < 0) { | ||
throw new Error('this should never happen: startIndex on resolved request is negative'); | ||
} // Step 4: Store data | ||
@@ -570,3 +755,3 @@ | ||
type: 'RESOLVED', | ||
startIndex: Math.max(unresolvedRequest.startIndex, 0), | ||
startIndex: unresolvedRequest.startIndex, | ||
cursor: unresolvedRequest.cursor, | ||
@@ -582,9 +767,9 @@ direction: unresolvedRequest.direction, | ||
var resolvedRequestIndex = startedRowsRequests.current[sectionKey].findIndex(function (request) { | ||
return request.startIndex === unresolvedRequest.startIndex && request.type === 'UNRESOLVED'; | ||
return request === unresolvedRequest; | ||
}); | ||
startedRowsRequests.current[sectionKey][resolvedRequestIndex] = resolvedRequest; | ||
recalculateRowsBySection(); | ||
}, [dataHandler.firstPageCursor, dataHandler.lastPageCursor, getEffectiveSectionRowCount, incrementSectionLengthDelta, recalculateRowsBySection, refreshColumnAndOverviewData, releaseRowsRequests, removeDuplicates, rightShiftRequests, sections]); | ||
recalculateRemoteRowsBySection(); | ||
}, [dataHandler.firstPageCursor, dataHandler.lastPageCursor, recalculateRemoteRowsBySection, refreshColumnAndOverviewData, releaseRowsRequests, removeDuplicates, rightShiftRequests, sections]); | ||
var createRowsRequest = (0, _react.useCallback)( /*#__PURE__*/function () { | ||
var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(sectionKey, request) { | ||
var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(sectionKey, request) { | ||
var storeResult, | ||
@@ -642,51 +827,14 @@ sectionResults, | ||
return function (_x, _x2) { | ||
return _ref4.apply(this, arguments); | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}(), [dataHandler, storeRowsForRequest]); | ||
var reset = (0, _react.useCallback)(function () { | ||
for (var _i5 = 0, _Object$keys = Object.keys(startedRowsRequests.current); _i5 < _Object$keys.length; _i5++) { | ||
var _sectionKey = _Object$keys[_i5]; | ||
releaseRowsRequests(_sectionKey); | ||
for (var _i10 = 0, _Object$keys = Object.keys(startedRowsRequests.current); _i10 < _Object$keys.length; _i10++) { | ||
var _sectionKey4 = _Object$keys[_i10]; | ||
releaseRowsRequests(_sectionKey4); | ||
} | ||
startedRowsRequests.current = {}; | ||
setRelativeSectionLengthDeltas({}); | ||
recalculateRowsBySection(); | ||
}, [recalculateRowsBySection, releaseRowsRequests]); // TODO should these APIs take sectionKey too? | ||
var setRowData = (0, _react.useCallback)(function (rowKey, rowData) { | ||
for (var _i6 = 0, _Object$keys2 = Object.keys(startedRowsRequests.current); _i6 < _Object$keys2.length; _i6++) { | ||
var _sectionKey2 = _Object$keys2[_i6]; | ||
var indexes = getRequestIndexesForRowKey(_sectionKey2, rowKey); | ||
if (!indexes) { | ||
continue; | ||
} | ||
var _indexes2 = (0, _slicedToArray2["default"])(indexes, 2), | ||
requestIndex = _indexes2[0], | ||
rowIndex = _indexes2[1]; | ||
var _request10 = startedRowsRequests.current[_sectionKey2][requestIndex]; | ||
_request10.rows[rowIndex].data = rowData; | ||
} | ||
recalculateRowsBySection(); | ||
}, [getRequestIndexesForRowKey, recalculateRowsBySection]); | ||
var addRowData = (0, _react.useCallback)(function (sectionKey, rowKey, rowData, afterRowKey) { | ||
return handleNewLocalRowMutation({ | ||
type: 'ADD', | ||
sectionKey: sectionKey, | ||
rowData: rowData, | ||
rowKey: rowKey, | ||
afterRowKey: afterRowKey | ||
}); | ||
}, [handleNewLocalRowMutation]); | ||
var deleteRowData = (0, _react.useCallback)(function (sectionKey, rowKey) { | ||
return handleNewLocalRowMutation({ | ||
type: 'DELETE', | ||
sectionKey: sectionKey, | ||
rowKey: rowKey | ||
}); | ||
}, [handleNewLocalRowMutation]); | ||
recalculateRemoteRowsBySection(); | ||
}, [recalculateRemoteRowsBySection, releaseRowsRequests]); | ||
var getRowData = (0, _react.useCallback)(function (sectionKey, rowKey) { | ||
@@ -696,8 +844,8 @@ var sectionRowData = rowsBySection[sectionKey]; | ||
if (sectionRowData) { | ||
var _iterator6 = _createForOfIteratorHelper(sectionRowData), | ||
_step6; | ||
var _iterator10 = _createForOfIteratorHelper(sectionRowData), | ||
_step10; | ||
try { | ||
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { | ||
var rowChunk = _step6.value; | ||
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) { | ||
var rowChunk = _step10.value; | ||
var row = rowChunk.rowsResult.rows.find(function (row) { | ||
@@ -712,5 +860,5 @@ return row.key === rowKey; | ||
} catch (err) { | ||
_iterator6.e(err); | ||
_iterator10.e(err); | ||
} finally { | ||
_iterator6.f(); | ||
_iterator10.f(); | ||
} | ||
@@ -736,2 +884,3 @@ } | ||
return { | ||
getEffectiveSectionRemoteRowCount: getEffectiveSectionRemoteRowCount, | ||
getEffectiveSectionRowCount: getEffectiveSectionRowCount, | ||
@@ -743,5 +892,2 @@ reset: reset, | ||
rowsBySection: rowsBySection, | ||
addRowData: addRowData, | ||
deleteRowData: deleteRowData, | ||
setRowData: setRowData, | ||
getRowData: getRowData | ||
@@ -748,0 +894,0 @@ }; |
@@ -74,2 +74,17 @@ /// <reference types="react" /> | ||
}>) => boolean; | ||
export declare type LocalRowMutation<T> = LocalRowMutationAdd<T> | LocalRowMutationDelete; | ||
interface LocalRowMutationAdd<T> { | ||
type: 'ADD'; | ||
sectionKey: string; | ||
rowKey: string; | ||
rowData: T; | ||
afterRowKey?: string; | ||
destroy?: () => void; | ||
} | ||
interface LocalRowMutationDelete { | ||
type: 'DELETE'; | ||
sectionKey: string; | ||
rowKey: string; | ||
destroy?: () => void; | ||
} | ||
export interface SheetDataOptions<T> { | ||
@@ -79,2 +94,3 @@ columnAndOverviewData: ColumnAndOverviewData; | ||
dataHandler: DataHandler<T>; | ||
mutations: Array<LocalRowMutation<T>>; | ||
doesCellHaveData?: (rowKey: string, sectionKey: string, columnKey: string, data: T) => boolean; | ||
@@ -93,6 +109,4 @@ onWrite: WriteHandler<T>; | ||
export interface SheetData<T> { | ||
addRowData(sectionKey: string, rowKey: string, rowData: T, afterRowKey?: string): boolean; | ||
columnAndOverviewData: ColumnAndOverviewData; | ||
doesCellHaveData?: (rowKey: string, sectionKey: string, columnKey: string, data: T) => boolean; | ||
deleteRowData(sectionKey: string, rowKey: string): boolean; | ||
onWrite: WriteHandler<T>; | ||
@@ -108,3 +122,2 @@ copyHandler: CopyHandler<T>; | ||
sectionRowMatcher: SectionRelativeRowMatcher; | ||
setRowData(rowKey: string, rowData: T): void; | ||
getRowData(sectionKey: string, rowKey: string): T | undefined; | ||
@@ -122,1 +135,2 @@ totalRowCount: number; | ||
export default function useSheetData<T>(options: SheetDataOptions<T>): SheetData<T>; | ||
export {}; |
@@ -43,2 +43,3 @@ "use strict"; | ||
doesCellHaveData = options.doesCellHaveData, | ||
mutations = options.mutations, | ||
onExpandColumns = options.onExpandColumns, | ||
@@ -53,17 +54,17 @@ onReorderColumn = options.onReorderColumn, | ||
dataHandler: options.dataHandler, | ||
refreshColumnAndOverviewData: refreshColumnAndOverviewData | ||
refreshColumnAndOverviewData: refreshColumnAndOverviewData, | ||
mutations: mutations | ||
}), | ||
rowsBySection = _useRowsBySection.rowsBySection, | ||
rowsBySectionAddRowData = _useRowsBySection.addRowData, | ||
getRowData = _useRowsBySection.getRowData, | ||
rowsBySectionSetRowData = _useRowsBySection.setRowData, | ||
startedRowsRequests = _useRowsBySection.startedRowsRequests, | ||
createRowsRequest = _useRowsBySection.createRowsRequest, | ||
releaseRowsRequests = _useRowsBySection.releaseRowsRequests, | ||
rowsBySectionDeleteRowData = _useRowsBySection.deleteRowData, | ||
resetRowsBySection = _useRowsBySection.reset, | ||
getEffectiveSectionRowCount = _useRowsBySection.getEffectiveSectionRowCount; | ||
getEffectiveSectionRowCount = _useRowsBySection.getEffectiveSectionRowCount, | ||
getEffectiveSectionRemoteRowCount = _useRowsBySection.getEffectiveSectionRemoteRowCount; | ||
verify(options); | ||
var sectionRowMatcher = (0, _useSectionRelativeRowMatcher["default"])(columnAndOverviewData.sections, getEffectiveSectionRowCount); | ||
var sectionRemoteRowMatcher = (0, _useSectionRelativeRowMatcher["default"])(columnAndOverviewData.sections, getEffectiveSectionRemoteRowCount); | ||
@@ -89,2 +90,10 @@ var _useState = (0, _react.useState)(), | ||
}, [columnAndOverviewData.sections]); | ||
var totalRemoteRowCount = (0, _sumBy["default"])(columnAndOverviewData.sections, function (s) { | ||
return ( | ||
/* sticky row */ | ||
1 + getEffectiveSectionRemoteRowCount(s) | ||
); | ||
}) + 1; | ||
/* column headers row */ | ||
var totalRowCount = (0, _sumBy["default"])(columnAndOverviewData.sections, function (s) { | ||
@@ -117,4 +126,4 @@ return ( | ||
return { | ||
start: adjustNegativeSectionOrRow(sectionRowMatcher.getSectionRow(Math.min(totalRowCount - 1, Math.max(0, visibleRowStartIndex - bufferAmount)))), | ||
stop: adjustNegativeSectionOrRow(sectionRowMatcher.getSectionRow(Math.min(totalRowCount - 1, Math.max(0, visibleRowStopIndex + bufferAmount)))) | ||
start: adjustNegativeSectionOrRow(sectionRemoteRowMatcher.getSectionRow(Math.min(totalRemoteRowCount - 1, Math.max(0, visibleRowStartIndex - bufferAmount)))), | ||
stop: adjustNegativeSectionOrRow(sectionRemoteRowMatcher.getSectionRow(Math.min(totalRemoteRowCount - 1, Math.max(0, visibleRowStopIndex + bufferAmount)))) | ||
}; | ||
@@ -154,8 +163,8 @@ } // TODO if we want to support multiple data handlers, loop over all handlers here | ||
var requestPromises = []; | ||
var requestTriggered = (0, _findMissingRowsInRange["default"])(startedRowsRequests, columnAndOverviewData.sections, requestTriggerRange, getEffectiveSectionRowCount, null); | ||
var requestTriggered = (0, _findMissingRowsInRange["default"])(startedRowsRequests, columnAndOverviewData.sections, requestTriggerRange, getEffectiveSectionRemoteRowCount, null); | ||
if (requestTriggered) { | ||
(0, _findMissingRowsInRange["default"])(startedRowsRequests, columnAndOverviewData.sections, requestLimitRange, getEffectiveSectionRowCount, function (missingRows) { | ||
(0, _findMissingRowsInRange["default"])(startedRowsRequests, columnAndOverviewData.sections, requestLimitRange, getEffectiveSectionRemoteRowCount, function (missingRows) { | ||
var section = columnAndOverviewData.sections[missingRows.sectionIndex]; | ||
var request = (0, _getRequestForMissingRows["default"])(missingRows, dataHandler, startedRowsRequests[section.key] || [], getEffectiveSectionRowCount(section)); | ||
var request = (0, _getRequestForMissingRows["default"])(missingRows, dataHandler, startedRowsRequests[section.key] || [], getEffectiveSectionRemoteRowCount(section)); | ||
var promise = createRowsRequest(section.key, request); | ||
@@ -184,4 +193,4 @@ requestPromises.push(promise); | ||
range = { | ||
start: adjustNegativeSectionOrRow(sectionRowMatcher.getSectionRow(start)), | ||
stop: adjustNegativeSectionOrRow(sectionRowMatcher.getSectionRow(end)) | ||
start: adjustNegativeSectionOrRow(sectionRemoteRowMatcher.getSectionRow(start)), | ||
stop: adjustNegativeSectionOrRow(sectionRemoteRowMatcher.getSectionRow(end)) | ||
}; | ||
@@ -194,3 +203,3 @@ missingRows = []; // TODO: We should be passing in `startedRowsRequests` | ||
(0, _findMissingRowsInRange["default"])({}, columnAndOverviewData.sections, range, getEffectiveSectionRowCount, function (_missingRows) { | ||
(0, _findMissingRowsInRange["default"])({}, columnAndOverviewData.sections, range, getEffectiveSectionRemoteRowCount, function (_missingRows) { | ||
return missingRows.push(_missingRows); | ||
@@ -201,3 +210,3 @@ }); | ||
var section = columnAndOverviewData.sections[missingRow.sectionIndex]; | ||
var request = (0, _getRequestForMissingRows["default"])(missingRow, options.dataHandler, [], getEffectiveSectionRowCount(section)); | ||
var request = (0, _getRequestForMissingRows["default"])(missingRow, options.dataHandler, [], getEffectiveSectionRemoteRowCount(section)); | ||
return createRowsRequest(section.key, request, false); | ||
@@ -407,30 +416,6 @@ })); | ||
}, []); | ||
} // Block locally add/deleting rows while refreshing | ||
} | ||
var addRowData = (0, _react.useCallback)(function (sectionKey, rowKey, rowData, afterRowKey) { | ||
if (isRefreshing) { | ||
return false; | ||
} | ||
return rowsBySectionAddRowData(sectionKey, rowKey, rowData, afterRowKey); | ||
}, [isRefreshing, rowsBySectionAddRowData]); | ||
var deleteRowData = (0, _react.useCallback)(function (sectionKey, rowKey) { | ||
if (isRefreshing) { | ||
return false; | ||
} | ||
return rowsBySectionDeleteRowData(sectionKey, rowKey); | ||
}, [isRefreshing, rowsBySectionDeleteRowData]); | ||
var setRowData = (0, _react.useCallback)(function (rowKey, rowData) { | ||
if (isRefreshing) { | ||
return; | ||
} | ||
return rowsBySectionSetRowData(rowKey, rowData); | ||
}, [isRefreshing, rowsBySectionSetRowData]); | ||
return { | ||
addRowData: addRowData, | ||
columnAndOverviewData: columnAndOverviewData, | ||
deleteRowData: deleteRowData, | ||
doesCellHaveData: doesCellHaveData, | ||
@@ -447,3 +432,2 @@ copyHandler: options.copyHandler, | ||
sectionRowMatcher: sectionRowMatcher, | ||
setRowData: setRowData, | ||
getRowData: getRowData, | ||
@@ -450,0 +434,0 @@ totalRowCount: totalRowCount, |
{ | ||
"name": "streaksheet", | ||
"version": "0.8.36", | ||
"version": "0.9.0", | ||
"author": "Chris Cowan <agentme49@gmail.com>", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
823920
175
7308