diff --git a/packages/core-api/src/apis/definitions/StorageApi.ts b/packages/core-api/src/apis/definitions/StorageApi.ts index 62a8fd6895..c8e72a518f 100644 --- a/packages/core-api/src/apis/definitions/StorageApi.ts +++ b/packages/core-api/src/apis/definitions/StorageApi.ts @@ -17,6 +17,11 @@ import { createApiRef } from '../ApiRef'; import { Observable } from '@backstage/core-api'; +export type ObservableMessage = { + key: string; + newValue?: T; +}; + export type StorageApi = { /** * Get persistent data. @@ -37,9 +42,8 @@ export type StorageApi = { * Save persistant data. * * @param {String} key Unique key associated with the data. - * @return */ - save(key: string, data: any): Promise; + set(key: string, data: any): Promise; /** * diff --git a/packages/core-api/src/apis/implementations/StorageApi/WebStorage.test.ts b/packages/core-api/src/apis/implementations/StorageApi/WebStorage.test.ts new file mode 100644 index 0000000000..6509ba6edb --- /dev/null +++ b/packages/core-api/src/apis/implementations/StorageApi/WebStorage.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { WebStorage } from './WebStorage'; +describe('WebStorage Storage API', () => { + it('should return undefined for values which are unset', async () => { + const storage = new WebStorage(); + + expect(storage.get('myfakekey')).toBeUndefined(); + }); + + it('should allow the setting and getting of the simple data structures', async () => { + const storage = new WebStorage(); + + await storage.set('myfakekey', 'helloimastring'); + await storage.set('mysecondfakekey', 1234); + await storage.set('mythirdfakekey', true); + + expect(storage.get('myfakekey')).toBe('helloimastring'); + expect(storage.get('mysecondfakekey')).toBe(1234); + expect(storage.get('mythirdfakekey')).toBe(true); + }); + + it('should allow setting of complex datastructures', async () => { + const storage = new WebStorage(); + + const mockData = { + something: 'here', + is: [{ super: { complex: [{ but: 'something', why: true }] } }], + }; + + await storage.set('myfakekey', mockData); + + expect(storage.get('myfakekey')).toEqual(mockData); + }); +}); diff --git a/packages/core-api/src/apis/implementations/StorageApi/WebStorage.ts b/packages/core-api/src/apis/implementations/StorageApi/WebStorage.ts index c48a1ee931..cbcab6349e 100644 --- a/packages/core-api/src/apis/implementations/StorageApi/WebStorage.ts +++ b/packages/core-api/src/apis/implementations/StorageApi/WebStorage.ts @@ -13,39 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { StorageApi } from '../../definitions'; +import { StorageApi, ObservableMessage } from '../../definitions'; +import { Observable } from '../../../types'; +import ObservableImpl from 'zen-observable'; export class WebStorage implements StorageApi { - async getFromStore( - storeName: string, - key: string = '', - defaultValue?: T, - ): Promise { - let store; + private readonly observable = new ObservableImpl(() => {}); + get(key: string): T | undefined { try { - store = JSON.parse(localStorage.getItem(storeName)!) || {}; + const storage = JSON.parse(localStorage.getItem(key)!); + return storage ?? undefined; } catch (e) { window.console.error( - `Error when parsing JSON config from storage for: ${storeName}`, + `Error when parsing JSON config from storage for: ${key}`, + e, ); - return defaultValue; } - if (key) { - return store[key] ?? defaultValue; - } - return store; + return undefined; } - async saveToStore(storeName: string, key: string, data: any): Promise { - const store = JSON.parse(localStorage.getItem(storeName)!) || {}; - store[key] = data; - localStorage.setItem(storeName, JSON.stringify(store)); + async set(key: string, data: T): Promise { + localStorage.setItem(key, JSON.stringify(data, null, 2)); } - async removeFromStore(storeName: string, key: string): Promise { - const store = JSON.parse(localStorage.getItem(storeName)!) || {}; - delete store[key]; - localStorage.setItem(storeName, JSON.stringify(store)); + async remove(key: string): Promise { + localStorage.removeItem(key); + } + + observe$(key: string): Observable { + return this.observable.filter( + ({ key: messageKey }) => messageKey === key, + ) as Observable; } }