@hrforte/react-pivottable 2.2.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,12 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.DEFAULT_WORKER_URL = undefined;
7
7
  exports.setWorkerDebug = setWorkerDebug;
8
8
  exports.configureWorkerUrl = configureWorkerUrl;
9
+ exports.retainPivotWorker = retainPivotWorker;
10
+ exports.releasePivotWorker = releasePivotWorker;
9
11
  exports.computePivotInWorker = computePivotInWorker;
12
+ exports.computePivotViewportInWorker = computePivotViewportInWorker;
13
+ exports.releasePivotInWorker = releasePivotInWorker;
14
+ exports.releaseDatasetInWorker = releaseDatasetInWorker;
10
15
  exports.computePivotSynchronously = computePivotSynchronously;
11
16
  exports.computePivotWithFallback = computePivotWithFallback;
12
17
 
@@ -21,8 +26,7 @@ var DEFAULT_WORKER_URL = exports.DEFAULT_WORKER_URL = 'pivot-worker.js'; /* esli
21
26
  * Responsibilities:
22
27
  * - lazily create a single shared Worker (at `workerUrl`, overrideable),
23
28
  * - route result/error messages to the matching request,
24
- * - transparently fall back to a synchronous main-thread computation when
25
- * workers are unavailable or the worker bundle fails to load.
29
+ * - surface worker errors instead of silently recomputing on the main thread.
26
30
  *
27
31
  * Debug logging is off by default. Turn it on with the `workerDebug` prop of
28
32
  * PivotTableUI (or by setting `window.__PVT_WORKER_DEBUG__ = true` before
@@ -32,6 +36,8 @@ var DEFAULT_WORKER_URL = exports.DEFAULT_WORKER_URL = 'pivot-worker.js'; /* esli
32
36
 
33
37
 
34
38
  var REQUEST_TIMEOUT_MS = 300000;
39
+ var VIEWPORT_TIMEOUT_MS = 10000;
40
+ var DATA_CHUNK_SIZE = 500;
35
41
 
36
42
  var workerUrl = DEFAULT_WORKER_URL;
37
43
  var sharedWorker = null;
@@ -42,8 +48,11 @@ var sharedWorkerBroken = false;
42
48
  var hasResultEver = false;
43
49
  var nextRequestId = 1;
44
50
  var lastStagedDataKey = null;
51
+ var stagingPromises = new Map();
45
52
  var workerDebug = false;
46
53
  var pendingRequests = new Map();
54
+ var pendingViewportByPivot = new Map();
55
+ var workerOwners = new Set();
47
56
 
48
57
  function setWorkerDebug(enabled) {
49
58
  var next = Boolean(enabled);
@@ -97,6 +106,24 @@ var failAllPending = function failAllPending(error) {
97
106
  entry.reject(error);
98
107
  });
99
108
  pendingRequests.clear();
109
+ pendingViewportByPivot.clear();
110
+ };
111
+
112
+ var cancelPendingViewport = function cancelPendingViewport(viewportKey) {
113
+ var requestId = pendingViewportByPivot.get(viewportKey);
114
+ if (typeof requestId !== 'number') {
115
+ return;
116
+ }
117
+ pendingViewportByPivot.delete(viewportKey);
118
+ var entry = pendingRequests.get(requestId);
119
+ if (!entry) {
120
+ return;
121
+ }
122
+ clearTimeout(entry.timer);
123
+ pendingRequests.delete(requestId);
124
+ var error = new Error('Pivot viewport request was replaced');
125
+ error.code = 'PIVOT_VIEWPORT_CANCELLED';
126
+ entry.reject(error);
100
127
  };
101
128
 
102
129
  function configureWorkerUrl(url) {
@@ -111,10 +138,36 @@ function configureWorkerUrl(url) {
111
138
  sharedWorkerBroken = false;
112
139
  hasResultEver = false;
113
140
  lastStagedDataKey = null;
141
+ stagingPromises.clear();
114
142
  }
115
143
  }
116
144
  }
117
145
 
146
+ function retainPivotWorker(ownerKey) {
147
+ if (ownerKey) {
148
+ workerOwners.add(ownerKey);
149
+ }
150
+ }
151
+
152
+ function releasePivotWorker(ownerKey) {
153
+ if (!ownerKey) {
154
+ return;
155
+ }
156
+ workerOwners.delete(ownerKey);
157
+ if (sharedWorker) {
158
+ sharedWorker.postMessage({ type: 'pivot:releaseOwner', ownerKey: ownerKey });
159
+ }
160
+ if (sharedWorker && workerOwners.size === 0) {
161
+ failAllPending(new Error('Pivot worker was released'));
162
+ sharedWorker.terminate();
163
+ sharedWorker = null;
164
+ sharedWorkerBroken = false;
165
+ hasResultEver = false;
166
+ lastStagedDataKey = null;
167
+ stagingPromises.clear();
168
+ }
169
+ }
170
+
118
171
  var handleWorkerMessage = function handleWorkerMessage(event) {
119
172
  var message = event.data || {};
120
173
  if (message.type === 'pivot:log') {
@@ -133,7 +186,15 @@ var handleWorkerMessage = function handleWorkerMessage(event) {
133
186
  }
134
187
  clearTimeout(entry.timer);
135
188
  pendingRequests.delete(message.id);
136
- if (message.type === 'pivot:result') {
189
+ if (entry.viewportKey !== undefined && pendingViewportByPivot.get(entry.viewportKey) === message.id) {
190
+ pendingViewportByPivot.delete(entry.viewportKey);
191
+ }
192
+ if (message.type === 'pivot:result' || message.type === 'pivot:viewportResult') {
193
+ if (message.type === 'pivot:viewportResult') {
194
+ log('#' + message.id + ' viewport received in ' + (Date.now() - entry.startedAt) + 'ms');
195
+ entry.resolve(message.result);
196
+ return;
197
+ }
137
198
  hasResultEver = true;
138
199
  var result = message.result;
139
200
  log('#' + message.id + ' result received in ' + (Date.now() - entry.startedAt) + 'ms', {
@@ -149,6 +210,48 @@ var handleWorkerMessage = function handleWorkerMessage(event) {
149
210
  }
150
211
  };
151
212
 
213
+ // `Worker.postMessage()` structured-clones its payload on the calling thread.
214
+ // Sending a wide dataset in one message can therefore freeze the UI before
215
+ // the worker has even started. Large inputs are split across macrotasks so
216
+ // pointer and paint work can run between chunks.
217
+ var stageDataInWorker = function stageDataInWorker(worker, id, dataKey, data, ownerKey) {
218
+ var owner = ownerKey ? { ownerKey: ownerKey } : {};
219
+ if (!Array.isArray(data) || data.length <= DATA_CHUNK_SIZE) {
220
+ worker.postMessage(Object.assign({ type: 'pivot:setData', id: id, dataKey: dataKey, data: data }, owner));
221
+ return null;
222
+ }
223
+
224
+ return new Promise(function (resolve, reject) {
225
+ try {
226
+ worker.postMessage(Object.assign({ type: 'pivot:setDataStart', id: id, dataKey: dataKey }, owner));
227
+ var offset = 0;
228
+ var postNextChunk = function postNextChunk() {
229
+ try {
230
+ var end = Math.min(offset + DATA_CHUNK_SIZE, data.length);
231
+ worker.postMessage({
232
+ type: 'pivot:setDataChunk',
233
+ id: id,
234
+ dataKey: dataKey,
235
+ data: data.slice(offset, end)
236
+ });
237
+ offset = end;
238
+ if (offset < data.length) {
239
+ setTimeout(postNextChunk, 0);
240
+ return;
241
+ }
242
+ worker.postMessage({ type: 'pivot:setDataEnd', id: id, dataKey: dataKey });
243
+ resolve();
244
+ } catch (error) {
245
+ reject(error);
246
+ }
247
+ };
248
+ postNextChunk();
249
+ } catch (error) {
250
+ reject(error);
251
+ }
252
+ });
253
+ };
254
+
152
255
  var ensureWorker = function ensureWorker() {
153
256
  if (sharedWorkerBroken) {
154
257
  return null;
@@ -191,7 +294,7 @@ var ensureWorker = function ensureWorker() {
191
294
  * worker reuse the materialized dataset across consecutive computations and
192
295
  * lets the client skip re-staging identical data.
193
296
  */
