replaced internal observable with a mapping from the storage API

Signed-off-by: Alex Rybchenko <arybchenko@box.com>
This commit is contained in:
Alex Rybchenko
2022-07-13 16:17:54 +02:00
parent 5b769fddb5
commit 2e17ad5e30
4 changed files with 33 additions and 43 deletions
+2 -1
View File
@@ -40,7 +40,8 @@ export interface ShortcutsProps {
export const Shortcuts = (props: ShortcutsProps) => {
const shortcutApi = useApi(shortcutsApiRef);
const shortcuts = useObservable(
useMemo(() => shortcutApi.shortcut$(), [shortcutApi]),
shortcutApi.shortcut$(),
shortcutApi.snapshot(),
);
const [anchorEl, setAnchorEl] = React.useState<Element | undefined>();
const loading = Boolean(!shortcuts);
@@ -27,17 +27,22 @@ describe('LocalStoredShortcuts', () => {
);
const shortcut: Shortcut = { id: 'id', title: 'title', url: '/url' };
await shortcutApi.add(shortcut);
const observerNextHandler = jest.fn();
await new Promise<void>(resolve => {
const subscription = shortcutApi.shortcut$().subscribe(data => {
expect(data).toEqual(
expect.arrayContaining([{ ...shortcut, id: expect.anything() }]),
);
subscription.unsubscribe();
resolve();
shortcutApi.shortcut$().subscribe({
next: data => {
observerNextHandler(data);
resolve();
},
});
shortcutApi.add(shortcut);
});
expect(observerNextHandler).toHaveBeenCalledTimes(1);
expect(observerNextHandler).toHaveBeenCalledWith(
expect.arrayContaining([{ ...shortcut, id: expect.anything() }]),
);
});
it('should add shortcuts with ids', async () => {
@@ -15,41 +15,45 @@
*/
import { pageTheme } from '@backstage/theme';
import ObservableImpl from 'zen-observable';
import { v4 as uuid } from 'uuid';
import { ShortcutApi } from './ShortcutApi';
import { Shortcut } from '../types';
import { StorageApi } from '@backstage/core-plugin-api';
import Observable from 'zen-observable';
/**
* Implementation of the ShortcutApi that uses the StorageApi to store shortcuts.
*/
export class LocalStoredShortcuts implements ShortcutApi {
constructor(private readonly storageApi: StorageApi) {
this.storageApi.observe$<Shortcut[]>('items').subscribe({
next: () => this.notify(),
});
}
constructor(private readonly storageApi: StorageApi) {}
shortcut$() {
return this.observable;
return Observable.from(this.storageApi.observe$<Shortcut[]>('items')).map(
snapshot => snapshot.value ?? [],
);
}
snapshot() {
return Array.from(
this.storageApi.snapshot<Shortcut[]>('items').value ?? [],
).sort((a, b) => (a.title >= b.title ? 1 : -1));
}
async add(shortcut: Omit<Shortcut, 'id'>) {
const shortcuts = this.get();
const shortcuts = this.snapshot();
shortcuts.push({ ...shortcut, id: uuid() });
await this.storageApi.set('items', shortcuts);
}
async remove(id: string) {
const shortcuts = this.get().filter(s => s.id !== id);
const shortcuts = this.snapshot().filter(s => s.id !== id);
await this.storageApi.set('items', shortcuts);
}
async update(shortcut: Shortcut) {
const shortcuts = this.get().filter(s => s.id !== shortcut.id);
const shortcuts = this.snapshot().filter(s => s.id !== shortcut.id);
shortcuts.push(shortcut);
await this.storageApi.set('items', shortcuts);
@@ -64,33 +68,8 @@ export class LocalStoredShortcuts implements ShortcutApi {
return pageTheme[theme].colors[0];
}
private subscribers = new Set<
ZenObservable.SubscriptionObserver<Shortcut[]>
>();
private readonly observable = new ObservableImpl<Shortcut[]>(subscriber => {
subscriber.next(this.get());
this.subscribers.add(subscriber);
return () => {
this.subscribers.delete(subscriber);
};
});
private readonly THEME_MAP: Record<string, keyof typeof pageTheme> = {
catalog: 'home',
docs: 'documentation',
};
private get() {
return Array.from(
this.storageApi.snapshot<Shortcut[]>('items').value ?? [],
).sort((a, b) => (a.title >= b.title ? 1 : -1));
}
private notify() {
for (const subscription of this.subscribers) {
subscription.next(this.get());
}
}
}
+5
View File
@@ -28,6 +28,11 @@ export interface ShortcutApi {
*/
shortcut$(): Observable<Shortcut[]>;
/**
* Returns an immediate snapshot of shortcuts, sorted by title
*/
snapshot(): Shortcut[];
/**
* Generates a unique id for the shortcut and then saves it.
*/