All files / app/assets/javascripts/import_entities/import_groups/graphql/services local_storage_cache.js

86.2% Statements 25/29
20% Branches 2/10
90% Functions 9/10
86.2% Lines 25/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 75 76 77 78 79 80 81 82 83      4x 4x 4x       3x 3x 3x   3x           3x       7x 7x                 7x         3x 3x   3x       1x         1x 1x 1x       1x       1x 1x                 1x     3x 4x   4x            
import { debounce, merge } from 'lodash';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
 
const OLD_KEY = 'gl-bulk-imports-import-state-v2';
export const KEY = 'gl-bulk-imports-import-state-v3';
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 {
      const storage = JSON.parse(this.storage.getItem(KEY)) ?? {};
      Object.values(storage).forEach((entry) => {
        if (entry.progress && !('message' in entry.progress)) {
          // eslint-disable-next-line no-param-reassign
          entry.progress.message = '';
        }
      });
      return storage;
    } 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
    Eif (!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, hasFailures) {
    this.getCacheKeysByJobId(jobId).forEach((webUrl) =>
      this.set(webUrl, {
        ...this.get(webUrl),
        progress: {
          id: jobId,
          status,
          hasFailures,
        },
      }),
    );
    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);
}