194
- function computePivotInWorker(data, dataKey, config) {
297
+ function computePivotInWorker(data, dataKey, config, ownerKey) {
195
298
  var worker = ensureWorker();
196
299
  if (!worker) {
197
300
  log('worker unavailable -> synchronous fallback');
@@ -212,14 +315,118 @@ function computePivotInWorker(data, dataKey, config) {
212
315
  });
213
316
  var mustStage = lastStagedDataKey !== dataKey;
214
317
  log('#' + id + ' dispatching to worker (dataKey=' + dataKey + (mustStage ? ', staging ' + (data || []).length + ' records' : ', cached dataset') + ', ' + describeConfig(config) + ')');
318
+ var dataReady = null;
215
319
  if (mustStage) {
216
- worker.postMessage({ type: 'pivot:setData', id: id, dataKey: dataKey, data: data });
217
320
  lastStagedDataKey = dataKey;
321
+ dataReady = stageDataInWorker(worker, id, dataKey, data, ownerKey);
322
+ if (dataReady) {
323
+ stagingPromises.set(dataKey, dataReady);
324
+ dataReady.then(function () {
325
+ if (stagingPromises.get(dataKey) === dataReady) {
326
+ stagingPromises.delete(dataKey);
327
+ }
328
+ }, function () {
329
+ return stagingPromises.delete(dataKey);
330
+ });
331
+ }
332
+ } else if (stagingPromises.has(dataKey)) {
333
+ dataReady = stagingPromises.get(dataKey);
334
+ }
335
+ var postCompute = function postCompute() {
336
+ if (pendingRequests.has(id)) {
337
+ worker.postMessage({
338
+ type: 'pivot:compute',
339
+ id: id,
340
+ dataKey: dataKey,
341
+ config: config,
342
+ ownerKey: ownerKey
343
+ });
344
+ }
345
+ };
346
+ if (dataReady) {
347
+ dataReady.then(postCompute).catch(function (error) {
348
+ clearTimeout(timer);
349
+ pendingRequests.delete(id);
350
+ reject(error);
351
+ });
352
+ } else {
353
+ postCompute();
354
+ }
355
+ });
356
+ }
357
+
358
+ // Request a small row window from a pivot result already cached in the worker.
359
+ // No dataset or full pivot state is cloned for a scroll request.
360
+ function computePivotViewportInWorker(viewportKey, start, end, columnMode) {
361
+ var columnStart = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
362
+ var columnEnd = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : Number.MAX_SAFE_INTEGER;
363
+
364
+ var worker = ensureWorker();
365
+ if (!worker) {
366
+ return Promise.reject(new Error('Web worker unavailable'));
367
+ }
368
+ cancelPendingViewport(viewportKey);
369
+ var id = nextRequestId++;
370
+ return new Promise(function (resolve, reject) {
371
+ var timer = setTimeout(function () {
372
+ pendingRequests.delete(id);
373
+ if (pendingViewportByPivot.get(viewportKey) === id) {
374
+ pendingViewportByPivot.delete(viewportKey);
375
+ }
376
+ reject(new Error('Pivot viewport timed out'));
377
+ }, VIEWPORT_TIMEOUT_MS);
378
+ pendingRequests.set(id, {
379
+ resolve: resolve,
380
+ reject: reject,
381
+ timer: timer,
382
+ startedAt: Date.now(),
383
+ viewportKey: viewportKey
384
+ });
385
+ pendingViewportByPivot.set(viewportKey, id);
386
+ log('#' + id + ' viewport dispatch (rows=' + start + '-' + end + ', ' + ('columns=' + columnStart + '-' + columnEnd + ', pivot=' + viewportKey + ')'));
387
+ try {
388
+ worker.postMessage({
389
+ type: 'pivot:viewport',
390
+ id: id,
391
+ viewportKey: viewportKey,
392
+ start: start,
393
+ end: end,
394
+ columnMode: columnMode,
395
+ columnStart: columnStart,
396
+ columnEnd: columnEnd
397
+ });
398
+ } catch (error) {
399
+ clearTimeout(timer);
400
+ pendingRequests.delete(id);
401
+ if (pendingViewportByPivot.get(viewportKey) === id) {
402
+ pendingViewportByPivot.delete(viewportKey);
403
+ }
404
+ reject(error);
218
405
  }
219
- worker.postMessage({ type: 'pivot:compute', id: id, dataKey: dataKey, config: config });
220
406
  });
221
407
  }
222
408
 
409
+ // Release a full virtual pivot as soon as its table no longer references it.
410
+ // This intentionally does not create a worker during component cleanup.
411
+ function releasePivotInWorker(viewportKey) {
412
+ if (!sharedWorker || typeof viewportKey !== 'number') {
413
+ return;
414
+ }
415
+ cancelPendingViewport(viewportKey);
416
+ sharedWorker.postMessage({ type: 'pivot:release', viewportKey: viewportKey });
417
+ }
418
+
419
+ function releaseDatasetInWorker(dataKey) {
420
+ if (!sharedWorker || !dataKey) {
421
+ return;
422
+ }
423
+ if (lastStagedDataKey === dataKey) {
424
+ lastStagedDataKey = null;
425
+ }
426
+ stagingPromises.delete(dataKey);
427
+ sharedWorker.postMessage({ type: 'pivot:releaseData', dataKey: dataKey });
428
+ }
429
+
223
430
  /*
224
431
  * Same contract as the worker path, executed on the main thread. Used as the
225
432
  * automatic fallback whenever the worker path is unavailable. Deferred by
@@ -248,14 +455,13 @@ function computePivotSynchronously(data, config) {
248
455
  }
249
456
 
250
457
  /*
251
- * Worker-first entry point with automatic synchronous fallback. The fallback
252
- * produces the exact same serialized shape, so callers render identically
253
- * either way.
458
+ * Keep the existing entry point while testing worker failures without a
459
+ * synchronous fallback. Rejections reach PivotTableUI's error state.
254
460
  */
