1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
import { debounce, merge } from 'lodash';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
const OLD_KEY = 'gl-bulk-imports-import-state';
export const KEY = 'gl-bulk-imports-import-state-v2';
export const DEBOUNCE_INTERVAL = DEFAULT_DEBOUNCE_AND_THROTTLE_MS;
export class LocalStorageCache {
constructor({ storage = window.localStorage } = {}) {
this.storage = storage;
this.cache = this.loadCacheFromStorage();
try {
// remove old storage data
this.storage.removeItem(OLD_KEY);
} catch {
// empty catch intended
}
// cache for searching data by jobid
this.jobsLookupCache = {};
}
loadCacheFromStorage() {
try {
return JSON.parse(this.storage.getItem(KEY)) ?? {};
} catch {
return {};
}
}
set(webUrl, data) {
this.cache[webUrl] = data;
this.saveCacheToStorage();
// There are changes to jobIds, drop cache
this.jobsLookupCache = {};
}
get(webUrl) {
return this.cache[webUrl];
}
getCacheKeysByJobId(jobId) {
// this is invoked by polling, so we would like to cache results
if (!this.jobsLookupCache[jobId]) {
this.jobsLookupCache[jobId] = Object.keys(this.cache).filter(
(url) => this.cache[url]?.progress.id === jobId,
);
}
return this.jobsLookupCache[jobId];
}
updateStatusByJobId(jobId, status) {
this.getCacheKeysByJobId(jobId).forEach((webUrl) =>
this.set(webUrl, {
...(this.get(webUrl) ?? {}),
progress: {
id: jobId,
status,
},
}),
);
this.saveCacheToStorage();
}
saveCacheToStorage = debounce(() => {
try {
// storage might be changed in other tab so fetch first
this.storage.setItem(KEY, JSON.stringify(merge({}, this.loadCacheFromStorage(), this.cache)));
} catch {
// empty catch intentional: storage might be unavailable or full
}
}, DEBOUNCE_INTERVAL);
}
|