open-consul/ui/packages/consul-ui/app/services/local-storage.js

132 lines
3.0 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Service from '@ember/service';
import { getOwner } from '@ember/application';
import ENV from 'consul-ui/config/environment';
export function storageFor(key) {
return function () {
return {
get() {
const owner = getOwner(this);
const localStorageService = owner.lookup('service:localStorage');
return localStorageService.getBucket(key);
},
};
};
}
/**
* An in-memory stub of window.localStorage. Ideally this would
* implement the [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage)-interface that localStorage implements
* as well.
*
* We use this implementation during testing to not pollute `window.localStorage`
*/
class MemoryStorage {
constructor() {
this.data = new Map();
}
getItem(key) {
return this.data.get(key);
}
setItem(key, value) {
return this.data.set(key, value.toString());
}
/**
* A function to seed data into MemoryStorage. This expects an object to be
* passed. The passed values will be persisted as a string - i.e. the values
* passed will call their `toString()`-method before writing to storage. You need
* to take this into account when you want to persist complex values, like arrays
* or objects:
*
* Example:
*
* ```js
* const storage = new MemoryStorage();
* storage.seed({ notices: ['notice-a', 'notice-b']});
*
* storage.getItem('notices') // => 'notice-a,notice-b'
*
* // won't work
* storage.seed({
* user: { name: 'Tomster' }
* })
*
* storage.getItem('user') // => '[object Object]'
*
* // this works
* storage.seed({
* . user: JSON.stringify({name: 'Tomster'})
* })
*
* storage.getItem('user') // => '{ "name": "Tomster" }'
* ```
* @param {object} data - the data to seed
*/
seed(data) {
const newData = new Map();
const keys = Object.keys(data);
keys.forEach((key) => {
newData.set(key, data[key].toString());
});
this.data = newData;
}
}
/**
* There might be better ways to do this but this is good enough for now.
* During testing we want to use MemoryStorage not window.localStorage.
*/
function initStorage() {
if (ENV.environment === 'test') {
return new MemoryStorage();
} else {
return window.localStorage;
}
}
/**
* A service that wraps access to local-storage. We wrap
* local-storage to not pollute local-storage during testing.
*/
export default class LocalStorageService extends Service {
constructor() {
super(...arguments);
this.storage = initStorage();
this.buckets = new Map();
}
getBucket(key) {
const bucket = this.buckets.get(key);
if (bucket) {
return bucket;
} else {
return this._setupBucket(key);
}
}
_setupBucket(key) {
const owner = getOwner(this);
const Klass = owner.factoryFor(`storage:${key}`).class;
const storage = new Klass(key, this.storage);
this.buckets.set(key, storage);
return storage;
}
}