dtable-statistic 5.0.48-alpha.2 → 5.0.48-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/es/dashboard.js CHANGED
@@ -17,6 +17,7 @@ var _mobileDashboard = _interopRequireDefault(require("./mobile-dashboard"));
17
17
  var _utils = require("./utils");
18
18
  var _commonUtils = require("./utils/common-utils");
19
19
  var _constants = require("./constants");
20
+ var _threadManager = _interopRequireDefault(require("./utils/formula-calc-worker/thread-manager"));
20
21
  require("./locale");
21
22
  require("./assets/css/dashboard.css");
22
23
  require("./assets/css/theme.css");
@@ -123,9 +124,14 @@ class DashBoard extends _react.Component {
123
124
  activeView
124
125
  });
125
126
  };
127
+ this.cancelCalculation = () => {
128
+ _threadManager.default.clearQueue();
129
+ _threadManager.default.terminateWorkers();
130
+ };
126
131
  this.selectDashboard = selectedDashboardIdx => {
127
132
  this.disabledUpdateLayout = true;
128
133
  this.setSelectedDashboardIdx(selectedDashboardIdx);
134
+ this.cancelCalculation();
129
135
  this.setState({
130
136
  selectedDashboardIdx
131
137
  });
@@ -158,6 +164,7 @@ class DashBoard extends _react.Component {
158
164
  });
159
165
  const selectedDashboardIdx = updatedStatistics.length - 1;
160
166
  this.setSelectedDashboardIdx(selectedDashboardIdx);
167
+ this.cancelCalculation();
161
168
  this.updateStatistics({
162
169
  statistics: updatedStatistics,
163
170
  selectedDashboardIdx
@@ -196,6 +203,7 @@ class DashBoard extends _react.Component {
196
203
  }
197
204
  });
198
205
  this.setSelectedDashboardIdx(nextSelectedDashboardIdx);