255
- function computePivotWithFallback(data, dataKey, config) {
256
- return computePivotInWorker(data, dataKey, config).catch(function (error) {
257
- log('worker request failed, falling back to the main thread:', error && error.message || error);
258
- return computePivotSynchronously(data, config);
461
+ function computePivotWithFallback(data, dataKey, config, ownerKey) {
462
+ return computePivotInWorker(data, dataKey, config, ownerKey).catch(function (error) {
463
+ log('worker request failed (synchronous fallback disabled):', error);
464
+ throw error;
259
465
  });
260
466
  }
261
467
  //# sourceMappingURL=PivotDataWorker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PivotDataWorker.js"],"names":["setWorkerDebug","configureWorkerUrl","computePivotInWorker","computePivotSynchronously","computePivotWithFallback","DEFAULT_WORKER_URL","REQUEST_TIMEOUT_MS","workerUrl","sharedWorker","sharedWorkerBroken","hasResultEver","nextRequestId","lastStagedDataKey","workerDebug","pendingRequests","Map","enabled","next","Boolean","wasEnabled","log","postMessage","type","isDebugEnabled","window","__PVT_WORKER_DEBUG__","args","describeConfig","config","rows","join","cols","aggregations","length","countOf","Array","isArray","value","undefined","failAllPending","forEach","clearTimeout","entry","timer","reject","error","clear","url","Error","terminate","handleWorkerMessage","message","event","data","detail","get","id","delete","result","Date","now","startedAt","totalRecords","rowKeys","colKeys","resolve","ensureWorker","Worker","onmessage","onerror","dataKey","worker","Promise","setTimeout","set","mustStage","materialized","catch"],"mappings":"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","file":"PivotDataWorker.js","sourcesContent":["/* eslint-disable valid-jsdoc */\n/* eslint-disable no-console */\n/* eslint-disable no-undefined */\n/*\n * Main-thread client for the pivot Web Worker (src/pivotWorker.js).\n *\n * Responsibilities:\n * - lazily create a single shared Worker (at `workerUrl`, overrideable),\n * - route result/error messages to the matching request,\n * - transparently fall back to a synchronous main-thread computation when\n * workers are unavailable or the worker bundle fails to load.\n *\n * Debug logging is off by default. Turn it on with the `workerDebug` prop of\n * PivotTableUI (or by setting `window.__PVT_WORKER_DEBUG__ = true` before\n * rendering) to trace worker creation, staging, computation, progress,\n * results, errors and fallbacks in the browser console.\n */\nimport {materializeData, computePivotState} from './pivotCompute';\n\nexport const DEFAULT_WORKER_URL = 'pivot-worker.js';\n\nconst REQUEST_TIMEOUT_MS = 300000;\n\nlet workerUrl = DEFAULT_WORKER_URL;\nlet sharedWorker = null;\n// The worker is marked broken only if it fails before ever producing a\n// result (e.g. a 404 worker script); runtime hiccups later on just reject\n// the affected request and fall back once.\nlet sharedWorkerBroken = false;\nlet hasResultEver = false;\nlet nextRequestId = 1;\nlet lastStagedDataKey = null;\nlet workerDebug = false;\nconst pendingRequests = new Map();\n\nexport function setWorkerDebug(enabled) {\n const next = Boolean(enabled);\n const wasEnabled = workerDebug;\n if (next === wasEnabled) {\n return;\n }\n if (next) {\n workerDebug = true;\n log('debug logging enabled');\n } else {\n // Log while logging is still active, so the \"disabled\" notice is shown.\n log('debug logging disabled');\n workerDebug = false;\n }\n if (sharedWorker) {\n sharedWorker.postMessage({type: 'pivot:debug', enabled: workerDebug});\n }\n}\n\nconst isDebugEnabled = () =>\n workerDebug ||\n (typeof window !== 'undefined' && window.__PVT_WORKER_DEBUG__ === true);\n\nfunction log(...args) {\n if (!isDebugEnabled()) {\n return;\n }\n console.log(\n '%c[pivottable worker]',\n 'color:#ff6600;font-weight:bold',\n ...args\n );\n}\n\nconst describeConfig = config =>\n `rows=[${(config.rows || []).join(', ')}] cols=[${(config.cols || []).join(\n ', '\n )}] aggregations=${(config.aggregations || []).length}`;\n\n// Length of an optional array field, used for defensive debug logging.\nconst countOf = value => (Array.isArray(value) ? value.length : undefined);\n\nconst failAllPending = error => {\n pendingRequests.forEach(entry => {\n clearTimeout(entry.timer);\n entry.reject(error);\n });\n pendingRequests.clear();\n};\n\nexport function configureWorkerUrl(url) {\n if (url && url !== workerUrl) {\n workerUrl = url;\n if (sharedWorker) {\n // Reject in-flight requests first so callers fall back to the\n // synchronous path instead of waiting for the request timeout.\n failAllPending(new Error('Pivot worker was reconfigured'));\n sharedWorker.terminate();\n sharedWorker = null;\n sharedWorkerBroken = false;\n hasResultEver = false;\n lastStagedDataKey = null;\n }\n }\n}\n\nconst handleWorkerMessage = event => {\n const message = event.data || {};\n if (message.type === 'pivot:log') {\n log('(in worker)', message.message, message.detail || '');\n return;\n }\n const entry = pendingRequests.get(message.id);\n if (!entry) {\n return;\n }\n if (message.type === 'pivot:progress') {\n // Progress reporting was removed: the UI only shows a loading overlay\n // until `pivot:result` arrives. Ignore messages from older worker\n // bundles that still emit progress so the request is not corrupted.\n return;\n }\n clearTimeout(entry.timer);\n pendingRequests.delete(message.id);\n if (message.type === 'pivot:result') {\n hasResultEver = true;\n const result = message.result;\n log(`#${message.id} result received in ${Date.now() - entry.startedAt}ms`, {\n totalRecords: result && result.totalRecords,\n rowKeys: countOf(result && result.rowKeys),\n colKeys: countOf(result && result.colKeys),\n aggregations: countOf(result && result.aggregations),\n });\n entry.resolve(message.result);\n } else if (message.type === 'pivot:error') {\n log(`#${message.id} worker reported an error:`, message.message);\n entry.reject(new Error(message.message || 'Pivot worker error'));\n }\n};\n\nconst ensureWorker = () => {\n if (sharedWorkerBroken) {\n return null;\n }\n\n if (typeof Worker === 'undefined') {\n log('no Worker support in this environment');\n return null;\n }\n\n if (!sharedWorker) {\n try {\n sharedWorker = new Worker(workerUrl);\n log('worker created:', workerUrl);\n } catch (error) {\n sharedWorkerBroken = true;\n log('worker creation failed:', error && error.message);\n return null;\n }\n sharedWorker.onmessage = handleWorkerMessage;\n sharedWorker.onerror = event => {\n log(\n 'worker error event (script failed to load / runtime error):',\n (event && event.message) || ''\n );\n failAllPending(new Error('Pivot worker failed to load'));\n if (!hasResultEver) {\n sharedWorkerBroken = true;\n log('worker marked unusable -> will use the synchronous fallback');\n }\n };\n if (isDebugEnabled()) {\n sharedWorker.postMessage({type: 'pivot:debug', enabled: true});\n }\n }\n return sharedWorker;\n};\n\n/*\n * Runs a full computation inside the shared worker.\n *\n * `dataKey` must change whenever the underlying dataset changes. It lets the\n * worker reuse the materialized dataset across consecutive computations and\n * lets the client skip re-staging identical data.\n */\nexport function computePivotInWorker(data, dataKey, config) {\n const worker = ensureWorker();\n if (!worker) {\n log('worker unavailable -> synchronous fallback');\n return Promise.reject(new Error('Web worker unavailable'));\n }\n const id = nextRequestId++;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingRequests.delete(id);\n log(`#${id} timed out after ${REQUEST_TIMEOUT_MS}ms`);\n reject(new Error('Pivot worker timed out'));\n }, REQUEST_TIMEOUT_MS);\n pendingRequests.set(id, {\n resolve,\n reject,\n timer,\n startedAt: Date.now(),\n });\n const mustStage = lastStagedDataKey !== dataKey;\n log(\n `#${id} dispatching to worker (dataKey=${dataKey}${\n mustStage\n ? ', staging ' + (data || []).length + ' records'\n : ', cached dataset'\n }, ${describeConfig(config)})`\n );\n if (mustStage) {\n worker.postMessage({type: 'pivot:setData', id, dataKey, data});\n lastStagedDataKey = dataKey;\n }\n worker.postMessage({type: 'pivot:compute', id, dataKey, config});\n });\n}\n\n/*\n * Same contract as the worker path, executed on the main thread. Used as the\n * automatic fallback whenever the worker path is unavailable. Deferred by\n * one tick so a loading indicator can paint before the blocking work starts.\n */\nexport function computePivotSynchronously(data, config) {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n const startedAt = Date.now();\n log('running synchronous computation on the main thread...');\n try {\n const materialized = materializeData(data, {});\n const result = computePivotState(materialized, config);\n log(`synchronous computation finished in ${Date.now() - startedAt}ms`, {\n totalRecords: result.totalRecords,\n rowKeys: result.rowKeys.length,\n colKeys: result.colKeys.length,\n });\n resolve(result);\n } catch (error) {\n log('synchronous computation failed:', error && error.message);\n reject(error);\n }\n }, 0);\n });\n}\n\n/*\n * Worker-first entry point with automatic synchronous fallback. The fallback\n * produces the exact same serialized shape, so callers render identically\n * either way.\n */\nexport function computePivotWithFallback(data, dataKey, config) {\n return computePivotInWorker(data, dataKey, config).catch(error => {\n log(\n 'worker request failed, falling back to the main thread:',\n (error && error.message) || error\n );\n return computePivotSynchronously(data, config);\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/PivotDataWorker.js"],"names":["setWorkerDebug","configureWorkerUrl","retainPivotWorker","releasePivotWorker","computePivotInWorker","computePivotViewportInWorker","releasePivotInWorker","releaseDatasetInWorker","computePivotSynchronously","computePivotWithFallback","DEFAULT_WORKER_URL","REQUEST_TIMEOUT_MS","VIEWPORT_TIMEOUT_MS","DATA_CHUNK_SIZE","workerUrl","sharedWorker","sharedWorkerBroken","hasResultEver","nextRequestId","lastStagedDataKey","stagingPromises","Map","workerDebug","pendingRequests","pendingViewportByPivot","workerOwners","Set","enabled","next","Boolean","wasEnabled","log","postMessage","type","isDebugEnabled","window","__PVT_WORKER_DEBUG__","args","describeConfig","config","rows","join","cols","aggregations","length","countOf","Array","isArray","value","undefined","failAllPending","forEach","clearTimeout","entry","timer","reject","error","clear","cancelPendingViewport","requestId","get","viewportKey","delete","Error","code","url","terminate","ownerKey","add","size","handleWorkerMessage","message","event","data","detail","id","Date","now","startedAt","resolve","result","totalRecords","rowKeys","colKeys","stageDataInWorker","worker","dataKey","owner","Object","assign","Promise","offset","postNextChunk","end","Math","min","slice","setTimeout","ensureWorker","Worker","onmessage","onerror","set","mustStage","dataReady","then","has","postCompute","catch","start","columnMode","columnStart","columnEnd","Number","MAX_SAFE_INTEGER","materialized"],"mappings":"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","file":"PivotDataWorker.js","sourcesContent":["/* eslint-disable valid-jsdoc */\n/* eslint-disable no-console */\n/* eslint-disable no-undefined */\n/*\n * Main-thread client for the pivot Web Worker (src/pivotWorker.js).\n *\n * Responsibilities:\n * - lazily create a single shared Worker (at `workerUrl`, overrideable),\n * - route result/error messages to the matching request,\n * - surface worker errors instead of silently recomputing on the main thread.\n *\n * Debug logging is off by default. Turn it on with the `workerDebug` prop of\n * PivotTableUI (or by setting `window.__PVT_WORKER_DEBUG__ = true` before\n * rendering) to trace worker creation, staging, computation, progress,\n * results, errors and fallbacks in the browser console.\n */\nimport {materializeData, computePivotState} from './pivotCompute';\n\nexport const DEFAULT_WORKER_URL = 'pivot-worker.js';\n\nconst REQUEST_TIMEOUT_MS = 300000;\nconst VIEWPORT_TIMEOUT_MS = 10000;\nconst DATA_CHUNK_SIZE = 500;\n\nlet workerUrl = DEFAULT_WORKER_URL;\nlet sharedWorker = null;\n// The worker is marked broken only if it fails before ever producing a\n// result (e.g. a 404 worker script); runtime hiccups later on just reject\n// the affected request and fall back once.\nlet sharedWorkerBroken = false;\nlet hasResultEver = false;\nlet nextRequestId = 1;\nlet lastStagedDataKey = null;\nconst stagingPromises = new Map();\nlet workerDebug = false;\nconst pendingRequests = new Map();\nconst pendingViewportByPivot = new Map();\nconst workerOwners = new Set();\n\nexport function setWorkerDebug(enabled) {\n const next = Boolean(enabled);\n const wasEnabled = workerDebug;\n if (next === wasEnabled) {\n return;\n }\n if (next) {\n workerDebug = true;\n log('debug logging enabled');\n } else {\n // Log while logging is still active, so the \"disabled\" notice is shown.\n log('debug logging disabled');\n workerDebug = false;\n }\n if (sharedWorker) {\n sharedWorker.postMessage({type: 'pivot:debug', enabled: workerDebug});\n }\n}\n\nconst isDebugEnabled = () =>\n workerDebug ||\n (typeof window !== 'undefined' && window.__PVT_WORKER_DEBUG__ === true);\n\nfunction log(...args) {\n if (!isDebugEnabled()) {\n return;\n }\n console.log(\n '%c[pivottable worker]',\n 'color:#ff6600;font-weight:bold',\n ...args\n );\n}\n\nconst describeConfig = config =>\n `rows=[${(config.rows || []).join(', ')}] cols=[${(config.cols || []).join(\n ', '\n )}] aggregations=${(config.aggregations || []).length}`;\n\n// Length of an optional array field, used for defensive debug logging.\nconst countOf = value => (Array.isArray(value) ? value.length : undefined);\n\nconst failAllPending = error => {\n pendingRequests.forEach(entry => {\n clearTimeout(entry.timer);\n entry.reject(error);\n });\n pendingRequests.clear();\n pendingViewportByPivot.clear();\n};\n\nconst cancelPendingViewport = viewportKey => {\n const requestId = pendingViewportByPivot.get(viewportKey);\n if (typeof requestId !== 'number') {\n return;\n }\n pendingViewportByPivot.delete(viewportKey);\n const entry = pendingRequests.get(requestId);\n if (!entry) {\n return;\n }\n clearTimeout(entry.timer);\n pendingRequests.delete(requestId);\n const error = new Error('Pivot viewport request was replaced');\n error.code = 'PIVOT_VIEWPORT_CANCELLED';\n entry.reject(error);\n};\n\nexport function configureWorkerUrl(url) {\n if (url && url !== workerUrl) {\n workerUrl = url;\n if (sharedWorker) {\n // Reject in-flight requests first so callers fall back to the\n // synchronous path instead of waiting for the request timeout.\n failAllPending(new Error('Pivot worker was reconfigured'));\n sharedWorker.terminate();\n sharedWorker = null;\n sharedWorkerBroken = false;\n hasResultEver = false;\n lastStagedDataKey = null;\n stagingPromises.clear();\n }\n }\n}\n\nexport function retainPivotWorker(ownerKey) {\n if (ownerKey) {\n workerOwners.add(ownerKey);\n }\n}\n\nexport function releasePivotWorker(ownerKey) {\n if (!ownerKey) {\n return;\n }\n workerOwners.delete(ownerKey);\n if (sharedWorker) {\n sharedWorker.postMessage({type: 'pivot:releaseOwner', ownerKey});\n }\n if (sharedWorker && workerOwners.size === 0) {\n failAllPending(new Error('Pivot worker was released'));\n sharedWorker.terminate();\n sharedWorker = null;\n sharedWorkerBroken = false;\n hasResultEver = false;\n lastStagedDataKey = null;\n stagingPromises.clear();\n }\n}\n\nconst handleWorkerMessage = event => {\n const message = event.data || {};\n if (message.type === 'pivot:log') {\n log('(in worker)', message.message, message.detail || '');\n return;\n }\n const entry = pendingRequests.get(message.id);\n if (!entry) {\n return;\n }\n if (message.type === 'pivot:progress') {\n // Progress reporting was removed: the UI only shows a loading overlay\n // until `pivot:result` arrives. Ignore messages from older worker\n // bundles that still emit progress so the request is not corrupted.\n return;\n }\n clearTimeout(entry.timer);\n pendingRequests.delete(message.id);\n if (\n entry.viewportKey !== undefined &&\n pendingViewportByPivot.get(entry.viewportKey) === message.id\n ) {\n pendingViewportByPivot.delete(entry.viewportKey);\n }\n if (\n message.type === 'pivot:result' ||\n message.type === 'pivot:viewportResult'\n ) {\n if (message.type === 'pivot:viewportResult') {\n log(\n `#${message.id} viewport received in ${Date.now() - entry.startedAt}ms`\n );\n entry.resolve(message.result);\n return;\n }\n hasResultEver = true;\n const result = message.result;\n log(`#${message.id} result received in ${Date.now() - entry.startedAt}ms`, {\n totalRecords: result && result.totalRecords,\n rowKeys: countOf(result && result.rowKeys),\n colKeys: countOf(result && result.colKeys),\n aggregations: countOf(result && result.aggregations),\n });\n entry.resolve(message.result);\n } else if (message.type === 'pivot:error') {\n log(`#${message.id} worker reported an error:`, message.message);\n entry.reject(new Error(message.message || 'Pivot worker error'));\n }\n};\n\n// `Worker.postMessage()` structured-clones its payload on the calling thread.\n// Sending a wide dataset in one message can therefore freeze the UI before\n// the worker has even started. Large inputs are split across macrotasks so\n// pointer and paint work can run between chunks.\nconst stageDataInWorker = (worker, id, dataKey, data, ownerKey) => {\n const owner = ownerKey ? {ownerKey} : {};\n if (!Array.isArray(data) || data.length <= DATA_CHUNK_SIZE) {\n worker.postMessage(\n Object.assign({type: 'pivot:setData', id, dataKey, data}, owner)\n );\n return null;\n }\n\n return new Promise((resolve, reject) => {\n try {\n worker.postMessage(\n Object.assign({type: 'pivot:setDataStart', id, dataKey}, owner)\n );\n let offset = 0;\n const postNextChunk = () => {\n try {\n const end = Math.min(offset + DATA_CHUNK_SIZE, data.length);\n worker.postMessage({\n type: 'pivot:setDataChunk',\n id,\n dataKey,\n data: data.slice(offset, end),\n });\n offset = end;\n if (offset < data.length) {\n setTimeout(postNextChunk, 0);\n return;\n }\n worker.postMessage({type: 'pivot:setDataEnd', id, dataKey});\n resolve();\n } catch (error) {\n reject(error);\n }\n };\n postNextChunk();\n } catch (error) {\n reject(error);\n }\n });\n};\n\nconst ensureWorker = () => {\n if (sharedWorkerBroken) {\n return null;\n }\n\n if (typeof Worker === 'undefined') {\n log('no Worker support in this environment');\n return null;\n }\n\n if (!sharedWorker) {\n try {\n sharedWorker = new Worker(workerUrl);\n log('worker created:', workerUrl);\n } catch (error) {\n sharedWorkerBroken = true;\n log('worker creation failed:', error && error.message);\n return null;\n }\n sharedWorker.onmessage = handleWorkerMessage;\n sharedWorker.onerror = event => {\n log(\n 'worker error event (script failed to load / runtime error):',\n (event && event.message) || ''\n );\n failAllPending(new Error('Pivot worker failed to load'));\n if (!hasResultEver) {\n sharedWorkerBroken = true;\n log('worker marked unusable -> will use the synchronous fallback');\n }\n };\n if (isDebugEnabled()) {\n sharedWorker.postMessage({type: 'pivot:debug', enabled: true});\n }\n }\n return sharedWorker;\n};\n\n/*\n * Runs a full computation inside the shared worker.\n *\n * `dataKey` must change whenever the underlying dataset changes. It lets the\n * worker reuse the materialized dataset across consecutive computations and\n * lets the client skip re-staging identical data.\n */\nexport function computePivotInWorker(data, dataKey, config, ownerKey) {\n const worker = ensureWorker();\n if (!worker) {\n log('worker unavailable -> synchronous fallback');\n return Promise.reject(new Error('Web worker unavailable'));\n }\n const id = nextRequestId++;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingRequests.delete(id);\n log(`#${id} timed out after ${REQUEST_TIMEOUT_MS}ms`);\n reject(new Error('Pivot worker timed out'));\n }, REQUEST_TIMEOUT_MS);\n pendingRequests.set(id, {\n resolve,\n reject,\n timer,\n startedAt: Date.now(),\n });\n const mustStage = lastStagedDataKey !== dataKey;\n log(\n `#${id} dispatching to worker (dataKey=${dataKey}${\n mustStage\n ? ', staging ' + (data || []).length + ' records'\n : ', cached dataset'\n }, ${describeConfig(config)})`\n );\n let dataReady = null;\n if (mustStage) {\n lastStagedDataKey = dataKey;\n dataReady = stageDataInWorker(worker, id, dataKey, data, ownerKey);\n if (dataReady) {\n stagingPromises.set(dataKey, dataReady);\n dataReady.then(\n () => {\n if (stagingPromises.get(dataKey) === dataReady) {\n stagingPromises.delete(dataKey);\n }\n },\n () => stagingPromises.delete(dataKey)\n );\n }\n } else if (stagingPromises.has(dataKey)) {\n dataReady = stagingPromises.get(dataKey);\n }\n const postCompute = () => {\n if (pendingRequests.has(id)) {\n worker.postMessage({\n type: 'pivot:compute',\n id,\n dataKey,\n config,\n ownerKey,\n });\n }\n };\n if (dataReady) {\n dataReady.then(postCompute).catch(error => {\n clearTimeout(timer);\n pendingRequests.delete(id);\n reject(error);\n });\n } else {\n postCompute();\n }\n });\n}\n\n// Request a small row window from a pivot result already cached in the worker.\n// No dataset or full pivot state is cloned for a scroll request.\nexport function computePivotViewportInWorker(\n viewportKey,\n start,\n end,\n columnMode,\n columnStart = 0,\n columnEnd = Number.MAX_SAFE_INTEGER\n) {\n const worker = ensureWorker();\n if (!worker) {\n return Promise.reject(new Error('Web worker unavailable'));\n }\n cancelPendingViewport(viewportKey);\n const id = nextRequestId++;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingRequests.delete(id);\n if (pendingViewportByPivot.get(viewportKey) === id) {\n pendingViewportByPivot.delete(viewportKey);\n }\n reject(new Error('Pivot viewport timed out'));\n }, VIEWPORT_TIMEOUT_MS);\n pendingRequests.set(id, {\n resolve,\n reject,\n timer,\n startedAt: Date.now(),\n viewportKey,\n });\n pendingViewportByPivot.set(viewportKey, id);\n log(\n `#${id} viewport dispatch (rows=${start}-${end}, ` +\n `columns=${columnStart}-${columnEnd}, pivot=${viewportKey})`\n );\n try {\n worker.postMessage({\n type: 'pivot:viewport',\n id,\n viewportKey,\n start,\n end,\n columnMode,\n columnStart,\n columnEnd,\n });\n } catch (error) {\n clearTimeout(timer);\n pendingRequests.delete(id);\n if (pendingViewportByPivot.get(viewportKey) === id) {\n pendingViewportByPivot.delete(viewportKey);\n }\n reject(error);\n }\n });\n}\n\n// Release a full virtual pivot as soon as its table no longer references it.\n// This intentionally does not create a worker during component cleanup.\nexport function releasePivotInWorker(viewportKey) {\n if (!sharedWorker || typeof viewportKey !== 'number') {\n return;\n }\n cancelPendingViewport(viewportKey);\n sharedWorker.postMessage({type: 'pivot:release', viewportKey});\n}\n\nexport function releaseDatasetInWorker(dataKey) {\n if (!sharedWorker || !dataKey) {\n return;\n }\n if (lastStagedDataKey === dataKey) {\n lastStagedDataKey = null;\n }\n stagingPromises.delete(dataKey);\n sharedWorker.postMessage({type: 'pivot:releaseData', dataKey});\n}\n\n/*\n * Same contract as the worker path, executed on the main thread. Used as the\n * automatic fallback whenever the worker path is unavailable. Deferred by\n * one tick so a loading indicator can paint before the blocking work starts.\n */\nexport function computePivotSynchronously(data, config) {\n return new Promise((resolve, reject) => {\n setTimeout(() => {\n const startedAt = Date.now();\n log('running synchronous computation on the main thread...');\n try {\n const materialized = materializeData(data, {});\n const result = computePivotState(materialized, config);\n log(`synchronous computation finished in ${Date.now() - startedAt}ms`, {\n totalRecords: result.totalRecords,\n rowKeys: result.rowKeys.length,\n colKeys: result.colKeys.length,\n });\n resolve(result);\n } catch (error) {\n log('synchronous computation failed:', error && error.message);\n reject(error);\n }\n }, 0);\n });\n}\n\n/*\n * Keep the existing entry point while testing worker failures without a\n * synchronous fallback. Rejections reach PivotTableUI's error state.\n */\nexport function computePivotWithFallback(data, dataKey, config, ownerKey) {\n return computePivotInWorker(data, dataKey, config, ownerKey).catch(error => {\n log('worker request failed (synchronous fallback disabled):', error);\n throw error;\n });\n}\n"]}
@@ -58,7 +58,8 @@ PivotTable.propTypes = Object.assign({}, _Utilities.PivotData.propTypes, {
58
58
  rowSorts: _propTypes2.default.objectOf(_propTypes2.default.oneOf(['ASC', 'DESC'])),
59
59
  onColSort: _propTypes2.default.func,
60
60
  onRowSort: _propTypes2.default.func,
61
- tableOptions: _propTypes2.default.object
61
+ tableOptions: _propTypes2.default.object,
62
+ virtualizeRows: _propTypes2.default.bool
62
63
  });
63
64
 
64
65
  PivotTable.defaultProps = Object.assign({}, _Utilities.PivotData.defaultProps, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PivotTable.jsx"],"names":["PivotTable","Renderer","props","renderers","rendererName","Object","keys","React","PureComponent","propTypes","assign","PivotData","PropTypes","string","objectOf","func","colSorts","oneOf","rowSorts","onColSort","onRowSort","tableOptions","object","defaultProps","TableRenderers"],"mappings":";;;;;;;;AAAA;;;;AACA;;;;AACA;;AACA;;;;;;;;;;;;AAEA;AACA;;IAEMA,U;;;;;;;;;;;6BACK;AACP,UAAMC,WAAW,KAAKC,KAAL,CAAWC,SAAX,CACf,KAAKD,KAAL,CAAWE,YAAX,IAA2B,KAAKF,KAAL,CAAWC,SAAtC,GACI,KAAKD,KAAL,CAAWE,YADf,GAEIC,OAAOC,IAAP,CAAY,KAAKJ,KAAL,CAAWC,SAAvB,EAAkC,CAAlC,CAHW,CAAjB;AAKA,aAAO,8BAAC,QAAD,EAAc,KAAKD,KAAnB,CAAP;AACD;;;;EARsBK,gBAAMC,a;;AAW/BR,WAAWS,SAAX,GAAuBJ,OAAOK,MAAP,CAAc,EAAd,EAAkBC,qBAAUF,SAA5B,EAAuC;AAC5DL,gBAAcQ,oBAAUC,MADoC;AAE5DV,aAAWS,oBAAUE,QAAV,CAAmBF,oBAAUG,IAA7B,CAFiD;AAG5DC,YAAUJ,oBAAUE,QAAV,CAAmBF,oBAAUK,KAAV,CAAgB,CAAC,KAAD,EAAQ,MAAR,CAAhB,CAAnB,CAHkD;AAI5DC,YAAUN,oBAAUE,QAAV,CAAmBF,oBAAUK,KAAV,CAAgB,CAAC,KAAD,EAAQ,MAAR,CAAhB,CAAnB,CAJkD;AAK5DE,aAAWP,oBAAUG,IALuC;AAM5DK,aAAWR,oBAAUG,IANuC;AAO5DM,gBAAcT,oBAAUU;AAPoC,CAAvC,CAAvB;;AAUAtB,WAAWuB,YAAX,GAA0BlB,OAAOK,MAAP,CAAc,EAAd,EAAkBC,qBAAUY,YAA5B,EAA0C;AAClEnB,gBAAc,OADoD;AAElED,aAAWqB,wBAFuD;AAGlEH,gBAAc;AAHoD,CAA1C,CAA1B;;kBAMerB,U","file":"PivotTable.js","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport {PivotData} from './Utilities';\nimport TableRenderers from './TableRenderers';\n\n/* eslint-disable react/prop-types */\n// eslint can't see inherited propTypes!\n\nclass PivotTable extends React.PureComponent {\n render() {\n const Renderer = this.props.renderers[\n this.props.rendererName in this.props.renderers\n ? this.props.rendererName\n : Object.keys(this.props.renderers)[0]\n ];\n return <Renderer {...this.props} />;\n }\n}\n\nPivotTable.propTypes = Object.assign({}, PivotData.propTypes, {\n rendererName: PropTypes.string,\n renderers: PropTypes.objectOf(PropTypes.func),\n colSorts: PropTypes.objectOf(PropTypes.oneOf(['ASC', 'DESC'])),\n rowSorts: PropTypes.objectOf(PropTypes.oneOf(['ASC', 'DESC'])),\n onColSort: PropTypes.func,\n onRowSort: PropTypes.func,\n tableOptions: PropTypes.object,\n});\n\nPivotTable.defaultProps = Object.assign({}, PivotData.defaultProps, {\n rendererName: 'Table',\n renderers: TableRenderers,\n tableOptions: {},\n});\n\nexport default PivotTable;\n"]}
1
+ {"version":3,"sources":["../src/PivotTable.jsx"],"names":["PivotTable","Renderer","props","renderers","rendererName","Object","keys","React","PureComponent","propTypes","assign","PivotData","PropTypes","string","objectOf","func","colSorts","oneOf","rowSorts","onColSort","onRowSort","tableOptions","object","virtualizeRows","bool","defaultProps","TableRenderers"],"mappings":";;;;;;;;AAAA;;;;AACA;;;;AACA;;AACA;;;;;;;;;;;;AAEA;AACA;;IAEMA,U;;;;;;;;;;;6BACK;AACP,UAAMC,WAAW,KAAKC,KAAL,CAAWC,SAAX,CACf,KAAKD,KAAL,CAAWE,YAAX,IAA2B,KAAKF,KAAL,CAAWC,SAAtC,GACI,KAAKD,KAAL,CAAWE,YADf,GAEIC,OAAOC,IAAP,CAAY,KAAKJ,KAAL,CAAWC,SAAvB,EAAkC,CAAlC,CAHW,CAAjB;AAKA,aAAO,8BAAC,QAAD,EAAc,KAAKD,KAAnB,CAAP;AACD;;;;EARsBK,gBAAMC,a;;AAW/BR,WAAWS,SAAX,GAAuBJ,OAAOK,MAAP,CAAc,EAAd,EAAkBC,qBAAUF,SAA5B,EAAuC;AAC5DL,gBAAcQ,oBAAUC,MADoC;AAE5DV,aAAWS,oBAAUE,QAAV,CAAmBF,oBAAUG,IAA7B,CAFiD;AAG5DC,YAAUJ,oBAAUE,QAAV,CAAmBF,oBAAUK,KAAV,CAAgB,CAAC,KAAD,EAAQ,MAAR,CAAhB,CAAnB,CAHkD;AAI5DC,YAAUN,oBAAUE,QAAV,CAAmBF,oBAAUK,KAAV,CAAgB,CAAC,KAAD,EAAQ,MAAR,CAAhB,CAAnB,CAJkD;AAK5DE,aAAWP,oBAAUG,IALuC;AAM5DK,aAAWR,oBAAUG,IANuC;AAO5DM,gBAAcT,oBAAUU,MAPoC;AAQ5DC,kBAAgBX,oBAAUY;AARkC,CAAvC,CAAvB;;AAWAxB,WAAWyB,YAAX,GAA0BpB,OAAOK,MAAP,CAAc,EAAd,EAAkBC,qBAAUc,YAA5B,EAA0C;AAClErB,gBAAc,OADoD;AAElED,aAAWuB,wBAFuD;AAGlEL,gBAAc;AAHoD,CAA1C,CAA1B;;kBAMerB,U","file":"PivotTable.js","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport {PivotData} from './Utilities';\nimport TableRenderers from './TableRenderers';\n\n/* eslint-disable react/prop-types */\n// eslint can't see inherited propTypes!\n\nclass PivotTable extends React.PureComponent {\n render() {\n const Renderer = this.props.renderers[\n this.props.rendererName in this.props.renderers\n ? this.props.rendererName\n : Object.keys(this.props.renderers)[0]\n ];\n return <Renderer {...this.props} />;\n }\n}\n\nPivotTable.propTypes = Object.assign({}, PivotData.propTypes, {\n rendererName: PropTypes.string,\n renderers: PropTypes.objectOf(PropTypes.func),\n colSorts: PropTypes.objectOf(PropTypes.oneOf(['ASC', 'DESC'])),\n rowSorts: PropTypes.objectOf(PropTypes.oneOf(['ASC', 'DESC'])),\n onColSort: PropTypes.func,\n onRowSort: PropTypes.func,\n tableOptions: PropTypes.object,\n virtualizeRows: PropTypes.bool,\n});\n\nPivotTable.defaultProps = Object.assign({}, PivotData.defaultProps, {\n rendererName: 'Table',\n renderers: TableRenderers,\n tableOptions: {},\n});\n\nexport default PivotTable;\n"]}
@@ -58,6 +58,7 @@ var AGG_KEY_LENGTH = 7;
58
58
  // inline `{}` literal would be a new object on every render, which makes the
59
59
  // rendered table re-render even when nothing about the pivot changed.
60
60
  var EMPTY_SORTS = {};
61
+ var EMPTY_ATTR_VALUES = {};
61
62
 
62
63
  /* eslint-disable react/prop-types */
63
64
  // eslint can't see inherited propTypes!
@@ -248,6 +249,7 @@ function DraggableAttribute(props) {
248
249
  }
249
250
 
250
251
  DraggableAttribute.defaultProps = {
252
+ attrValues: EMPTY_ATTR_VALUES,
251
253
  valueFilter: {}
252
254
  };
253
255
 
@@ -1132,61 +1134,7 @@ function PivotLoadingOverlay() {
1132
1134
  _react2.default.createElement(
1133
1135
  'div',
1134
1136
  { className: 'pvtLoadingText' },
1135
- _react2.default.createElement(
1136
- 'span',
1137
- null,
1138
- 'P'
1139
- ),
1140
- _react2.default.createElement(
1141
- 'span',
1142
- null,
1143
- 'r'
1144
- ),
1145
- _react2.default.createElement(
1146
- 'span',
1147
- null,
1148
- 'o'
1149
- ),
1150
- _react2.default.createElement(
1151
- 'span',
1152
- null,
1153
- 'c'
1154
- ),
1155
- _react2.default.createElement(
1156
- 'span',
1157
- null,
1158
- 'e'
1159
- ),
1160
- _react2.default.createElement(
1161
- 'span',
1162
- null,
1163
- 's'
1164
- ),
1165
- _react2.default.createElement(
1166
- 'span',
1167
- null,
1168
- 's'
1169
- ),
1170
- _react2.default.createElement(
1171
- 'span',
1172
- null,
1173
- 'i'
1174
- ),
1175
- _react2.default.createElement(
1176
- 'span',
1177
- null,
1178
- 'n'
1179
- ),
1180
- _react2.default.createElement(
1181
- 'span',
1182
- null,
1183
- 'g'
1184
- ),
1185
- _react2.default.createElement(
1186
- 'span',
1187
- null,
1188
- '\u2026'
1189
- )
1137
+ 'Processing'
1190
1138
  )
1191
1139
  );
1192
1140
  }
@@ -1288,7 +1236,7 @@ function PivotTableUI(props) {
1288
1236
 
1289
1237
  var computeSignature = (0, _react.useMemo)(function () {
1290
1238
  return (0, _pivotCompute.createComputeSignature)(props);
1291
- }, [props.rows, props.cols, props.aggregatorName, props.aggregations, props.vals, props.valueFilter, props.sorters, props.rowOrder, props.colOrder, props.rowSorts, props.colSorts]);
1239
+ }, [props.rows, props.cols, props.aggregatorName, props.aggregations, props.vals, props.valueFilter, props.sorters, props.rowOrder, props.colOrder, props.rowSorts, props.colSorts, props.virtualizeRows, props.rendererName, props.tableOptions && props.tableOptions.aggregationDisplayMode]);
1292
1240
 
1293
1241
  // Version the dataset during render instead of inside the compute effect.
1294
1242
  // The effect runs *after* the render, so bumping the version there left one
@@ -1333,11 +1281,20 @@ function PivotTableUI(props) {
1333
1281
  }, [props.data, workerEligible]);
