diff --git a/.changeset/new-foxes-matter.md b/.changeset/new-foxes-matter.md new file mode 100644 index 0000000000..234dd78451 --- /dev/null +++ b/.changeset/new-foxes-matter.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-app-api': minor +'@backstage/core-plugin-api': minor +'@backstage/test-utils': minor +--- + +**BREAKING**: Removed the deprecated `get` method from `StorageAPI` and its implementations, this method has been replaced by the `snapshot` method. The return value from snapshot no longer includes `newValue` which has been replaced by `value`. For getting notified when a value changes, use `observe$`. diff --git a/.changeset/two-lobsters-hammer.md b/.changeset/two-lobsters-hammer.md new file mode 100644 index 0000000000..412901fb41 --- /dev/null +++ b/.changeset/two-lobsters-hammer.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-catalog-react': patch +--- + +Updated usage of `StorageApi` to use `snapshot` method instead of `get` diff --git a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.test.ts b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.test.ts index d81cba48d2..2f82ed5e88 100644 --- a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.test.ts +++ b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.test.ts @@ -33,12 +33,11 @@ describe('WebStorage Storage API', () => { it('should return undefined for values which are unset', async () => { const storage = createWebStorage(); - expect(storage.get('myfakekey')).toBeUndefined(); + expect(storage.snapshot('myfakekey').value).toBeUndefined(); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'absent', value: undefined, - newValue: undefined, }); }); @@ -48,26 +47,23 @@ describe('WebStorage Storage API', () => { 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); + expect(storage.snapshot('myfakekey').value).toBe('helloimastring'); + expect(storage.snapshot('mysecondfakekey').value).toBe(1234); + expect(storage.snapshot('mythirdfakekey').value).toBe(true); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'present', value: 'helloimastring', - newValue: 'helloimastring', }); expect(storage.snapshot('mysecondfakekey')).toEqual({ key: 'mysecondfakekey', presence: 'present', value: 1234, - newValue: 1234, }); expect(storage.snapshot('mythirdfakekey')).toEqual({ key: 'mythirdfakekey', presence: 'present', value: true, - newValue: true, }); }); @@ -81,12 +77,11 @@ describe('WebStorage Storage API', () => { await storage.set('myfakekey', mockData); - expect(storage.get('myfakekey')).toEqual(mockData); + expect(storage.snapshot('myfakekey').value).toEqual(mockData); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'present', value: mockData, - newValue: mockData, }); }); @@ -118,7 +113,6 @@ describe('WebStorage Storage API', () => { key: 'correctKey', presence: 'present', value: mockData, - newValue: mockData, }); }); @@ -152,7 +146,6 @@ describe('WebStorage Storage API', () => { key: 'correctKey', presence: 'absent', value: undefined, - newValue: undefined, }); }); @@ -166,9 +159,11 @@ describe('WebStorage Storage API', () => { await firstStorage.set(keyName, 'boop'); await secondStorage.set(keyName, 'deerp'); - expect(firstStorage.get(keyName)).not.toBe(secondStorage.get(keyName)); - expect(firstStorage.get(keyName)).toBe('boop'); - expect(secondStorage.get(keyName)).toBe('deerp'); + expect(firstStorage.snapshot(keyName)).not.toBe( + secondStorage.snapshot(keyName), + ); + expect(firstStorage.snapshot(keyName).value).toBe('boop'); + expect(secondStorage.snapshot(keyName).value).toBe('deerp'); expect(firstStorage.snapshot(keyName)).not.toEqual( secondStorage.snapshot(keyName), ); @@ -176,13 +171,11 @@ describe('WebStorage Storage API', () => { key: keyName, presence: 'present', value: 'boop', - newValue: 'boop', }); expect(secondStorage.snapshot(keyName)).toEqual({ key: keyName, presence: 'present', value: 'deerp', - newValue: 'deerp', }); }); @@ -217,7 +210,6 @@ describe('WebStorage Storage API', () => { key: 'key', presence: 'absent', value: undefined, - newValue: undefined, }); expect(mockErrorApi.post).toHaveBeenCalledWith(expect.any(Error)); expect(mockErrorApi.post).toHaveBeenCalledWith( diff --git a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts index c4cffaf184..ac3d3f20f2 100644 --- a/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts +++ b/packages/core-app-api/src/apis/implementations/StorageApi/WebStorage.ts @@ -65,7 +65,7 @@ export class WebStorage implements StorageApi { new Error(`Error when parsing JSON config from storage for: ${key}`), ); } - return { key, value, newValue: value, presence }; + return { key, value, presence }; } forBucket(name: string): WebStorage { diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx index e62b3fa82d..3348c278ee 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.test.tsx @@ -75,7 +75,7 @@ describe('', () => { ); fireEvent.click(button); const dismissedBanners = - notifications?.get('dismissedBanners') ?? []; + notifications?.snapshot('dismissedBanners').value ?? []; expect( dismissedBanners.includes('catalog_page_welcome_banner'), ).toBeTruthy(); diff --git a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx index 566b326cb5..9ff7616c45 100644 --- a/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx +++ b/packages/core-components/src/components/DismissableBanner/DismissableBanner.tsx @@ -101,7 +101,7 @@ export const DismissableBanner = (props: Props) => { const storageApi = useApi(storageApiRef); const notificationsStore = storageApi.forBucket('notifications'); const rawDismissedBanners = - notificationsStore.get('dismissedBanners') ?? []; + notificationsStore.snapshot('dismissedBanners').value ?? []; const [dismissedBanners, setDismissedBanners] = useState( new Set(rawDismissedBanners), @@ -112,11 +112,11 @@ export const DismissableBanner = (props: Props) => { ); useEffect(() => { - if (observedItems?.newValue) { - const currentValue = observedItems?.newValue ?? []; + if (observedItems?.value) { + const currentValue = observedItems?.value ?? []; setDismissedBanners(new Set(currentValue)); } - }, [observedItems?.newValue]); + }, [observedItems?.value]); const handleClick = () => { notificationsStore.set('dismissedBanners', [...dismissedBanners, id]); diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 83cca4477b..89361419ba 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -678,8 +678,6 @@ export type SignInPageProps = { // @public export interface StorageApi { forBucket(name: string): StorageApi; - // @deprecated - get(key: string): T | undefined; observe$( key: string, ): Observable>; @@ -691,23 +689,17 @@ export interface StorageApi { // @public export const storageApiRef: ApiRef; -// @public @deprecated (undocumented) -export type StorageValueChange = - StorageValueSnapshot; - // @public export type StorageValueSnapshot = | { key: string; presence: 'unknown' | 'absent'; value?: undefined; - newValue?: undefined; } | { key: string; presence: 'present'; value: TValue; - newValue?: TValue; }; // @public diff --git a/packages/core-plugin-api/src/apis/definitions/StorageApi.ts b/packages/core-plugin-api/src/apis/definitions/StorageApi.ts index 4bd49f9b83..1506e5f143 100644 --- a/packages/core-plugin-api/src/apis/definitions/StorageApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/StorageApi.ts @@ -27,24 +27,13 @@ export type StorageValueSnapshot = key: string; presence: 'unknown' | 'absent'; value?: undefined; - /** @deprecated Use `value` instead */ - newValue?: undefined; } | { key: string; presence: 'present'; value: TValue; - /** @deprecated Use `value` instead */ - newValue?: TValue; }; -/** - * @public - * @deprecated Use StorageValueSnapshot instead - */ -export type StorageValueChange = - StorageValueSnapshot; - /** * Provides a key-value persistence API. * @@ -59,14 +48,6 @@ export interface StorageApi { */ forBucket(name: string): StorageApi; - /** - * Get the current value for persistent data, use observe$ to be notified of updates. - * - * @deprecated Use `snapshot` instead. - * @param key - Unique key associated with the data. - */ - get(key: string): T | undefined; - /** * Remove persistent data. * diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 4e5361ff80..2f2671885e 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -164,8 +164,6 @@ export class MockStorageApi implements StorageApi { // (undocumented) forBucket(name: string): StorageApi; // (undocumented) - get(key: string): T | undefined; - // (undocumented) observe$(key: string): Observable>; // (undocumented) remove(key: string): Promise; diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts index c974198be1..63aa4235e1 100644 --- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts +++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.test.ts @@ -24,7 +24,7 @@ describe('WebStorage Storage API', () => { it('should return undefined for values which are unset', async () => { const storage = createMockStorage(); - expect(storage.get('myfakekey')).toBeUndefined(); + expect(storage.snapshot('myfakekey').value).toBeUndefined(); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'absent', @@ -33,32 +33,29 @@ describe('WebStorage Storage API', () => { }); }); - it('should allow the setting and getting of the simple data structures', async () => { + it('should allow the setting and snapshotting of the simple data structures', async () => { const storage = createMockStorage(); 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); + expect(storage.snapshot('myfakekey').value).toBe('helloimastring'); + expect(storage.snapshot('mysecondfakekey').value).toBe(1234); + expect(storage.snapshot('mythirdfakekey').value).toBe(true); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'present', value: 'helloimastring', - newValue: 'helloimastring', }); expect(storage.snapshot('mysecondfakekey')).toEqual({ key: 'mysecondfakekey', presence: 'present', value: 1234, - newValue: 1234, }); expect(storage.snapshot('mythirdfakekey')).toEqual({ key: 'mythirdfakekey', presence: 'present', value: true, - newValue: true, }); }); @@ -72,12 +69,11 @@ describe('WebStorage Storage API', () => { await storage.set('myfakekey', mockData); - expect(storage.get('myfakekey')).toEqual(mockData); + expect(storage.snapshot('myfakekey').value).toEqual(mockData); expect(storage.snapshot('myfakekey')).toEqual({ key: 'myfakekey', presence: 'present', value: mockData, - newValue: mockData, }); }); @@ -107,7 +103,6 @@ describe('WebStorage Storage API', () => { key: 'correctKey', presence: 'present', value: mockData, - newValue: mockData, }); }); @@ -153,9 +148,11 @@ describe('WebStorage Storage API', () => { await firstStorage.set(keyName, 'boop'); await secondStorage.set(keyName, 'deerp'); - expect(firstStorage.get(keyName)).not.toBe(secondStorage.get(keyName)); - expect(firstStorage.get(keyName)).toBe('boop'); - expect(secondStorage.get(keyName)).toBe('deerp'); + expect(firstStorage.snapshot(keyName)).not.toBe( + secondStorage.snapshot(keyName), + ); + expect(firstStorage.snapshot(keyName).value).toBe('boop'); + expect(secondStorage.snapshot(keyName).value).toBe('deerp'); expect(firstStorage.snapshot(keyName)).not.toEqual( secondStorage.snapshot(keyName), ); @@ -163,13 +160,11 @@ describe('WebStorage Storage API', () => { key: keyName, presence: 'present', value: 'boop', - newValue: 'boop', }); expect(secondStorage.snapshot(keyName)).toEqual({ key: keyName, presence: 'present', value: 'deerp', - newValue: 'deerp', }); }); @@ -186,7 +181,7 @@ describe('WebStorage Storage API', () => { await firstStorage.set('test2', { error: true }); - expect(secondStorage.get('deep/test2')).toBe(undefined); + expect(secondStorage.snapshot('deep/test2').value).toBe(undefined); expect(secondStorage.snapshot('deep/test2')).toMatchObject({ presence: 'absent', }); @@ -201,19 +196,17 @@ describe('WebStorage Storage API', () => { await firstStorage.set('test2', true); - expect(firstStorage.get('test2')).toBe(true); - expect(secondStorage.get('test2')).toBe(undefined); + expect(firstStorage.snapshot('test2').value).toBe(true); + expect(secondStorage.snapshot('test2').value).toBe(undefined); expect(firstStorage.snapshot('test2')).toEqual({ key: 'test2', presence: 'present', value: true, - newValue: true, }); expect(secondStorage.snapshot('test2')).toEqual({ key: 'test2', presence: 'absent', value: undefined, - newValue: undefined, }); }); diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts index 25024f2211..6ce91a4a31 100644 --- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts +++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts @@ -61,10 +61,6 @@ export class MockStorageApi implements StorageApi { return this.bucketStorageApis.get(name)!; } - get(key: string): T | undefined { - return this.snapshot(key).value as T | undefined; - } - snapshot(key: string): StorageValueSnapshot { if (this.data.hasOwnProperty(this.getKeyName(key))) { const data = this.data[this.getKeyName(key)]; @@ -72,14 +68,12 @@ export class MockStorageApi implements StorageApi { key, presence: 'present', value: data, - newValue: data, }; } return { key, presence: 'absent', value: undefined, - newValue: undefined, }; } @@ -95,7 +89,6 @@ export class MockStorageApi implements StorageApi { key, presence: 'present', value: serialized, - newValue: serialized, }); } @@ -105,7 +98,6 @@ export class MockStorageApi implements StorageApi { key, presence: 'absent', value: undefined, - newValue: undefined, }); } diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts index e9cf84f11b..f4b7771d04 100644 --- a/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts @@ -36,12 +36,12 @@ export class DefaultStarredEntitiesApi implements StarredEntitiesApi { this.settingsStore = opts.storageApi.forBucket('starredEntities'); this.starredEntities = new Set( - this.settingsStore.get('entityRefs') ?? [], + this.settingsStore.snapshot('entityRefs').value ?? [], ); this.settingsStore.observe$('entityRefs').subscribe({ next: next => { - this.starredEntities = new Set(next.newValue ?? []); + this.starredEntities = new Set(next.value ?? []); this.notifyChanges(); }, }); diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts b/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts index 7eb5648d13..b3bc5400d5 100644 --- a/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/migration.test.ts @@ -41,19 +41,19 @@ describe('performMigrationToTheNewBucket', () => { 'entity:Component:default:a', 'entity:template:custom:b', ]); - expect(oldBucket.get('starredEntities')).not.toBeUndefined(); + expect(oldBucket.snapshot('starredEntities').value).not.toBeUndefined(); await performMigrationToTheNewBucket({ storageApi: mockStorage }); // read NEW bucket - expect(await newBucket.get('entityRefs')).toEqual([ + expect(await newBucket.snapshot('entityRefs').value).toEqual([ 'component:default/c', 'component:default/a', 'template:custom/b', ]); // OLD bucket should be removed - expect(oldBucket.get('starredEntities')).toBeUndefined(); + expect(oldBucket.snapshot('starredEntities').value).toBeUndefined(); }); it('should ignore invalid entries', async () => { @@ -67,15 +67,17 @@ describe('performMigrationToTheNewBucket', () => { 'entity:Component:a', 'invalid', ]); - expect(oldBucket.get('starredEntities')).not.toBeUndefined(); + expect(oldBucket.snapshot('starredEntities')).not.toBeUndefined(); await performMigrationToTheNewBucket({ storageApi: mockStorage }); // read NEW bucket - expect(await newBucket.get('entityRefs')).toEqual(['component:default/a']); + expect(await newBucket.snapshot('entityRefs').value).toEqual([ + 'component:default/a', + ]); // OLD bucket should be removed - expect(oldBucket.get('starredEntities')).toBeUndefined(); + expect(oldBucket.snapshot('starredEntities').value).toBeUndefined(); }); it('should skip migration without old starred entities', async () => { @@ -88,7 +90,7 @@ describe('performMigrationToTheNewBucket', () => { await performMigrationToTheNewBucket({ storageApi: mockStorage }); // read NEW bucket - expect(newBucket.get('entityRefs')).toEqual(expectedEntries); + expect(newBucket.snapshot('entityRefs').value).toEqual(expectedEntries); }); it('should skip migration with non-array old starred entities', async () => { @@ -105,9 +107,9 @@ describe('performMigrationToTheNewBucket', () => { await performMigrationToTheNewBucket({ storageApi: mockStorage }); // read NEW bucket - expect(newBucket.get('entityRefs')).toEqual(expectedEntries); + expect(newBucket.snapshot('entityRefs').value).toEqual(expectedEntries); // OLD bucket should be unchanged - expect(oldBucket.get('starredEntities')).toBe('invalid'); + expect(oldBucket.snapshot('starredEntities').value).toBe('invalid'); }); }); diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/migration.ts b/plugins/catalog/src/apis/StarredEntitiesApi/migration.ts index 8405d9e08d..51dcd6e7ce 100644 --- a/plugins/catalog/src/apis/StarredEntitiesApi/migration.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/migration.ts @@ -35,13 +35,15 @@ export async function performMigrationToTheNewBucket({ const source = storageApi.forBucket('settings'); const target = storageApi.forBucket('starredEntities'); - const oldStarredEntities = source.get('starredEntities'); + const oldStarredEntities = source.snapshot('starredEntities').value; if (!isArray(oldStarredEntities)) { // nothing to do return; } - const targetEntities = new Set(target.get('entityRefs') ?? []); + const targetEntities = new Set( + target.snapshot('entityRefs').value ?? [], + ); oldStarredEntities .filter(isString)