206
+ this.cancelCalculation();
199
207
  this.updateStatistics({
200
208
  statistics: updatedStatistics,
201
209
  selectedDashboardIdx: nextSelectedDashboardIdx
@@ -375,6 +383,7 @@ class DashBoard extends _react.Component {
375
383
  componentWillUnmount() {
376
384
  this.unsubscribeLocalDtableChanged();
377
385
  this.unsubscribeRemoteDtableChange();
386
+ this.cancelCalculation();
378
387
  }
379
388
  render() {
380
389
  const {
package/es/index.js CHANGED
@@ -5,6 +5,7 @@ var _react = _interopRequireDefault(require("react"));
5
5
  var _dtableStore = require("dtable-store");
6
6
  var _dashboard = _interopRequireDefault(require("./dashboard"));
7
7
  var _calcWithWorker = require("./utils/formula-calc-worker/calc-with-worker");
8
+ var _resultCacheManager = require("./utils/formula-calc-worker/result-cache-manager");
8
9
  class Statistic {
9
10
  static getInitProps() {
10
11
  if (!window || !window.app) {
@@ -41,10 +42,10 @@ class Statistic {
41
42
  userId = null,
42
43
  userDepartmentIdsMap = null
43
44
  } = dtableStore.dtableSettings;
44
- const rows = await (0, _calcWithWorker.calcViewRowsWithWorker)(view, table, this.dtableStore.value, username, userId, userDepartmentIdsMap);
45
+ const rows = await (0, _calcWithWorker.calcViewRowsWithWorker)(view, table, dtableStore.value, username, userId, userDepartmentIdsMap);
45
46
  return rows;
46
47
  }
47
- static async getTableFormulaResults(table, rows) {
48
+ static async getTableFormulaResults(table, rows, value, viewId) {
48
49
  const dtableStore = window.app.dtableStore || {};
49
50
  const {
50
51
  username = null,
@@ -52,7 +53,7 @@ class Statistic {
52
53
  userDepartmentIdsMap = null
53
54
  } = dtableStore.dtableSettings;
54
55
  const formulaColumns = _dtableStore.Views.getFormulaColumnsContainLinks(table);
55
- const res = await (0, _calcWithWorker.calcFormulaResultsWithWorker)(table, rows, this.dtableStore.value, formulaColumns, username, userId, userDepartmentIdsMap);
56
+ const res = await (0, _calcWithWorker.calcFormulaResultsWithWorker)(table, rows, dtableStore.value, formulaColumns, username, userId, userDepartmentIdsMap, viewId);
56
57
  return res;
57
58
  }
58
59
  static updateStatistics(dtableStore, statistics) {
@@ -73,6 +74,9 @@ class Statistic {
73
74
  animation: true
74
75
  };
75
76
  if (!window.app) return;
77
+ _resultCacheManager.viewRowsCacheManager.clear();
78
+ _resultCacheManager.formulaResultsCacheManager.clear();
79
+ (0, _resultCacheManager.clearCachedBase)();
76
80
  window.app.unmountWidget({
77
81
  animation
78
82
  });
@@ -1,51 +1,86 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
3
5
  Object.defineProperty(exports, "__esModule", {
4
6
  value: true
5
7
  });
6
8
  exports.calcFormulaResultsWithWorker = calcFormulaResultsWithWorker;
7
9
  exports.calcViewRowsWithWorker = calcViewRowsWithWorker;
8
- function calcViewRowsWithWorker(view, table, value) {
9
- return new Promise((resolve, reject) => {
10
- const worker = new Worker(new URL('./calc-view-rows-worker.js', import.meta.url), {
11
- type: 'module'
12
- });
13
- worker.postMessage({
14
- view,
15
- table,
16
- value
17
- });
18
- worker.onmessage = function (e) {
19
- resolve(e.data);
20
- worker.terminate();
21
- };
22
- worker.onerror = function (e) {
23
- reject(e);
24
- worker.terminate();
25
- };
10
+ var Comlink = _interopRequireWildcard(require("comlink"));
11
+ var _calc = _interopRequireDefault(require("./calc.worker"));
12
+ var _resultCacheManager = require("./result-cache-manager");
13
+ var _threadManager = _interopRequireDefault(require("./thread-manager"));
14
+ var _lodashEs = require("lodash-es");
15
+ var _hasReactElement = require("../hasReactElement");
16
+ function uuid() {
17
+ return Math.random().toString(36).slice(2, 9);
18
+ }
19
+ async function calcViewRowsWithWorker(view, table, value, username, userId, userDepartmentIdsMap) {
20
+ const key = view._id + table._id;
21
+ const cachedRows = _resultCacheManager.viewRowsCacheManager.get(key);
22
+ if (cachedRows) {
23
+ return cachedRows;
24
+ }
25
+ if (!_resultCacheManager.cachedBase) {
26
+ (0, _resultCacheManager.initCachedBase)(value);
27
+ }
28
+ const clonedTable = (0, _lodashEs.cloneDeep)(table);
29
+ // Symbol can't passed to workers
30
+ clonedTable.columns = clonedTable.columns.map(c => {
31
+ delete c.editor;
32
+ delete c.formatter;
33
+ return c;
26
34
  });
35
+ (0, _hasReactElement.containsReactElementSymbol)(_resultCacheManager.cachedBase);
36
+ (0, _hasReactElement.containsReactElementSymbol)(clonedTable);
37
+ const workerId = uuid();
38
+ let worker;
39
+ try {
40
+ worker = await _threadManager.default.applyThread(workerId, _calc.default);
41
+ } catch (e) {
42
+ return [];
43
+ }
44
+ const calcWorker = Comlink.wrap(worker);
45
+ const rows = await calcWorker.getViewRows(view, clonedTable, _resultCacheManager.cachedBase, username, userId, userDepartmentIdsMap);
46
+ _resultCacheManager.viewRowsCacheManager.set(key, rows);
47
+ _threadManager.default.removeThread(workerId);
48
+ return rows;
27
49
  }
28
- function calcFormulaResultsWithWorker(table, rows, value, formulaColumns, username, userId, userDepartmentIdsMap) {
29
- return new Promise((resolve, reject) => {
30
- const worker = new Worker(new URL('./calc-formula-result-worker.js', import.meta.url), {
31
- type: 'module'
32
- });
33
- worker.postMessage({
34
- table,
35
- rows,
36
- value,
37
- formulaColumns,
38
- username,
39
- userId,
40
- userDepartmentIdsMap
41
- });
42
- worker.onmessage = function (e) {
43
- resolve(e.data);
44
- worker.terminate();
45
- };
46
- worker.onerror = function (e) {
47
- reject(e);
48
- worker.terminate();
49
- };
50
+ async function calcFormulaResultsWithWorker(table, rows, value, formulaColumns, username, userId, userDepartmentIdsMap, viewId) {
51
+ const key = viewId + table._id;
52
+ const cachedResults = _resultCacheManager.formulaResultsCacheManager.get(key);
53
+ if (cachedResults) {
54
+ return cachedResults;
55
+ }
56
+ if (!_resultCacheManager.cachedBase) {
57
+ (0, _resultCacheManager.initCachedBase)(value);
58
+ }
59
+ const clonedTable = (0, _lodashEs.cloneDeep)(table);
60
+ // Symbol can't passed to workers
61
+ clonedTable.columns = clonedTable.columns.map(c => {
62
+ delete c.editor;
63
+ delete c.formatter;
64
+ return c;
65
+ });
66
+ let clonedFormulaColumns = (0, _lodashEs.cloneDeep)(formulaColumns);
67
+ clonedFormulaColumns = clonedFormulaColumns.map(c => {
68
+ delete c.editor;
69
+ delete c.formatter;
70
+ return c;
50
71
  });
72
+ (0, _hasReactElement.containsReactElementSymbol)(_resultCacheManager.cachedBase);
73
+ (0, _hasReactElement.containsReactElementSymbol)(clonedTable);
74
+ const workerId = uuid();
75
+ let worker;
76
+ try {
77
+ worker = await _threadManager.default.applyThread(workerId, _calc.default);
78
+ } catch (e) {
79
+ return [];
80
+ }
81
+ const calcWorker = Comlink.wrap(worker);
82
+ const results = await calcWorker.getTableFormulaResults(clonedTable, rows, _resultCacheManager.cachedBase, clonedFormulaColumns, username, userId, userDepartmentIdsMap);
83
+ _resultCacheManager.formulaResultsCacheManager.set(key, results);
84
+ _threadManager.default.removeThread(workerId);
85
+ return results;
51
86
  }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ var Comlink = _interopRequireWildcard(require("comlink"));
5
+ var _dtableStore = require("dtable-store");
6
+ // async function calc(callback) {
7
+ // const res = await callback();
8
+ // return res;
9
+ // }
10
+ // Comlink.expose(calc);
11
+ const workerFunctions = {
12
+ async getViewRows(view, table, value, username, userId, userDepartmentIdsMap) {
13
+ return _dtableStore.Views.getViewRows(view, table, value, username, userId, userDepartmentIdsMap);
14
+ },
15
+ async getTableFormulaResults(table, rows, value, formulaColumns, username, userId, userDepartmentIdsMap) {
16
+ return _dtableStore.Views.getTableFormulaResults(table, rows, value, formulaColumns, {
17
+ username,
18
+ userId,
19
+ userDepartmentIdsMap
20
+ });
21
+ }
22
+ };
23
+ Comlink.expose(workerFunctions);
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.cachedBase = void 0;
7
+ exports.clearCachedBase = clearCachedBase;
8
+ exports.formulaResultsCacheManager = void 0;
9
+ exports.initCachedBase = initCachedBase;
10
+ exports.viewRowsCacheManager = void 0;
11
+ var _lodashEs = require("lodash-es");
12
+ class ResultCacheManager {
13
+ constructor() {
14
+ this.cache = new Map();
15
+ }
16
+ get(key) {
17
+ return this.cache.get(key);
18
+ }
19
+ set(key, value) {
20
+ this.cache.set(key, value);
21
+ }
22
+ clear() {
23
+ this.cache.clear();
24
+ }
25
+ }
26
+ const viewRowsCacheManager = exports.viewRowsCacheManager = new ResultCacheManager();
27
+ const formulaResultsCacheManager = exports.formulaResultsCacheManager = new ResultCacheManager();
28
+ let cachedBase = exports.cachedBase = null;
29
+ function initCachedBase(value) {
30
+ // don't clone rows cause they are really big
31
+ const tableIdRowMap = {};
32
+ value.tables.forEach(t => {
33
+ tableIdRowMap[t._id] = t === null || t === void 0 ? void 0 : t.rows;
34
+ t.rows && delete t.rows;
35
+ });
36
+ const clonedBase = (0, _lodashEs.cloneDeep)(value);
37
+ clonedBase.tables.forEach(t => {
38
+ // delete symbols
39
+ t.columns = t.columns.map(c => {
40
+ delete c.editor;
41
+ delete c.formatter;
42
+ return c;
43
+ });
44
+ t.rows = tableIdRowMap[t._id];
45
+ });
46
+ value.tables.forEach(t => {
47
+ t.rows = tableIdRowMap[t._id];
48
+ });
49
+ exports.cachedBase = cachedBase = clonedBase;
50
+ }
51
+ function clearCachedBase() {
52
+ exports.cachedBase = cachedBase = null;
53
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ class ThreadManager {
8
+ constructor(threadCount) {
9
+ const supportedThreads = navigator.hardwareConcurrency;
10
+ // prevent the browser from freezing by leaving 3 threads for the main thread
11
+ if (typeof supportedThreads === 'number' && supportedThreads - 3 > 0) {
12
+ this.threadCount = supportedThreads - 3;
13
+ } else {
14
+ this.threadCount = 2;
15
+ }
16
+ this.threadList = [];
17
+ this.queue = [];
18
+ }
19
+ async applyThread(id, workerConstructor) {
20
+ return new Promise((resolve, reject) => {
21
+ if (this.threadList.length < this.threadCount) {
22
+ const worker = new workerConstructor();
23
+ worker.id = id;
24
+ this.threadList.push(worker);
25
+ resolve(worker);
26
+ } else {
27
+ this.queue.push({
28
+ id,
29
+ emitter: resolve,
30
+ rejector: reject,
31
+ workerConstructor
32
+ });
33
+ }
34
+ });
35
+ }
36
+ removeThread(id) {
37
+ const index = this.threadList.findIndex(worker => worker.id === id);
38
+ if (index > -1) {
39
+ this.threadList[index] && this.threadList[index].terminate();
40
+ this.threadList.splice(index, 1);
41
+ }
42
+ if (this.queue.length > 0) {
43
+ const {
44
+ id,
45
+ emitter,
46
+ workerConstructor
47
+ } = this.queue.shift();
48
+ const worker = new workerConstructor();
49
+ worker.id = id;
50
+ this.threadList.push(worker);
51
+ emitter(worker);
52
+ }
53
+ }
54
+ clearQueue() {
55
+ this.queue.forEach(_ref => {
56
+ let {
57
+ rejector
58
+ } = _ref;
59
+ return rejector();
60
+ });
61
+ this.queue = [];
62
+ }
63
+ terminateWorkers() {
64
+ this.threadList.forEach(item => {
65
+ item && item.terminate();
66
+ });
67
+ this.threadList = [];
68
+ }
69
+ }
70
+ const threadManager = new ThreadManager();
71
+ var _default = exports.default = threadManager;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.containsReactElementSymbol = containsReactElementSymbol;
7
+ const REACT_ELEMENT_TYPE = Symbol.for('react.element');
8
+ function containsReactElementSymbol(obj) {
9
+ let parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
10
+ if (obj === null || typeof obj !== 'object') {
11
+ return false;
12
+ }
13
+
14
+ // Check if the current object is a React element
15
+ if (obj.$$typeof === REACT_ELEMENT_TYPE) {
16
+ console.log('Parent object containing Symbol(react.element):', parent);
17
+ return true;
18
+ }
19
+
20
+ // Recursively check all properties of the object
21
+ for (let key in obj) {
22
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
23
+ if (containsReactElementSymbol(obj[key], obj)) {
24
+ return true;
25
+ }
26
+ }
27
+ }
28
+
29
+ // Check symbol properties as well
30
+ const symbolProperties = Object.getOwnPropertySymbols(obj);
31
+ for (let symbol of symbolProperties) {
32
+ if (containsReactElementSymbol(obj[symbol], obj)) {
33
+ return true;
34
+ }
35
+ }
36
+ return false;
37
+ }
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dtable-statistic",
3
- "version": "5.0.48-alpha.2",
3
+ "version": "5.0.48-alpha.20",
4
4
  "description": "statistics",
5
5
  "main": "dist/dtable-statistic.js",
6
6
  "author": "seafile",
@@ -18,8 +18,7 @@
18
18
  "react-grid-layout": "^1.2.5",
19
19
  "react-intl-universal": "^2.4.8",
20
20
  "reactstrap": "8.9.0",
21
- "sea-chart": "~0.0.94"
22
-
21
+ "sea-chart": "^0.0.95-alpha.7"
23
22
  },
24
23
  "peerDependencies": {
25
24
  "dtable-ui-component": "~5.0.*",
@@ -53,7 +52,7 @@
53
52
  "css-minimizer-webpack-plugin": "^3.2.0",
54
53
  "dotenv": "^10.0.0",
55
54
  "dotenv-expand": "^5.1.0",
56
- "dtable-store": "5.0.8",
55
+ "dtable-store": "4.3.6",
57
56
  "dtable-ui-component": "~5.0.11",
58
57
  "dtable-utils": "5.0.0",
59
58
  "dtable-web-api": "^5.0.3",
@@ -1,21 +0,0 @@
1
- "use strict";
2
-
3
- var _dtableStore = require("dtable-store");
4
- /* eslint-disable no-restricted-globals */
5
- self.onmessage = function (e) {
6
- const {
7
- table,
8
- rows,
9
- value,
10
- formulaColumns,
11
- username,
12
- userId,
13
- userDepartmentIdsMap
14
- } = e.data;
15
- const res = _dtableStore.Views.getTableFormulaResults(table, rows, value, formulaColumns, {
16
- username,
17
- userId,
18
- userDepartmentIdsMap
19
- });
20
- self.postMessage(res);
21
- };
@@ -1,16 +0,0 @@
1
- "use strict";
2
-
3
- var _dtableStore = require("dtable-store");
4
- /* eslint-disable no-restricted-globals */
5
- self.onmessage = function (e) {
6
- const {
7
- view,
8
- table,
9
- value,
10
- username,
11
- userId,
12
- userDepartmentIdsMap
13
- } = e.data;
14
- const rows = _dtableStore.Views.getViewRows(view, table, value, username, userId, userDepartmentIdsMap);
15
- self.postMessage(rows);
16
- };