diff options
Diffstat (limited to 'app/assets/javascripts/import_entities/import_groups/graphql/services')
3 files changed, 74 insertions, 122 deletions
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/local_storage_cache.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/local_storage_cache.js new file mode 100644 index 00000000000..09bc7b33692 --- /dev/null +++ b/app/assets/javascripts/import_entities/import_groups/graphql/services/local_storage_cache.js @@ -0,0 +1,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); +} diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js deleted file mode 100644 index 7caa37d9ad4..00000000000 --- a/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js +++ /dev/null @@ -1,87 +0,0 @@ -import { debounce, merge } from 'lodash'; - -export const KEY = 'gl-bulk-imports-import-state'; -export const DEBOUNCE_INTERVAL = 200; - -export class SourceGroupsManager { - constructor({ sourceUrl, storage = window.localStorage }) { - this.sourceUrl = sourceUrl; - - this.storage = storage; - this.importStates = this.loadImportStatesFromStorage(); - } - - loadImportStatesFromStorage() { - try { - return Object.fromEntries( - Object.entries(JSON.parse(this.storage.getItem(KEY)) ?? {}).map(([jobId, config]) => { - // new format of storage - if (config.groups) { - return [jobId, config]; - } - - return [ - jobId, - { - status: config.status, - groups: [{ id: config.id, importTarget: config.importTarget }], - }, - ]; - }), - ); - } catch { - return {}; - } - } - - createImportState(importId, jobConfig) { - this.importStates[importId] = { - status: jobConfig.status, - groups: jobConfig.groups.map((g) => ({ - importTarget: { ...g.import_target }, - id: g.id, - })), - }; - this.saveImportStatesToStorage(); - } - - updateImportProgress(importId, status) { - const currentState = this.importStates[importId]; - if (!currentState) { - return; - } - - currentState.status = status; - this.saveImportStatesToStorage(); - } - - getImportedGroupsByJobId(jobId) { - return this.importStates[jobId]?.groups ?? []; - } - - getImportStateFromStorageByGroupId(groupId) { - const [jobId, importState] = - Object.entries(this.importStates) - .reverse() - .find(([, state]) => state.groups.some((g) => g.id === groupId)) ?? []; - - if (!jobId) { - return null; - } - - const group = importState.groups.find((g) => g.id === groupId); - return { jobId, importState: { ...group, status: importState.status } }; - } - - saveImportStatesToStorage = debounce(() => { - try { - // storage might be changed in other tab so fetch first - this.storage.setItem( - KEY, - JSON.stringify(merge({}, this.loadImportStatesFromStorage(), this.importStates)), - ); - } catch { - // empty catch intentional: storage might be unavailable or full - } - }, DEBOUNCE_INTERVAL); -} diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js deleted file mode 100644 index 0297b3d3428..00000000000 --- a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js +++ /dev/null @@ -1,35 +0,0 @@ -import Visibility from 'visibilityjs'; -import createFlash from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import Poll from '~/lib/utils/poll'; -import { s__ } from '~/locale'; - -export class StatusPoller { - constructor({ updateImportStatus, pollPath }) { - this.eTagPoll = new Poll({ - resource: { - fetchJobs: () => axios.get(pollPath), - }, - method: 'fetchJobs', - successCallback: ({ data: statuses }) => { - statuses.forEach((status) => updateImportStatus(status)); - }, - errorCallback: () => - createFlash({ - message: s__('BulkImport|Update of import statuses with realtime changes failed'), - }), - }); - - Visibility.change(() => { - if (!Visibility.hidden()) { - this.eTagPoll.restart(); - } else { - this.eTagPoll.stop(); - } - }); - } - - startPolling() { - this.eTagPoll.makeRequest(); - } -} |