expensify-common 2.0.188 → 2.0.190
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/dist/Logger.js +11 -1
- package/dist/esm/API.d.ts +11 -0
- package/dist/esm/API.js +786 -0
- package/dist/esm/APIDeferred.d.ts +7 -0
- package/dist/esm/APIDeferred.js +216 -0
- package/dist/esm/BrowserDetect.d.ts +19 -0
- package/dist/esm/BrowserDetect.js +105 -0
- package/dist/esm/CLI.js +37 -29
- package/dist/esm/CONST.d.ts +1727 -0
- package/dist/esm/CONST.js +1847 -0
- package/dist/esm/Cookie.d.ts +68 -0
- package/dist/esm/Cookie.js +159 -0
- package/dist/esm/CredentialsWrapper.d.ts +32 -0
- package/dist/esm/CredentialsWrapper.js +46 -0
- package/dist/esm/Device.d.ts +8 -0
- package/dist/esm/Device.js +24 -0
- package/dist/esm/ExpenseRule.d.ts +39 -0
- package/dist/esm/ExpenseRule.js +77 -0
- package/dist/esm/ExpensiMark.d.ts +197 -0
- package/dist/esm/ExpensiMark.js +1374 -0
- package/dist/esm/Func.d.ts +40 -0
- package/dist/esm/Func.js +69 -0
- package/dist/esm/Log.d.ts +3 -0
- package/dist/esm/Log.js +35 -0
- package/dist/esm/Logger.d.ts +82 -0
- package/dist/esm/Logger.js +148 -0
- package/dist/esm/Network.d.ts +6 -0
- package/dist/esm/Network.js +168 -0
- package/dist/esm/Num.d.ts +95 -0
- package/dist/esm/Num.js +190 -0
- package/dist/esm/PageEvent.d.ts +25 -0
- package/dist/esm/PageEvent.js +22 -0
- package/dist/esm/PubSub.d.ts +2 -0
- package/dist/esm/PubSub.js +111 -0
- package/dist/esm/ReportHistoryStore.d.ts +8 -0
- package/dist/esm/ReportHistoryStore.js +199 -0
- package/dist/esm/SafeString.js +2 -2
- package/dist/esm/Templates.d.ts +58 -0
- package/dist/esm/Templates.js +196 -0
- package/dist/esm/Url.d.ts +10 -0
- package/dist/esm/Url.js +15 -0
- package/dist/esm/components/CopyText.d.ts +45 -0
- package/dist/esm/components/CopyText.js +56 -0
- package/dist/esm/components/StepProgressBar.d.ts +26 -0
- package/dist/esm/components/StepProgressBar.js +40 -0
- package/dist/esm/components/form/element/combobox.d.ts +231 -0
- package/dist/esm/components/form/element/combobox.js +812 -0
- package/dist/esm/components/form/element/dropdown.d.ts +35 -0
- package/dist/esm/components/form/element/dropdown.js +61 -0
- package/dist/esm/components/form/element/dropdownItem.d.ts +55 -0
- package/dist/esm/components/form/element/dropdownItem.js +113 -0
- package/dist/esm/components/form/element/onOffSwitch.d.ts +94 -0
- package/dist/esm/components/form/element/onOffSwitch.js +167 -0
- package/dist/esm/components/form/element/switch.d.ts +58 -0
- package/dist/esm/components/form/element/switch.js +98 -0
- package/dist/esm/fastMerge.d.ts +9 -0
- package/dist/esm/fastMerge.js +58 -0
- package/dist/esm/index.d.ts +22 -0
- package/dist/esm/index.js +22 -0
- package/dist/esm/jquery.expensifyIframify.d.ts +9 -0
- package/dist/esm/jquery.expensifyIframify.js +397 -0
- package/dist/esm/md5.d.ts +2 -0
- package/dist/esm/md5.js +170 -0
- package/dist/esm/mixins/PubSub.d.ts +20 -0
- package/dist/esm/mixins/PubSub.js +47 -0
- package/dist/esm/mixins/extraClasses.d.ts +8 -0
- package/dist/esm/mixins/extraClasses.js +37 -0
- package/dist/esm/mixins/validationClasses.d.ts +12 -0
- package/dist/esm/mixins/validationClasses.js +30 -0
- package/dist/esm/str.d.ts +604 -0
- package/dist/esm/str.js +1036 -0
- package/dist/esm/tlds.d.ts +2 -0
- package/dist/esm/tlds.js +2 -0
- package/dist/esm/utils.d.ts +30 -0
- package/dist/esm/utils.js +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -1
- package/package.json +221 -4
package/dist/esm/Num.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import Str from './str';
|
|
2
|
+
export default {
|
|
3
|
+
/**
|
|
4
|
+
* Converts an exponential number into it's non-exponential string equivalent
|
|
5
|
+
*
|
|
6
|
+
* @param {Number} num
|
|
7
|
+
*
|
|
8
|
+
* @returns {String}
|
|
9
|
+
*/
|
|
10
|
+
notExponential(num) {
|
|
11
|
+
const numStr = num.toString();
|
|
12
|
+
// If this number isn't exponential already, just return it.
|
|
13
|
+
if (numStr.indexOf('e') === -1) {
|
|
14
|
+
return num;
|
|
15
|
+
}
|
|
16
|
+
const numArr = numStr.split(/e\+/);
|
|
17
|
+
let exponent = parseInt(numArr[1], 10);
|
|
18
|
+
let value = parseFloat(numArr[0]);
|
|
19
|
+
// Convert the number into the largest possible non-exponent.
|
|
20
|
+
exponent -= 20;
|
|
21
|
+
value *= Math.pow(10, 20);
|
|
22
|
+
// Now we make it into a string and start appending '0's
|
|
23
|
+
value = value.toString();
|
|
24
|
+
while (exponent--) {
|
|
25
|
+
value += '0';
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* Format a number, similar to PHP's number_format.
|
|
31
|
+
*
|
|
32
|
+
* @param {Number} _a The number you want to format
|
|
33
|
+
* @param {Number} [b="0"] The number of decimal places you want
|
|
34
|
+
* @param {String} [_c=","] The decimal separator
|
|
35
|
+
* @param {String} [d="."] The thousands separator
|
|
36
|
+
*
|
|
37
|
+
* @todo should be camelCase / needs refactor
|
|
38
|
+
* @returns {String}
|
|
39
|
+
*/
|
|
40
|
+
number_format(_a, b = 0, _c = '.', d = ',') {
|
|
41
|
+
let sign = '';
|
|
42
|
+
let a = _a;
|
|
43
|
+
let c = _c;
|
|
44
|
+
let e = null;
|
|
45
|
+
let f = null;
|
|
46
|
+
let g = null;
|
|
47
|
+
let h = null;
|
|
48
|
+
let i = null;
|
|
49
|
+
let j = null;
|
|
50
|
+
const multiplier = Math.pow(10, b);
|
|
51
|
+
a = Math.round(a * multiplier) / multiplier;
|
|
52
|
+
if (a < 0) {
|
|
53
|
+
a *= -1;
|
|
54
|
+
sign = '-';
|
|
55
|
+
}
|
|
56
|
+
e = String(this.notExponential(a));
|
|
57
|
+
f = e.split('.');
|
|
58
|
+
if (!f[0]) {
|
|
59
|
+
f[0] = '0';
|
|
60
|
+
}
|
|
61
|
+
if (!f[1]) {
|
|
62
|
+
f[1] = '';
|
|
63
|
+
}
|
|
64
|
+
if (f[1].length < b) {
|
|
65
|
+
g = f[1];
|
|
66
|
+
for (i = f[1].length + 1; i <= b; i++) {
|
|
67
|
+
g += '0';
|
|
68
|
+
}
|
|
69
|
+
f[1] = g;
|
|
70
|
+
}
|
|
71
|
+
if (d !== '' && f[0].length > 3) {
|
|
72
|
+
h = f[0];
|
|
73
|
+
f[0] = '';
|
|
74
|
+
for (j = 3; j < h.length; j += 3) {
|
|
75
|
+
const sliceStart = h.length - j;
|
|
76
|
+
i = h.slice(sliceStart, sliceStart + 3);
|
|
77
|
+
f[0] = `${d}${i}${f[0]}`;
|
|
78
|
+
}
|
|
79
|
+
j = h.substr(0, h.length % 3 === 0 ? 3 : h.length % 3);
|
|
80
|
+
f[0] = j + f[0];
|
|
81
|
+
}
|
|
82
|
+
c = b <= 0 ? '' : c;
|
|
83
|
+
return `${sign}${f[0]}${c}${f[1]}`;
|
|
84
|
+
},
|
|
85
|
+
generateRandom6DigitID() {
|
|
86
|
+
return Math.floor(Math.random() * 900000) + 100000; // 100000 - 999999
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Converts a number to base 26 (using capital english letters as digits).
|
|
90
|
+
*
|
|
91
|
+
* @param {Number} num The number to convert to base 26.
|
|
92
|
+
*
|
|
93
|
+
* @returns {String} The number, converted to base 26.
|
|
94
|
+
*/
|
|
95
|
+
toBase26LetterCode(num) {
|
|
96
|
+
const base26Digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
97
|
+
const outputDigits = [];
|
|
98
|
+
for (let i = num; i >= 0; i = Math.floor(i / 26) - 1) {
|
|
99
|
+
outputDigits.push(base26Digits.charAt(i % 26));
|
|
100
|
+
}
|
|
101
|
+
return outputDigits.reverse().join('');
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* Check if a number is finite and not NaN. i.e.
|
|
105
|
+
*
|
|
106
|
+
* @param {number} number The number to test
|
|
107
|
+
*
|
|
108
|
+
* @returns {Boolean} true if the number is finite and not NaN.
|
|
109
|
+
*/
|
|
110
|
+
isFiniteNumber(number) {
|
|
111
|
+
return typeof number === 'number' && Number.isFinite(number) && !Number.isNaN(number);
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* Truncates the given number to the given precision.
|
|
115
|
+
*
|
|
116
|
+
* @param {number} number the number to truncate.
|
|
117
|
+
* @param {number} decimals the number of decimals to keep.
|
|
118
|
+
*
|
|
119
|
+
* @returns {number} the truncated number.
|
|
120
|
+
*/
|
|
121
|
+
toPrecision(number, decimals) {
|
|
122
|
+
const numeral = Math.pow(10, decimals);
|
|
123
|
+
return Math.round(number * numeral) / numeral;
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* Check if a number is between 2 numbers, including them.
|
|
127
|
+
*
|
|
128
|
+
* @param {number} number to check
|
|
129
|
+
* @param {number} a the 1st limit
|
|
130
|
+
* @param {number} b the 2nd limit
|
|
131
|
+
*
|
|
132
|
+
* @returns {boolean}
|
|
133
|
+
*/
|
|
134
|
+
isNumberBetween(number, a, b) {
|
|
135
|
+
return number >= Math.min(a, b) && number <= Math.max(a, b);
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Returns how many decimals to display (used for currencies).
|
|
139
|
+
*
|
|
140
|
+
* @param {Number} rate
|
|
141
|
+
* @returns {Number}
|
|
142
|
+
*/
|
|
143
|
+
getDisplayDecimals(rate) {
|
|
144
|
+
if (rate % 1 === 0) {
|
|
145
|
+
return 2;
|
|
146
|
+
}
|
|
147
|
+
if ((rate * 10) % 1 === 0) {
|
|
148
|
+
return 3;
|
|
149
|
+
}
|
|
150
|
+
return 4;
|
|
151
|
+
},
|
|
152
|
+
tax: {
|
|
153
|
+
/**
|
|
154
|
+
* Calculate the pre-tax, or net amount
|
|
155
|
+
*
|
|
156
|
+
* @param {Number} total The total to calculate from, in negative cents
|
|
157
|
+
* @param {UserDefinedField} taxUDF The tax UDF
|
|
158
|
+
*
|
|
159
|
+
* @returns {number} The pre-tax amount, in negative cents
|
|
160
|
+
*/
|
|
161
|
+
calculatePreTaxAmount(total, taxUDF) {
|
|
162
|
+
return total - taxUDF.getTaxAmount(total);
|
|
163
|
+
},
|
|
164
|
+
/**
|
|
165
|
+
* Calculate the tax amount from the total.
|
|
166
|
+
*
|
|
167
|
+
* @param {Number} total The total to calculate from
|
|
168
|
+
* @param {String} percentage The percentage, as a string, e.g. '20%'
|
|
169
|
+
*
|
|
170
|
+
* @returns {number} The amount of tax
|
|
171
|
+
*/
|
|
172
|
+
calculateTaxFromPercentage(total, percentage) {
|
|
173
|
+
const percentageAsDecimal = Str.percentageStringToNumber(percentage) / 100;
|
|
174
|
+
const divisor = percentage ? percentageAsDecimal + 1 : 1;
|
|
175
|
+
return this.calculateTaxFromDivisor(total, divisor);
|
|
176
|
+
},
|
|
177
|
+
/**
|
|
178
|
+
* Calculate the tax amount from a divisor.
|
|
179
|
+
*
|
|
180
|
+
* @param {Number} total The total to calculate from
|
|
181
|
+
* @param {Number} divisor The divisor (0.1 = 10%)
|
|
182
|
+
*
|
|
183
|
+
* @returns {number} The amount of tax
|
|
184
|
+
*/
|
|
185
|
+
calculateTaxFromDivisor(total, divisor) {
|
|
186
|
+
const amountExcludingTax = total / divisor;
|
|
187
|
+
return parseInt(Math.round(total - amountExcludingTax), 10);
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event object used by page to do internal logic.
|
|
3
|
+
* Used with the method pageSubscribe and pageUnSubscribe
|
|
4
|
+
* of the PubSub for automatic clean up of pages events
|
|
5
|
+
*
|
|
6
|
+
* @param {String} eventName Name of the event to listen to
|
|
7
|
+
* @param {Function} callback Function to fire
|
|
8
|
+
* @class
|
|
9
|
+
*/
|
|
10
|
+
export default function _default(eventName: string, callback: Function): {
|
|
11
|
+
subscribe(scope: any): void;
|
|
12
|
+
unsubscribe(): void;
|
|
13
|
+
};
|
|
14
|
+
export default class _default {
|
|
15
|
+
/**
|
|
16
|
+
* Event object used by page to do internal logic.
|
|
17
|
+
* Used with the method pageSubscribe and pageUnSubscribe
|
|
18
|
+
* of the PubSub for automatic clean up of pages events
|
|
19
|
+
*
|
|
20
|
+
* @param {String} eventName Name of the event to listen to
|
|
21
|
+
* @param {Function} callback Function to fire
|
|
22
|
+
* @class
|
|
23
|
+
*/
|
|
24
|
+
constructor(eventName: string, callback: Function);
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import PubSub from './PubSub';
|
|
2
|
+
/**
|
|
3
|
+
* Event object used by page to do internal logic.
|
|
4
|
+
* Used with the method pageSubscribe and pageUnSubscribe
|
|
5
|
+
* of the PubSub for automatic clean up of pages events
|
|
6
|
+
*
|
|
7
|
+
* @param {String} eventName Name of the event to listen to
|
|
8
|
+
* @param {Function} callback Function to fire
|
|
9
|
+
* @class
|
|
10
|
+
*/
|
|
11
|
+
export default function (eventName, callback) {
|
|
12
|
+
let id = null;
|
|
13
|
+
return {
|
|
14
|
+
subscribe(scope) {
|
|
15
|
+
id = PubSub.subscribe(eventName, callback, scope);
|
|
16
|
+
},
|
|
17
|
+
unsubscribe() {
|
|
18
|
+
PubSub.unsubscribe(id);
|
|
19
|
+
id = null;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import has from 'lodash/has';
|
|
2
|
+
import once from 'lodash/once';
|
|
3
|
+
import Log from './Log';
|
|
4
|
+
import * as Utils from './utils';
|
|
5
|
+
/**
|
|
6
|
+
* PubSub
|
|
7
|
+
*
|
|
8
|
+
* A simple publisher subscriber system for async / decouple/ cross module communication
|
|
9
|
+
*/
|
|
10
|
+
const eventMap = {};
|
|
11
|
+
// Used to generate the uniq id of the event
|
|
12
|
+
let counter = 0;
|
|
13
|
+
/**
|
|
14
|
+
* Create a unique ID for each event subscriber
|
|
15
|
+
* @param {String} eventName Name of the event to listen to
|
|
16
|
+
* @returns {String} unique ID
|
|
17
|
+
*/
|
|
18
|
+
const generateID = (eventName) => {
|
|
19
|
+
counter++;
|
|
20
|
+
return `${eventName}@#@${counter}`;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Find the name of the event from the ID
|
|
24
|
+
* @param {string} eventID
|
|
25
|
+
* @returns {String}
|
|
26
|
+
*/
|
|
27
|
+
const extractEventName = (eventID = '') => eventID.substring(0, eventID.indexOf('@#@'));
|
|
28
|
+
const PubSubModule = {
|
|
29
|
+
ERROR: 'ev_error',
|
|
30
|
+
/**
|
|
31
|
+
* Publish an event
|
|
32
|
+
*
|
|
33
|
+
* @param {String} eventName Name of the event to fire
|
|
34
|
+
* @param {Object} [param] Parameters to send with the event, send to the callback
|
|
35
|
+
* @returns {PubSub}
|
|
36
|
+
*/
|
|
37
|
+
publish(eventName, param = {}) {
|
|
38
|
+
if (eventMap[eventName] === undefined) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const eventIDs = Object.keys(eventMap[eventName]);
|
|
42
|
+
if (eventName === this.ERROR) {
|
|
43
|
+
// Doing the split slice 2 because the 1st element of the stacktrace will always be from here (PubSub.publish)
|
|
44
|
+
// When debugging, we just need to know who called PubSub.publish (so, all next elements in the stack)
|
|
45
|
+
Log.hmmm('Error published', 0, { tplt: param.tplt, stackTrace: new Error().stack.split(' at ').slice(2) });
|
|
46
|
+
}
|
|
47
|
+
for (const eventID of eventIDs) {
|
|
48
|
+
const subscriber = eventMap[eventName][eventID];
|
|
49
|
+
if (subscriber) {
|
|
50
|
+
subscriber.callback.call(subscriber.scope, param);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return this;
|
|
54
|
+
},
|
|
55
|
+
/**
|
|
56
|
+
* Subscribes to an event and triggers the callback only once with the given scope
|
|
57
|
+
*
|
|
58
|
+
* @param {String} eventName
|
|
59
|
+
* @param {Function} callback
|
|
60
|
+
* @param {Object} [optionalScope]
|
|
61
|
+
* @returns {String}
|
|
62
|
+
*/
|
|
63
|
+
once(eventName, callback, optionalScope) {
|
|
64
|
+
const scope = Utils.isObject(optionalScope) && optionalScope !== null ? optionalScope : window;
|
|
65
|
+
const functionToCallOnce = once((...args) => callback.apply(scope, args));
|
|
66
|
+
return this.subscribe(eventName, functionToCallOnce);
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* Listen to an event and call the callback when it is done.
|
|
70
|
+
* Order of callback call is not guaranteed
|
|
71
|
+
*
|
|
72
|
+
* "PUBLIC" event ( aka for views ) are available in lib/constant.js
|
|
73
|
+
* "PRIVATE" event should be used only by system modules
|
|
74
|
+
*
|
|
75
|
+
* @param {String} eventName Name of the event to listen
|
|
76
|
+
* @param {Function} optionalCallback Callback function to call when event occur
|
|
77
|
+
* @param {Object} optionalScope
|
|
78
|
+
* @returns {String} event identifier that should be used to unsubscribe
|
|
79
|
+
*/
|
|
80
|
+
subscribe(eventName, optionalCallback, optionalScope) {
|
|
81
|
+
if (!eventName) {
|
|
82
|
+
throw new Error('Attempted to subscribe to undefined event');
|
|
83
|
+
}
|
|
84
|
+
const callback = Utils.isFunction(optionalCallback) ? optionalCallback : () => { };
|
|
85
|
+
const scope = Utils.isObject(optionalScope) && optionalScope !== null ? optionalScope : window;
|
|
86
|
+
const eventID = generateID(eventName);
|
|
87
|
+
if (eventMap[eventName] === undefined) {
|
|
88
|
+
eventMap[eventName] = {};
|
|
89
|
+
}
|
|
90
|
+
eventMap[eventName][eventID] = {
|
|
91
|
+
callback,
|
|
92
|
+
scope,
|
|
93
|
+
};
|
|
94
|
+
return eventID;
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* Remove a subscriber
|
|
98
|
+
*
|
|
99
|
+
* @param {String} bindID The id of the element to delete
|
|
100
|
+
*/
|
|
101
|
+
unsubscribe(bindID) {
|
|
102
|
+
const IDs = Array.isArray(bindID) ? bindID : [bindID];
|
|
103
|
+
for (const id of IDs) {
|
|
104
|
+
const eventName = extractEventName(id);
|
|
105
|
+
if (has(eventMap, `${eventName}.${id}`)) {
|
|
106
|
+
delete eventMap[eventName][id];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
export default Utils.isWindowAvailable() && window.PubSub ? window.PubSub : PubSubModule;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Deferred } from 'simply-deferred';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a report history store with platform-specific API and PubSub implementations.
|
|
4
|
+
*
|
|
5
|
+
* @param {Object} API
|
|
6
|
+
* @param {Object} PubSub
|
|
7
|
+
* @returns {Object}
|
|
8
|
+
*/
|
|
9
|
+
export default function ReportHistoryStore(API, PubSub) {
|
|
10
|
+
if (!API) {
|
|
11
|
+
throw new Error('Cannot instantiate ReportHistoryStore without API');
|
|
12
|
+
}
|
|
13
|
+
const store = {
|
|
14
|
+
API,
|
|
15
|
+
cache: {},
|
|
16
|
+
PubSub,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Filters out actions we never want to display on web or mobile.
|
|
20
|
+
*
|
|
21
|
+
* @param {Object[]} historyItems
|
|
22
|
+
* @returns {Object[]}
|
|
23
|
+
*/
|
|
24
|
+
const filterHiddenActions = (historyItems) => historyItems.filter((historyItem) => historyItem.shouldShow);
|
|
25
|
+
/**
|
|
26
|
+
* Merges history items into the cache and creates it if it doesn't yet exist.
|
|
27
|
+
*
|
|
28
|
+
* @param {Number} reportID
|
|
29
|
+
* @param {Object[]} newHistory
|
|
30
|
+
*/
|
|
31
|
+
function mergeItems(reportID, newHistory) {
|
|
32
|
+
if (newHistory.length === 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const newCache = newHistory.reverse().reduce((prev, curr) => {
|
|
36
|
+
if (!prev.some((item) => item.sequenceNumber === curr.sequenceNumber)) {
|
|
37
|
+
prev.unshift(curr);
|
|
38
|
+
}
|
|
39
|
+
return prev;
|
|
40
|
+
}, store.cache[reportID] || []);
|
|
41
|
+
store.cache[reportID] = newCache.sort((a, b) => b.sequenceNumber - a.sequenceNumber);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Merges history items into the cache and creates it if it doesn't yet exist.
|
|
45
|
+
*
|
|
46
|
+
* @param {Number} reportID
|
|
47
|
+
* @param {Object[]} newHistory
|
|
48
|
+
*/
|
|
49
|
+
function mergeHistoryByTimestamp(reportID, newHistory) {
|
|
50
|
+
if (newHistory.length === 0) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const newCache = newHistory.reverse().reduce((prev, curr) => {
|
|
54
|
+
if (!prev.some((item) => item.reportActionTimestamp === curr.reportActionTimestamp)) {
|
|
55
|
+
prev.unshift(curr);
|
|
56
|
+
}
|
|
57
|
+
return prev;
|
|
58
|
+
}, store.cache[reportID] || []);
|
|
59
|
+
store.cache[reportID] = newCache.sort((a, b) => b.reportActionTimestamp - a.reportActionTimestamp);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Merges history items by reportActionID into the cache and creates it if it doesn't yet exist.
|
|
63
|
+
*
|
|
64
|
+
* @param {Number} reportID
|
|
65
|
+
* @param {Object[]} newHistory
|
|
66
|
+
*/
|
|
67
|
+
function mergeHistoryByReportActionID(reportID, newHistory) {
|
|
68
|
+
if (newHistory.length === 0) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const newCache = newHistory.reverse().reduce((prev, curr) => {
|
|
72
|
+
if (!prev.some((item) => item.reportActionID === curr.reportActionID)) {
|
|
73
|
+
prev.unshift(curr);
|
|
74
|
+
}
|
|
75
|
+
return prev;
|
|
76
|
+
}, store.cache[reportID] || []);
|
|
77
|
+
store.cache[reportID] = newCache.sort((a, b) => b.reportActionTimestamp - a.reportActionTimestamp);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Gets the history.
|
|
81
|
+
*
|
|
82
|
+
* @param {Number} reportID
|
|
83
|
+
* @param {Boolean} ignoreCache
|
|
84
|
+
* @returns {Deferred}
|
|
85
|
+
*/
|
|
86
|
+
function get(reportID, ignoreCache) {
|
|
87
|
+
const promise = new Deferred();
|
|
88
|
+
if (ignoreCache) {
|
|
89
|
+
delete store.cache[reportID];
|
|
90
|
+
}
|
|
91
|
+
const cachedHistory = store.cache[reportID] || [];
|
|
92
|
+
const firstHistoryItem = cachedHistory[0] || {};
|
|
93
|
+
store.API.Report_GetHistory({
|
|
94
|
+
reportID,
|
|
95
|
+
offset: firstHistoryItem.sequenceNumber || 0,
|
|
96
|
+
})
|
|
97
|
+
.done((recentHistory) => {
|
|
98
|
+
mergeItems(reportID, recentHistory);
|
|
99
|
+
promise.resolve(store.cache[reportID]);
|
|
100
|
+
})
|
|
101
|
+
.fail(promise.reject);
|
|
102
|
+
return promise;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Gets the history. This flow does not depend on the deprecated sequence number in report actions.
|
|
106
|
+
*
|
|
107
|
+
* @param {Number} reportID
|
|
108
|
+
* @param {Boolean} ignoreCache
|
|
109
|
+
* @returns {Deferred}
|
|
110
|
+
*/
|
|
111
|
+
function getFlatHistory(reportID, ignoreCache) {
|
|
112
|
+
const promise = new Deferred();
|
|
113
|
+
if (ignoreCache) {
|
|
114
|
+
delete store.cache[reportID];
|
|
115
|
+
}
|
|
116
|
+
store.API.Report_GetHistory({
|
|
117
|
+
reportID,
|
|
118
|
+
})
|
|
119
|
+
.done((recentHistory) => {
|
|
120
|
+
mergeHistoryByReportActionID(reportID, recentHistory);
|
|
121
|
+
promise.resolve(store.cache[reportID]);
|
|
122
|
+
})
|
|
123
|
+
.fail(promise.reject);
|
|
124
|
+
return promise;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Gets the history from the cache if it exists. Otherwise fully loads the history.
|
|
128
|
+
*
|
|
129
|
+
* @param {Number} reportID
|
|
130
|
+
* @returns {Deferred}
|
|
131
|
+
*/
|
|
132
|
+
function getFromCache(reportID) {
|
|
133
|
+
const promise = new Deferred();
|
|
134
|
+
const cachedHistory = store.cache[reportID] || [];
|
|
135
|
+
if (cachedHistory.length === 0) {
|
|
136
|
+
return getFlatHistory(reportID);
|
|
137
|
+
}
|
|
138
|
+
return promise.resolve(cachedHistory);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
get: (reportID, ignoreCache = false) => {
|
|
142
|
+
const promise = new Deferred();
|
|
143
|
+
get(reportID, ignoreCache)
|
|
144
|
+
.done((reportHistory) => {
|
|
145
|
+
promise.resolve(filterHiddenActions(reportHistory));
|
|
146
|
+
})
|
|
147
|
+
.fail(promise.reject);
|
|
148
|
+
return promise;
|
|
149
|
+
},
|
|
150
|
+
getFlatHistory: (reportID, ignoreCache = false) => {
|
|
151
|
+
const promise = new Deferred();
|
|
152
|
+
getFlatHistory(reportID, ignoreCache)
|
|
153
|
+
.done((reportHistory) => {
|
|
154
|
+
promise.resolve(filterHiddenActions(reportHistory));
|
|
155
|
+
})
|
|
156
|
+
.fail(promise.reject);
|
|
157
|
+
return promise;
|
|
158
|
+
},
|
|
159
|
+
insertIntoCache: (reportID, reportAction) => {
|
|
160
|
+
const promise = new Deferred();
|
|
161
|
+
getFromCache(reportID)
|
|
162
|
+
.done((cachedHistory) => {
|
|
163
|
+
const sequenceNumber = reportAction.sequenceNumber;
|
|
164
|
+
if (cachedHistory.length >= sequenceNumber) {
|
|
165
|
+
mergeItems(reportID, [reportAction]);
|
|
166
|
+
return promise.resolve(filterHiddenActions(store.cache[reportID]));
|
|
167
|
+
}
|
|
168
|
+
get(reportID)
|
|
169
|
+
.done((reportHistory) => promise.resolve(filterHiddenActions(reportHistory)))
|
|
170
|
+
.fail(promise.reject);
|
|
171
|
+
})
|
|
172
|
+
.fail(promise.reject);
|
|
173
|
+
return promise;
|
|
174
|
+
},
|
|
175
|
+
insertIntoCacheByActionID: (reportID, reportAction) => {
|
|
176
|
+
const promise = new Deferred();
|
|
177
|
+
getFromCache(reportID)
|
|
178
|
+
.done((cachedHistory) => {
|
|
179
|
+
if (cachedHistory.some(({ reportActionID }) => reportActionID === reportAction.reportActionID)) {
|
|
180
|
+
mergeHistoryByTimestamp(reportID, [reportAction]);
|
|
181
|
+
return promise.resolve(filterHiddenActions(store.cache[reportID]));
|
|
182
|
+
}
|
|
183
|
+
getFlatHistory(reportID)
|
|
184
|
+
.done((reportHistory) => promise.resolve(filterHiddenActions(reportHistory)))
|
|
185
|
+
.fail(promise.reject);
|
|
186
|
+
})
|
|
187
|
+
.fail(promise.reject);
|
|
188
|
+
return promise;
|
|
189
|
+
},
|
|
190
|
+
bindCacheClearingEvents: (events) => {
|
|
191
|
+
for (const event of events) {
|
|
192
|
+
store.PubSub.subscribe(event, () => {
|
|
193
|
+
store.cache = {};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
filterHiddenActions,
|
|
198
|
+
};
|
|
199
|
+
}
|
package/dist/esm/SafeString.js
CHANGED
|
@@ -23,7 +23,7 @@ export default function SafeString(value) {
|
|
|
23
23
|
try {
|
|
24
24
|
return JSON.stringify(value);
|
|
25
25
|
}
|
|
26
|
-
catch {
|
|
26
|
+
catch (_a) {
|
|
27
27
|
return '[object Array]';
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -41,7 +41,7 @@ export default function SafeString(value) {
|
|
|
41
41
|
try {
|
|
42
42
|
return JSON.stringify(obj);
|
|
43
43
|
}
|
|
44
|
-
catch {
|
|
44
|
+
catch (_b) {
|
|
45
45
|
return '[object Object]';
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export default Templates;
|
|
2
|
+
declare namespace Templates {
|
|
3
|
+
/**
|
|
4
|
+
* Given a templatePath, return the value
|
|
5
|
+
*
|
|
6
|
+
* @param {Array} templatePath
|
|
7
|
+
* @param {Object} [data] Information that need to be injected into the template
|
|
8
|
+
* @returns {String}
|
|
9
|
+
*/
|
|
10
|
+
function get(templatePath: any[], data?: Object): string;
|
|
11
|
+
/**
|
|
12
|
+
* Given a templatePath, does it have a registered template?
|
|
13
|
+
* @param {Array} templatePath
|
|
14
|
+
* @returns {Boolean}
|
|
15
|
+
*/
|
|
16
|
+
function has(templatePath: any[]): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Inits the templating engine, and slurps all DOM templates in an internal data structure
|
|
19
|
+
*/
|
|
20
|
+
function init(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Register a new json object in the template manager
|
|
23
|
+
*
|
|
24
|
+
* @param {Array} wantedNamespace Namespace where we want to store the templates
|
|
25
|
+
* @param {object} templateData The literal object that contain the templates
|
|
26
|
+
*/
|
|
27
|
+
function register(wantedNamespace: any[], templateData: object): void;
|
|
28
|
+
/**
|
|
29
|
+
* Removes a namespace from the templateStore (only used for testing purposes)
|
|
30
|
+
*
|
|
31
|
+
* @param {String} nameSpace
|
|
32
|
+
*/
|
|
33
|
+
function unregister(nameSpace: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Replace the DOM HTML with the template value
|
|
36
|
+
*
|
|
37
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
38
|
+
* @param {Array} templatePath
|
|
39
|
+
* @param {Object} [data] Information that need to be injected into the template
|
|
40
|
+
*/
|
|
41
|
+
function insert($target: JQueryStatic, templatePath: any[], data?: Object): void;
|
|
42
|
+
/**
|
|
43
|
+
* Append the template value into a DOM elements
|
|
44
|
+
*
|
|
45
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
46
|
+
* @param {Array} templatePath
|
|
47
|
+
* @param {Object} data Information that need to be injected into the template
|
|
48
|
+
*/
|
|
49
|
+
function prepend($target: JQueryStatic, templatePath: any[], data: Object): void;
|
|
50
|
+
/**
|
|
51
|
+
* Prepend the template value into a DOM elements
|
|
52
|
+
*
|
|
53
|
+
* @param {jQuery} $target Element(s) that will be updated
|
|
54
|
+
* @param {array} templatePath
|
|
55
|
+
* @param {object} [data] Information that need to be injected into the template
|
|
56
|
+
*/
|
|
57
|
+
function append($target: JQueryStatic, templatePath: array, data?: object): void;
|
|
58
|
+
}
|