1334
1282
 
1335
1283
  (0, _react.useEffect)(function () {
1284
+ (0, _PivotDataWorker.retainPivotWorker)(instanceIdRef.current);
1336
1285
  return function () {
1337
1286
  unmountedRef.current = true;
1287
+ (0, _PivotDataWorker.releasePivotWorker)(instanceIdRef.current);
1338
1288
  };
1339
1289
  }, []);
1340
1290
 
1291
+ (0, _react.useEffect)(function () {
1292
+ var viewportKey = workerEligible && precomputed && precomputed.data ? precomputed.data.viewportKey : null;
1293
+ return function () {
1294
+ return (0, _PivotDataWorker.releasePivotInWorker)(viewportKey);
1295
+ };
1296
+ }, [precomputed, workerEligible]);
1297
+
1341
1298
  // Forward the `workerDebug` prop to the worker client so the whole
1342
1299
  // worker pipeline can be traced from the browser console.
1343
1300
  (0, _react.useEffect)(function () {
@@ -1387,6 +1344,10 @@ function PivotTableUI(props) {
1387
1344
  // overlay on screen for a result nothing is going to read. `attrValues` and
1388
1345
  // `materializedInput` are handled by the effect above.
1389
1346
  if (!workerEligible) {
1347
+ if (precomputedRef.current) {
1348
+ precomputedRef.current = null;
1349
+ setPrecomputed(null);
1350
+ }
1390
1351
  setIsProcessing(false);
1391
1352
  setResultReady(false);
1392
1353
  setComputeError(null);
@@ -1408,14 +1369,21 @@ function PivotTableUI(props) {
1408
1369
  var timer = setTimeout(function () {
1409
1370
  var requestId = activeRequestRef.current;
1410
1371
  var dataKey = instanceIdRef.current + '-data-' + dataVersionRef.current;
1411
- (0, _PivotDataWorker.computePivotWithFallback)(props.data, dataKey, (0, _pivotCompute.createWorkerConfig)(props)).then(function (result) {
1372
+ (0, _PivotDataWorker.computePivotWithFallback)(props.data, dataKey, (0, _pivotCompute.createWorkerConfig)(props), instanceIdRef.current).then(function (result) {
1412
1373
  if (unmountedRef.current || requestId !== activeRequestRef.current) {
1374
+ (0, _PivotDataWorker.releasePivotInWorker)(result && result.viewportKey);
1413
1375
  return;
1414
1376
  }
1415
1377
  precomputedRef.current = { signature: currentSignature, data: result };
1416
1378
  setPrecomputed(precomputedRef.current);
1417
- setAttrValues(result.attrValues);
1418
- setMaterializedInput(result.materializedInput);
1379
+ if (result.attrValues) {
1380
+ setAttrValues(result.attrValues);
1381
+ }
1382
+ (0, _PivotDataWorker.releaseDatasetInWorker)(dataKey);
1383
+ // The worker received this exact array when the request was staged.
1384
+ // Reusing it avoids structured-cloning the full dataset back to the
1385
+ // main thread with every result.
1386
+ setMaterializedInput(props.data);
1419
1387
  setComputeError(null);
1420
1388
  // Keep the overlay up for one more render: `resultReady` makes the
1421
1389
  // fresh table render underneath, and the layout effect above turns
@@ -1432,7 +1400,7 @@ function PivotTableUI(props) {
1432
1400
  return function () {
1433
1401
  clearTimeout(timer);
1434
1402
  };
1435
- }, [props.data, computeSignature]);
1403
+ }, [props.data, computeSignature, workerEligible]);
1436
1404
 
1437
1405
  // Event handlers are referentially stable (they read the latest props from
1438
1406
  // `propsRef`): a new handler identity on every render would defeat
@@ -1698,9 +1666,9 @@ function PivotTableUI(props) {
1698
1666
  return _react2.default.createElement(DraggableAttribute, {
1699
1667
  name: x,
1700
1668
  key: x,
1701
- attrValues: attrValues[x],
1669
+ attrValues: attrValues[x] || EMPTY_ATTR_VALUES,
1702
1670
  valueFilter: props.valueFilter[x] || {},
1703
- sorter: (0, _Utilities.getSort)(props.sorters, x, attrValues[x]),
1671
+ sorter: (0, _Utilities.getSort)(props.sorters, x, attrValues[x] || EMPTY_ATTR_VALUES),
1704
1672
  menuLimit: props.menuLimit,
1705
1673
  setValuesInFilter: setValuesInFilter,
1706
1674
  addValuesToFilter: addValuesToFilter,
@@ -1989,6 +1957,9 @@ function PivotTableUI(props) {
1989
1957
  outputContent = liveViewElement;
1990
1958
  }
1991
1959
 
1960
+ // Keep the processing layer scoped to the output cell. Rendering it next to
1961
+ // the table made its absolute inset resolve against a much larger ancestor,
1962
+ // which intercepted pointer events across the surrounding application UI.
1992
1963
  var outputCell = _react2.default.createElement(
1993
1964
  'td',
1994
1965
  { className: 'pvtOutput' },
@@ -1997,8 +1968,10 @@ function PivotTableUI(props) {
1997
1968
 
1998
1969
  if (horizUnused) {
1999
1970
  return _react2.default.createElement(
2000
- _react2.default.Fragment,
2001
- null,
1971
+ 'div',
1972
+ {
1973
+ style: { borderRadius: 5, width: 'max-content', height: 'max-content' }
1974
+ },
2002
1975
  showProcessing ? _react2.default.createElement(PivotLoadingOverlay, null) : null,
2003
1976
  _react2.default.createElement(
2004
1977
  'table',
@@ -2032,8 +2005,8 @@ function PivotTableUI(props) {
2032
2005
  }
2033
2006
 
2034
2007
  return _react2.default.createElement(
2035
- _react2.default.Fragment,
2036
- null,
2008
+ 'div',
2009
+ { style: { borderRadius: 5, width: 'max-content', height: 'max-content' } },
2037
2010
  showProcessing ? _react2.default.createElement(PivotLoadingOverlay, null) : null,
2038
2011
  _react2.default.createElement(
2039
2012
  'table',