diff --git a/.eslintrc.js b/.eslintrc.js index 52dbebef05..1b313b14f6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -98,6 +98,7 @@ const config = { 'i', 'unused-imports', 'unicorn', + 'rxjs', ], rules: { 'array-callback-return': 'error', @@ -202,6 +203,21 @@ const config = { 'sonarjs/no-collection-size-mischeck': 'error', 'sonarjs/no-useless-catch': 'error', 'sonarjs/no-identical-functions': 'error', + 'rxjs/finnish': [ + 'error', + { + functions: false, + methods: false, + strict: true, + types: { + '^LiveData$': true, + // some yjs classes are Observables, but they don't need to be in Finnish notation + '^Doc$': false, // yjs Doc + '^Awareness$': false, // yjs Awareness + '^UndoManager$': false, // yjs UndoManager + }, + }, + ], }, overrides: [ { diff --git a/package.json b/package.json index 8b5a05c945..f8ff5950fc 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "eslint-plugin-i": "^2.29.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-rxjs": "^5.0.3", "eslint-plugin-simple-import-sort": "^12.0.0", "eslint-plugin-sonarjs": "^0.24.0", "eslint-plugin-unicorn": "^51.0.1", diff --git a/packages/backend/server/src/fundamentals/metrics/metrics.ts b/packages/backend/server/src/fundamentals/metrics/metrics.ts index 83e6d72216..92ff1ecdcc 100644 --- a/packages/backend/server/src/fundamentals/metrics/metrics.ts +++ b/packages/backend/server/src/fundamentals/metrics/metrics.ts @@ -43,9 +43,9 @@ const metricCreators: MetricCreators = { gauge(meter: Meter, name: string, opts?: MetricOptions) { let value: any; let attrs: Attributes | undefined; - const ob = meter.createObservableGauge(name, opts); + const ob$ = meter.createObservableGauge(name, opts); - ob.addCallback(result => { + ob$.addCallback(result => { result.observe(value, attrs); }); diff --git a/packages/common/infra/src/initialization/index.ts b/packages/common/infra/src/initialization/index.ts index ce8748ecc0..a296a6e6ce 100644 --- a/packages/common/infra/src/initialization/index.ts +++ b/packages/common/infra/src/initialization/index.ts @@ -113,8 +113,8 @@ export async function buildShowcaseWorkspace( // perhaps put them into middleware? { // the "Write, Draw, Plan all at Once." page should be set to edgeless mode - const edgelessPage1 = pageRecordList.records.value.find( - p => p.title.value === 'Write, Draw, Plan all at Once.' + const edgelessPage1 = pageRecordList.records$.value.find( + p => p.title$.value === 'Write, Draw, Plan all at Once.' ); if (edgelessPage1) { @@ -122,8 +122,8 @@ export async function buildShowcaseWorkspace( } // should jump to "Write, Draw, Plan all at Once." by default - const defaultPage = pageRecordList.records.value.find(p => - p.title.value.startsWith('Write, Draw, Plan all at Once.') + const defaultPage = pageRecordList.records$.value.find(p => + p.title$.value.startsWith('Write, Draw, Plan all at Once.') ); if (defaultPage) { diff --git a/packages/common/infra/src/livedata/__tests__/livedata.spec.ts b/packages/common/infra/src/livedata/__tests__/livedata.spec.ts index dec3f98972..3e4d1d6e63 100644 --- a/packages/common/infra/src/livedata/__tests__/livedata.spec.ts +++ b/packages/common/infra/src/livedata/__tests__/livedata.spec.ts @@ -6,33 +6,33 @@ import { LiveData, PoisonedError } from '..'; describe('livedata', () => { test('LiveData', async () => { - const livedata = new LiveData(0); - expect(livedata.value).toBe(0); - livedata.next(1); - expect(livedata.value).toBe(1); + const livedata$ = new LiveData(0); + expect(livedata$.value).toBe(0); + livedata$.next(1); + expect(livedata$.value).toBe(1); let subscribed = 0; - livedata.subscribe(v => { + livedata$.subscribe(v => { subscribed = v; }); - livedata.next(2); - expect(livedata.value).toBe(2); + livedata$.next(2); + expect(livedata$.value).toBe(2); await vitest.waitFor(() => subscribed === 2); }); test('from', async () => { { - const livedata = LiveData.from(of(1, 2, 3, 4), 0); - expect(livedata.value).toBe(4); + const livedata$ = LiveData.from(of(1, 2, 3, 4), 0); + expect(livedata$.value).toBe(4); } { let subscriber: Subscriber = null!; - const observable = new Observable(s => { + const observable$ = new Observable(s => { subscriber = s; }); - const livedata = LiveData.from(observable, 0); + const livedata$ = LiveData.from(observable$, 0); let value = 0; - livedata.subscribe(v => { + livedata$.subscribe(v => { value = v; }); @@ -46,16 +46,16 @@ describe('livedata', () => { { let observableSubscribed = false; let observableClosed = false; - const observable = new Observable(subscriber => { + const observable$ = new Observable(subscriber => { observableSubscribed = true; subscriber.next(1); return () => { observableClosed = true; }; }); - const livedata = LiveData.from(observable, 0); + const livedata$ = LiveData.from(observable$, 0); expect(observableSubscribed).toBe(false); - const subscription = livedata.subscribe(_ => {}); + const subscription = livedata$.subscribe(_ => {}); expect(observableSubscribed).toBe(true); expect(observableClosed).toBe(false); subscription.unsubscribe(); @@ -64,17 +64,17 @@ describe('livedata', () => { { let subscriber: Subscriber = null!; - const observable = new Observable(s => { + const observable$ = new Observable(s => { subscriber = s; }); - const livedata = LiveData.from(observable, 0); + const livedata$ = LiveData.from(observable$, 0); let value1 = 0; - livedata.subscribe(v => { + livedata$.subscribe(v => { value1 = v; }); let value2 = 0; - livedata.subscribe(v => { + livedata$.subscribe(v => { value2 = v; }); @@ -91,17 +91,17 @@ describe('livedata', () => { { let observableSubscribed = false; let observableClosed = false; - const observable = new Observable(subscriber => { + const observable$ = new Observable(subscriber => { observableSubscribed = true; subscriber.next(1); return () => { observableClosed = true; }; }); - const livedata = LiveData.from(observable, 0); + const livedata$ = LiveData.from(observable$, 0); expect(observableSubscribed).toBe(false); - const subscription1 = livedata.subscribe(_ => {}); - const subscription2 = livedata.subscribe(_ => {}); + const subscription1 = livedata$.subscribe(_ => {}); + const subscription2 = livedata$.subscribe(_ => {}); expect(observableSubscribed).toBe(true); expect(observableClosed).toBe(false); subscription1.unsubscribe(); @@ -112,31 +112,31 @@ describe('livedata', () => { { let observerCount = 0; - const observable = new Observable(_ => { + const observable$ = new Observable(_ => { observerCount++; }); - const livedata = LiveData.from(observable, 0); - livedata.subscribe(_ => {}); - livedata.subscribe(_ => {}); + const livedata$ = LiveData.from(observable$, 0); + livedata$.subscribe(_ => {}); + livedata$.subscribe(_ => {}); expect(observerCount).toBe(1); } { let value = 0; - const observable = new Observable(subscriber => { + const observable$ = new Observable(subscriber => { subscriber.next(value); }); - const livedata = LiveData.from(observable, 0); - expect(livedata.value).toBe(0); + const livedata$ = LiveData.from(observable$, 0); + expect(livedata$.value).toBe(0); value = 1; - expect(livedata.value).toBe(1); + expect(livedata$.value).toBe(1); } }); test('poisoned', () => { { let subscriber: Subscriber = null!; - const livedata = LiveData.from( + const livedata$ = LiveData.from( new Observable(sub => { subscriber = sub; }), @@ -145,7 +145,7 @@ describe('livedata', () => { let value: number = 0; let error: any = null; - livedata.subscribe({ + livedata$.subscribe({ next: v => { value = v; }, @@ -161,11 +161,11 @@ describe('livedata', () => { subscriber.error('error'); expect(error).toBeInstanceOf(PoisonedError); - expect(() => livedata.next(3)).toThrowError(PoisonedError); - expect(() => livedata.value).toThrowError(PoisonedError); + expect(() => livedata$.next(3)).toThrowError(PoisonedError); + expect(() => livedata$.value).toThrowError(PoisonedError); let error2: any = null; - livedata.subscribe({ + livedata$.subscribe({ error: e => { error2 = e; }, @@ -176,29 +176,29 @@ describe('livedata', () => { test('map', () => { { - const livedata = new LiveData(0); - const mapped = livedata.map(v => v + 1); - expect(mapped.value).toBe(1); - livedata.next(1); - expect(mapped.value).toBe(2); + const livedata$ = new LiveData(0); + const mapped$ = livedata$.map(v => v + 1); + expect(mapped$.value).toBe(1); + livedata$.next(1); + expect(mapped$.value).toBe(2); } { - const livedata = new LiveData(0); - const mapped = livedata.map(v => v + 1); + const livedata$ = new LiveData(0); + const mapped$ = livedata$.map(v => v + 1); let value = 0; - mapped.subscribe(v => { + mapped$.subscribe(v => { value = v; }); expect(value).toBe(1); - livedata.next(1); + livedata$.next(1); expect(value).toBe(2); } { let observableSubscribed = false; let observableClosed = false; - const observable = new Observable(subscriber => { + const observable$ = new Observable(subscriber => { observableSubscribed = true; subscriber.next(1); return () => { @@ -206,11 +206,11 @@ describe('livedata', () => { }; }); - const livedata = LiveData.from(observable, 0); - const mapped = livedata.map(v => v + 1); + const livedata$ = LiveData.from(observable$, 0); + const mapped$ = livedata$.map(v => v + 1); expect(observableSubscribed).toBe(false); - const subscription = mapped.subscribe(_ => {}); + const subscription = mapped$.subscribe(_ => {}); expect(observableSubscribed).toBe(true); expect(observableClosed).toBe(false); subscription.unsubscribe(); @@ -219,9 +219,9 @@ describe('livedata', () => { }); test('interop with rxjs', () => { - const ob = combineLatest([new LiveData(1)]); + const ob$ = combineLatest([new LiveData(1)]); let value = 0; - ob.subscribe(v => { + ob$.subscribe(v => { value = v[0]; }); expect(value).toBe(1); @@ -229,69 +229,69 @@ describe('livedata', () => { test('flat', () => { { - const wrapped = new LiveData(new LiveData(0)); - const flatten = wrapped.flat(); - expect(flatten.value).toBe(0); + const wrapped$ = new LiveData(new LiveData(0)); + const flatten$ = wrapped$.flat(); + expect(flatten$.value).toBe(0); - wrapped.next(new LiveData(1)); - expect(flatten.value).toBe(1); + wrapped$.next(new LiveData(1)); + expect(flatten$.value).toBe(1); - wrapped.next(LiveData.from(of(2, 3), 0)); - expect(flatten.value).toBe(3); + wrapped$.next(LiveData.from(of(2, 3), 0)); + expect(flatten$.value).toBe(3); } { - const wrapped = new LiveData( + const wrapped$ = new LiveData( new LiveData([ new LiveData(new LiveData(1)), new LiveData(new LiveData(2)), ]) ); - const flatten = wrapped.flat(); - expect(flatten.value).toStrictEqual([1, 2]); + const flatten$ = wrapped$.flat(); + expect(flatten$.value).toStrictEqual([1, 2]); } { - const wrapped = new LiveData([new LiveData(0), new LiveData(1)]); - const flatten = wrapped.flat(); + const wrapped$ = new LiveData([new LiveData(0), new LiveData(1)]); + const flatten$ = wrapped$.flat(); - expect(flatten.value).toEqual([0, 1]); + expect(flatten$.value).toEqual([0, 1]); - const inner = new LiveData(2); - wrapped.next([inner, new LiveData(3)]); - expect(flatten.value).toEqual([2, 3]); - inner.next(4); - expect(flatten.value).toEqual([4, 3]); + const inner$ = new LiveData(2); + wrapped$.next([inner$, new LiveData(3)]); + expect(flatten$.value).toEqual([2, 3]); + inner$.next(4); + expect(flatten$.value).toEqual([4, 3]); } }); test('computed', () => { { - const a = new LiveData(1); - const b = LiveData.computed(get => get(a) + 1); - expect(b.value).toBe(2); + const a$ = new LiveData(1); + const b$ = LiveData.computed(get => get(a$) + 1); + expect(b$.value).toBe(2); } { - const a = new LiveData('v1'); - const v1 = new LiveData(100); - const v2 = new LiveData(200); + const a$ = new LiveData('v1'); + const v1$ = new LiveData(100); + const v2$ = new LiveData(200); - const v = LiveData.computed(get => { - return get(a) === 'v1' ? get(v1) : get(v2); + const v$ = LiveData.computed(get => { + return get(a$) === 'v1' ? get(v1$) : get(v2$); }); - expect(v.value).toBe(100); + expect(v$.value).toBe(100); - a.next('v2'); - expect(v.value).toBe(200); + a$.next('v2'); + expect(v$.value).toBe(200); } { let watched = false; let count = 0; let subscriber: Subscriber = null!; - const a = LiveData.from( + const a$ = LiveData.from( new Observable(sub => { count++; watched = true; @@ -303,16 +303,16 @@ describe('livedata', () => { }), 0 ); - const b = LiveData.computed(get => get(a) + 1); + const b$ = LiveData.computed(get => get(a$) + 1); expect(watched).toBe(false); expect(count).toBe(0); - const subscription = b.subscribe(_ => {}); + const subscription = b$.subscribe(_ => {}); expect(watched).toBe(true); expect(count).toBe(1); subscriber.next(2); - expect(b.value).toBe(3); + expect(b$.value).toBe(3); subscription.unsubscribe(); expect(watched).toBe(false); @@ -320,11 +320,11 @@ describe('livedata', () => { } { - let c = null! as LiveData; - const b = LiveData.computed(get => get(c) + 1); - c = LiveData.computed(get => get(b) + 1); + let c$ = null! as LiveData; + const b$ = LiveData.computed(get => get(c$) + 1); + c$ = LiveData.computed(get => get(b$) + 1); - expect(() => b.value).toThrowError(PoisonedError); + expect(() => b$.value).toThrowError(PoisonedError); } }); }); diff --git a/packages/common/infra/src/livedata/__tests__/react.spec.tsx b/packages/common/infra/src/livedata/__tests__/react.spec.tsx index 74e9ff25bd..cfe13a736f 100644 --- a/packages/common/infra/src/livedata/__tests__/react.spec.tsx +++ b/packages/common/infra/src/livedata/__tests__/react.spec.tsx @@ -10,11 +10,11 @@ import { LiveData, useLiveData } from '..'; describe('livedata', () => { test('react', () => { - const livedata = new LiveData(0); + const livedata$ = new LiveData(0); const Component = () => { const renderCount = useRef(0); renderCount.current++; - const value = useLiveData(livedata); + const value = useLiveData(livedata$); return (
{renderCount.current}:{value} @@ -23,7 +23,7 @@ describe('livedata', () => { }; const { rerender } = render(); expect(screen.getByRole('main').innerText).toBe('1:0'); - livedata.next(1); + livedata$.next(1); rerender(); expect(screen.getByRole('main').innerText).toBe('3:1'); }); @@ -31,7 +31,7 @@ describe('livedata', () => { test('lifecycle', async () => { let observableSubscribed = false; let observableClosed = false; - const observable = new Observable(subscriber => { + const observable$ = new Observable(subscriber => { observableSubscribed = true; subscriber.next(1); console.log(1); @@ -40,9 +40,9 @@ describe('livedata', () => { }; }); - const livedata = LiveData.from(observable, 0); + const livedata$ = LiveData.from(observable$, 0); const Component1 = () => { - const value = useLiveData(livedata); + const value = useLiveData(livedata$); return
{value}
; }; diff --git a/packages/common/infra/src/livedata/index.ts b/packages/common/infra/src/livedata/index.ts index 06524dc4cf..e04479769f 100644 --- a/packages/common/infra/src/livedata/index.ts +++ b/packages/common/infra/src/livedata/index.ts @@ -14,6 +14,7 @@ import { skip, type Subscription, switchMap, + type TeardownLogic, } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs'; @@ -78,20 +79,23 @@ const logger = new DebugLogger('livedata'); * @see {@link https://rxjs.dev/api/index/class/BehaviorSubject} * @see {@link https://developer.android.com/topic/libraries/architecture/livedata} */ -export class LiveData implements InteropObservable { +export class LiveData + extends Observable + implements InteropObservable +{ static from( - upstream: + upstream$: | Observable | InteropObservable | ((stream: Observable) => Observable), initialValue: T ): LiveData { - const data = new LiveData( + const data$ = new LiveData( initialValue, - typeof upstream === 'function' - ? upstream - : stream => - stream.pipe( + typeof upstream$ === 'function' + ? upstream$ + : stream$ => + stream$.pipe( filter( (op): op is Exclude => op !== 'set' ), @@ -121,7 +125,7 @@ export class LiveData implements InteropObservable { distinctUntilChanged(), switchMap(op => { if (op === 'watch') { - return upstream; + return upstream$; } else { return EMPTY; } @@ -129,7 +133,7 @@ export class LiveData implements InteropObservable { ) ); - return data; + return data$; } private static GLOBAL_COMPUTED_RECURSIVE_COUNT = 0; @@ -155,11 +159,11 @@ export class LiveData implements InteropObservable { new Observable(subscribe => { const execute = (next: () => void) => { const subscriptions: Subscription[] = []; - const getfn = (data: LiveData) => { + const getfn = (data$: LiveData) => { let value = null as L; let first = true; subscriptions.push( - data.subscribe({ + data$.subscribe({ error(err) { subscribe.error(err); }, @@ -212,8 +216,8 @@ export class LiveData implements InteropObservable { ); } - private readonly raw: BehaviorSubject; - private readonly ops = new Subject(); + private readonly raw$: BehaviorSubject; + private readonly ops$ = new Subject(); private readonly upstreamSubscription: Subscription | undefined; /** @@ -232,14 +236,15 @@ export class LiveData implements InteropObservable { | ((upstream: Observable) => Observable) | undefined = undefined ) { - this.raw = new BehaviorSubject(initialValue); + super(); + this.raw$ = new BehaviorSubject(initialValue); if (upstream) { - this.upstreamSubscription = upstream(this.ops).subscribe({ + this.upstreamSubscription = upstream(this.ops$).subscribe({ next: v => { - this.raw.next(v); + this.raw$.next(v); }, complete: () => { - if (!this.raw.closed) { + if (!this.raw$.closed) { logger.error('livedata upstream unexpected complete'); } }, @@ -247,7 +252,7 @@ export class LiveData implements InteropObservable { logger.error('uncatched error in livedata', err); this.isPoisoned = true; this.poisonedError = new PoisonedError(err); - this.raw.error(this.poisonedError); + this.raw$.error(this.poisonedError); }, }); } @@ -257,16 +262,16 @@ export class LiveData implements InteropObservable { if (this.isPoisoned) { throw this.poisonedError; } - this.ops.next('get'); - return this.raw.value; + this.ops$.next('get'); + return this.raw$.value; } setValue(v: T) { if (this.isPoisoned) { throw this.poisonedError; } - this.raw.next(v); - this.ops.next('set'); + this.raw$.next(v); + this.ops$.next('set'); } get value(): T { @@ -284,66 +289,81 @@ export class LiveData implements InteropObservable { this.setValue(v); } - subscribe( - observer?: Partial> | ((value: T) => void) | undefined + override subscribe( + observerOrNext?: Partial> | ((value: T) => void) + ): Subscription; + override subscribe( + next?: ((value: T) => void) | null, + error?: ((error: any) => void) | null, + complete?: (() => void) | null + ): Subscription; + override subscribe( + observerOrNext?: Partial> | ((value: T) => void) | null, + error?: ((error: any) => void) | null, + complete?: (() => void) | null ): Subscription { - this.ops.next('watch'); - const subscription = this.raw.subscribe(observer); + this.ops$.next('watch'); + const subscription = this.raw$.subscribe( + observerOrNext as any, + error, + complete + ); subscription.add(() => { - this.ops.next('unwatch'); + this.ops$.next('unwatch'); }); return subscription; } - map(mapper: (v: T) => R) { - const sub = LiveData.from( + map(mapper: (v: T) => R): LiveData { + const sub$ = LiveData.from( new Observable(subscriber => this.subscribe({ next: v => { subscriber.next(mapper(v)); }, complete: () => { - sub.complete(); + sub$.complete(); }, }) ), undefined as R // is safe ); - return sub; + return sub$; } + // eslint-disable-next-line rxjs/finnish asObservable(): Observable { return new Observable(subscriber => { return this.subscribe(subscriber); }); } - pipe(): Observable; - pipe(op1: OperatorFunction): Observable; - pipe( + override pipe(): Observable; + override pipe(op1: OperatorFunction): Observable; + override pipe( op1: OperatorFunction, op2: OperatorFunction ): Observable; - pipe( + override pipe( op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction ): Observable; - pipe( + override pipe( op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction ): Observable; - pipe( + override pipe( op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, op4: OperatorFunction, op5: OperatorFunction ): Observable; - pipe( + override pipe( op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction, @@ -351,23 +371,23 @@ export class LiveData implements InteropObservable { op5: OperatorFunction, op6: OperatorFunction ): Observable; - pipe(...args: any[]) { + override pipe(...args: any[]) { return new Observable(subscriber => { - this.ops.next('watch'); + this.ops$.next('watch'); // eslint-disable-next-line prefer-spread - const subscription = this.raw.pipe - .apply(this.raw, args as any) + const subscription = this.raw$.pipe + .apply(this.raw$, args as any) .subscribe(subscriber); subscription.add(() => { - this.ops.next('unwatch'); + this.ops$.next('unwatch'); }); return subscription; }); } complete() { - this.ops.complete(); - this.raw.complete(); + this.ops$.complete(); + this.raw$.complete(); this.upstreamSubscription?.unsubscribe(); } @@ -411,12 +431,12 @@ export class LiveData implements InteropObservable { if (this.isPoisoned) { throw this.poisonedError; } - this.ops.next('watch'); - const subscription = this.raw + this.ops$.next('watch'); + const subscription = this.raw$ .pipe(distinctUntilChanged(), skip(1)) .subscribe(cb); subscription.add(() => { - this.ops.next('unwatch'); + this.ops$.next('unwatch'); }); return () => subscription.unsubscribe(); }; @@ -425,13 +445,17 @@ export class LiveData implements InteropObservable { if (this.isPoisoned) { throw this.poisonedError; } - this.ops.next('watch'); + this.ops$.next('watch'); setImmediate(() => { - this.ops.next('unwatch'); + this.ops$.next('unwatch'); }); - return this.raw.value; + return this.raw$.value; }; + protected _subscribe(): TeardownLogic { + throw new Error('Method not implemented.'); + } + [Symbol.observable || '@@observable']() { return this; } diff --git a/packages/common/infra/src/livedata/react.ts b/packages/common/infra/src/livedata/react.ts index b6aa5a50a8..153f384704 100644 --- a/packages/common/infra/src/livedata/react.ts +++ b/packages/common/infra/src/livedata/react.ts @@ -40,13 +40,13 @@ export function useLiveData | null | undefined>( /** * subscribe LiveData and return the value. If the value is nullish, will suspends until the value is not nullish. */ -export function useEnsureLiveData(liveData: LiveData): NonNullable { - const data = useLiveData(liveData); +export function useEnsureLiveData(liveData$: LiveData): NonNullable { + const data = useLiveData(liveData$); if (data === null || data === undefined) { return use( new Promise((resolve, reject) => { - const subscription = liveData.subscribe({ + const subscription = liveData$.subscribe({ next(value) { if (value === null || value === undefined) { resolve(value); diff --git a/packages/common/infra/src/page/manager.ts b/packages/common/infra/src/page/manager.ts index c5ff670549..9d8d6c314f 100644 --- a/packages/common/infra/src/page/manager.ts +++ b/packages/common/infra/src/page/manager.ts @@ -16,7 +16,7 @@ export class PageManager { ) {} open(pageId: string) { - const pageRecord = this.pageRecordList.record(pageId).value; + const pageRecord = this.pageRecordList.record$(pageId).value; if (!pageRecord) { throw new Error('Page record not found'); } diff --git a/packages/common/infra/src/page/page.ts b/packages/common/infra/src/page/page.ts index d291624393..49ce5fec11 100644 --- a/packages/common/infra/src/page/page.ts +++ b/packages/common/infra/src/page/page.ts @@ -14,9 +14,9 @@ export class Doc { return this.record.id; } - readonly mete = this.record.meta; - readonly mode = this.record.mode; - readonly title = this.record.title; + readonly mete$ = this.record.meta$; + readonly mode$ = this.record.mode$; + readonly title$ = this.record.title$; setMode(mode: PageMode) { this.record.setMode(mode); diff --git a/packages/common/infra/src/page/record-list.ts b/packages/common/infra/src/page/record-list.ts index fee4cb6325..79a4b461c2 100644 --- a/packages/common/infra/src/page/record-list.ts +++ b/packages/common/infra/src/page/record-list.ts @@ -11,7 +11,7 @@ export class PageRecordList { private readonly localState: WorkspaceLocalState ) {} - public readonly records = LiveData.from( + public readonly records$ = LiveData.from( new Observable(subscriber => { const emit = () => { subscriber.next( @@ -35,11 +35,11 @@ export class PageRecordList { [] ); - public readonly isReady = this.workspace.engine.rootDocState.map( + public readonly isReady$ = this.workspace.engine.rootDocState$.map( state => !state.syncing ); - public record(id: string) { - return this.records.map(record => record.find(record => record.id === id)); + public record$(id: string) { + return this.records$.map(record => record.find(record => record.id === id)); } } diff --git a/packages/common/infra/src/page/record.ts b/packages/common/infra/src/page/record.ts index b3276b5b76..b117ef3245 100644 --- a/packages/common/infra/src/page/record.ts +++ b/packages/common/infra/src/page/record.ts @@ -13,7 +13,7 @@ export class PageRecord { private readonly localState: WorkspaceLocalState ) {} - meta = LiveData.from( + meta$ = LiveData.from( new Observable(subscriber => { const emit = () => { const meta = this.workspace.docCollection.meta.docMetas.find( @@ -45,7 +45,7 @@ export class PageRecord { this.workspace.docCollection.setDocMeta(this.id, meta); } - mode: LiveData = LiveData.from( + mode$: LiveData = LiveData.from( this.localState.watch(`page:${this.id}:mode`), 'page' ).map(mode => (mode === 'edgeless' ? 'edgeless' : 'page')); @@ -55,9 +55,9 @@ export class PageRecord { } toggleMode() { - this.setMode(this.mode.value === 'edgeless' ? 'page' : 'edgeless'); - return this.mode.value; + this.setMode(this.mode$.value === 'edgeless' ? 'page' : 'edgeless'); + return this.mode$.value; } - title = this.meta.map(meta => meta.title); + title$ = this.meta$.map(meta => meta.title); } diff --git a/packages/common/infra/src/storage/memento.ts b/packages/common/infra/src/storage/memento.ts index 0dc6b3aabb..c59c9ccbb5 100644 --- a/packages/common/infra/src/storage/memento.ts +++ b/packages/common/infra/src/storage/memento.ts @@ -40,12 +40,12 @@ export class MemoryMemento implements Memento { private readonly data = new Map>(); private getLiveData(key: string): LiveData { - let data = this.data.get(key); - if (!data) { - data = new LiveData(null); - this.data.set(key, data); + let data$ = this.data.get(key); + if (!data$) { + data$ = new LiveData(null); + this.data.set(key, data$); } - return data; + return data$; } get(key: string): T | null { diff --git a/packages/common/infra/src/workspace/__tests__/workspace.spec.ts b/packages/common/infra/src/workspace/__tests__/workspace.spec.ts index 1a1182ba1f..d168055fb4 100644 --- a/packages/common/infra/src/workspace/__tests__/workspace.spec.ts +++ b/packages/common/infra/src/workspace/__tests__/workspace.spec.ts @@ -14,13 +14,13 @@ describe('Workspace System', () => { const provider = services.provider(); const workspaceManager = provider.get(WorkspaceManager); const workspaceListService = provider.get(WorkspaceListService); - expect(workspaceListService.workspaceList.value.length).toBe(0); + expect(workspaceListService.workspaceList$.value.length).toBe(0); const { workspace } = workspaceManager.open( await workspaceManager.createWorkspace(WorkspaceFlavour.LOCAL) ); - expect(workspaceListService.workspaceList.value.length).toBe(1); + expect(workspaceListService.workspaceList$.value.length).toBe(1); const page = workspace.docCollection.createDoc({ id: 'page0', diff --git a/packages/common/infra/src/workspace/engine/doc/index.ts b/packages/common/infra/src/workspace/engine/doc/index.ts index 09316f7086..506db43d9c 100644 --- a/packages/common/infra/src/workspace/engine/doc/index.ts +++ b/packages/common/infra/src/workspace/engine/doc/index.ts @@ -32,10 +32,10 @@ export class DocEngine { storage: DocStorageInner; - engineState = LiveData.computed(get => { - const localState = get(this.localPart.engineState); + engineState$ = LiveData.computed(get => { + const localState = get(this.localPart.engineState$); if (this.remotePart) { - const remoteState = get(this.remotePart?.engineState); + const remoteState = get(this.remotePart?.engineState$); return { total: remoteState.total, syncing: remoteState.syncing, @@ -53,12 +53,12 @@ export class DocEngine { }; }); - docState(docId: string) { - const localState = this.localPart.docState(docId); - const remoteState = this.remotePart?.docState(docId); + docState$(docId: string) { + const localState$ = this.localPart.docState$(docId); + const remoteState$ = this.remotePart?.docState$(docId); return LiveData.computed(get => { - const local = get(localState); - const remote = remoteState ? get(remoteState) : null; + const local = get(localState$); + const remote = remoteState$ ? get(remoteState$) : null; return { ready: local.ready, saving: local.syncing, @@ -134,7 +134,7 @@ export class DocEngine { */ waitForSaved() { return new Promise(resolve => { - this.engineState + this.engineState$ .pipe(map(state => state.saving === 0)) .subscribe(saved => { if (saved) { @@ -150,7 +150,7 @@ export class DocEngine { */ waitForSynced() { return new Promise(resolve => { - this.engineState + this.engineState$ .pipe(map(state => state.syncing === 0 && state.saving === 0)) .subscribe(synced => { if (synced) { @@ -175,7 +175,7 @@ export class DocEngine { */ waitForReady(docId: string) { return new Promise(resolve => { - this.docState(docId) + this.docState$(docId) .pipe(map(state => state.ready)) .subscribe(ready => { if (ready) { diff --git a/packages/common/infra/src/workspace/engine/doc/local.ts b/packages/common/infra/src/workspace/engine/doc/local.ts index 3e07ee82bc..31c3f4df64 100644 --- a/packages/common/infra/src/workspace/engine/doc/local.ts +++ b/packages/common/infra/src/workspace/engine/doc/local.ts @@ -48,7 +48,7 @@ export interface LocalDocState { */ export class DocEngineLocalPart { private readonly prioritySettings = new Map(); - private readonly statusUpdatedSubject = new Subject(); + private readonly statusUpdatedSubject$ = new Subject(); private readonly status = { docs: new Map(), @@ -59,7 +59,7 @@ export class DocEngineLocalPart { currentJob: null as { docId: string; jobs: Job[] } | null, }; - engineState = LiveData.from( + engineState$ = LiveData.from( new Observable(subscribe => { const next = () => { subscribe.next({ @@ -68,14 +68,14 @@ export class DocEngineLocalPart { }); }; next(); - return this.statusUpdatedSubject.subscribe(() => { + return this.statusUpdatedSubject$.subscribe(() => { next(); }); }), { syncing: 0, total: 0 } ); - docState(docId: string) { + docState$(docId: string) { return LiveData.from( new Observable(subscribe => { const next = () => { @@ -87,7 +87,7 @@ export class DocEngineLocalPart { }); }; next(); - return this.statusUpdatedSubject.subscribe(updatedId => { + return this.statusUpdatedSubject$.subscribe(updatedId => { if (updatedId === docId) next(); }); }), @@ -120,7 +120,7 @@ export class DocEngineLocalPart { } this.status.currentJob = { docId, jobs }; - this.statusUpdatedSubject.next(docId); + this.statusUpdatedSubject$.next(docId); const { apply, load, save } = groupBy(jobs, job => job.type) as { [key in Job['type']]?: Job[]; @@ -139,7 +139,7 @@ export class DocEngineLocalPart { } this.status.currentJob = null; - this.statusUpdatedSubject.next(docId); + this.statusUpdatedSubject$.next(docId); } } finally { dispose(); @@ -161,7 +161,7 @@ export class DocEngineLocalPart { }); this.status.docs.set(doc.guid, doc); - this.statusUpdatedSubject.next(doc.guid); + this.statusUpdatedSubject$.next(doc.guid); }, }; @@ -186,7 +186,7 @@ export class DocEngineLocalPart { doc.on('update', this.handleDocUpdate); this.status.connectedDocs.add(job.docId); - this.statusUpdatedSubject.next(job.docId); + this.statusUpdatedSubject$.next(job.docId); const docData = await this.storage.loadDocFromLocal(job.docId, signal); @@ -196,7 +196,7 @@ export class DocEngineLocalPart { this.applyUpdate(job.docId, docData); this.status.readyDocs.add(job.docId); - this.statusUpdatedSubject.next(job.docId); + this.statusUpdatedSubject$.next(job.docId); }, save: async ( docId: string, @@ -292,7 +292,7 @@ export class DocEngineLocalPart { const existingJobs = this.status.jobMap.get(job.docId) ?? []; existingJobs.push(job); this.status.jobMap.set(job.docId, existingJobs); - this.statusUpdatedSubject.next(job.docId); + this.statusUpdatedSubject$.next(job.docId); } setPriority(docId: string, priority: number) { diff --git a/packages/common/infra/src/workspace/engine/doc/remote.ts b/packages/common/infra/src/workspace/engine/doc/remote.ts index 6869bec411..c336ff4f08 100644 --- a/packages/common/infra/src/workspace/engine/doc/remote.ts +++ b/packages/common/infra/src/workspace/engine/doc/remote.ts @@ -81,9 +81,9 @@ export class DocEngineRemotePart { retrying: false, errorMessage: null, }; - private readonly statusUpdatedSubject = new Subject(); + private readonly statusUpdatedSubject$ = new Subject(); - engineState = LiveData.from( + engineState$ = LiveData.from( new Observable(subscribe => { const next = () => { if (!this.status.syncing) { @@ -103,7 +103,7 @@ export class DocEngineRemotePart { }); }; next(); - return this.statusUpdatedSubject.subscribe(() => { + return this.statusUpdatedSubject$.subscribe(() => { next(); }); }), @@ -115,7 +115,7 @@ export class DocEngineRemotePart { } ); - docState(docId: string) { + docState$(docId: string) { return LiveData.from( new Observable(subscribe => { const next = () => { @@ -126,7 +126,7 @@ export class DocEngineRemotePart { }); }; next(); - return this.statusUpdatedSubject.subscribe(updatedId => { + return this.statusUpdatedSubject$.subscribe(updatedId => { if (updatedId === true || updatedId === docId) next(); }); }), @@ -152,7 +152,7 @@ export class DocEngineRemotePart { } this.status.connectedDocs.add(docId); - this.statusUpdatedSubject.next(docId); + this.statusUpdatedSubject$.next(docId); }, push: async ( docId: string, @@ -321,7 +321,7 @@ export class DocEngineRemotePart { addDoc: (docId: string) => { if (!this.status.docs.has(docId)) { this.status.docs.add(docId); - this.statusUpdatedSubject.next(docId); + this.statusUpdatedSubject$.next(docId); this.schedule({ type: 'connect', docId, @@ -359,7 +359,7 @@ export class DocEngineRemotePart { logger.error('Remote sync error, retry in 5s', err); this.status.errorMessage = err instanceof Error ? err.message : `${err}`; - this.statusUpdatedSubject.next(true); + this.statusUpdatedSubject$.next(true); } finally { this.status = { docs: this.status.docs, @@ -371,7 +371,7 @@ export class DocEngineRemotePart { retrying: true, errorMessage: this.status.errorMessage, }; - this.statusUpdatedSubject.next(true); + this.statusUpdatedSubject$.next(true); } await Promise.race([ new Promise(resolve => { @@ -420,7 +420,7 @@ export class DocEngineRemotePart { logger.info('Remote sync started'); this.status.syncing = true; - this.statusUpdatedSubject.next(true); + this.statusUpdatedSubject$.next(true); this.server.onInterrupted(reason => { abort.abort(reason); @@ -471,7 +471,7 @@ export class DocEngineRemotePart { const jobs = this.status.jobMap.get(docId); if (!jobs || jobs.length === 0) { this.status.jobMap.delete(docId); - this.statusUpdatedSubject.next(docId); + this.statusUpdatedSubject$.next(docId); break; } @@ -535,7 +535,7 @@ export class DocEngineRemotePart { const existingJobs = this.status.jobMap.get(job.docId) ?? []; existingJobs.push(job); this.status.jobMap.set(job.docId, existingJobs); - this.statusUpdatedSubject.next(job.docId); + this.statusUpdatedSubject$.next(job.docId); } setPriority(docId: string, priority: number) { diff --git a/packages/common/infra/src/workspace/engine/index.ts b/packages/common/infra/src/workspace/engine/index.ts index 0d90f23abe..50b8b46d34 100644 --- a/packages/common/infra/src/workspace/engine/index.ts +++ b/packages/common/infra/src/workspace/engine/index.ts @@ -52,7 +52,7 @@ export class WorkspaceEngine { } canGracefulStop() { - return this.doc.engineState.value.saving === 0; + return this.doc.engineState$.value.saving === 0; } async waitForGracefulStop(abort?: AbortSignal) { @@ -67,9 +67,9 @@ export class WorkspaceEngine { this.blob.stop(); } - docEngineState = this.doc.engineState; + docEngineState$ = this.doc.engineState$; - rootDocState = this.doc.docState(this.yDoc.guid); + rootDocState$ = this.doc.docState$(this.yDoc.guid); waitForSynced() { return this.doc.waitForSynced(); diff --git a/packages/common/infra/src/workspace/list/index.ts b/packages/common/infra/src/workspace/list/index.ts index 3c90a7fa50..7963052d59 100644 --- a/packages/common/infra/src/workspace/list/index.ts +++ b/packages/common/infra/src/workspace/list/index.ts @@ -86,18 +86,18 @@ export class WorkspaceListService { WorkspaceInformation >(); - status = new LiveData({ + status$ = new LiveData({ loading: true, workspaceList: [], }); setStatus(status: WorkspaceListStatus) { - this.status.next(status); + this.status$.next(status); // update cache writeWorkspaceListCache(this.cache, status.workspaceList); } - workspaceList = this.status.map(x => x.workspaceList); + workspaceList$ = this.status$.map(x => x.workspaceList); constructor( private readonly providers: WorkspaceListProvider[], @@ -106,8 +106,8 @@ export class WorkspaceListService { // initialize workspace list from cache const cached = readWorkspaceListCache(cache); const workspaceList = cached; - this.status.next({ - ...this.status.value, + this.status$.next({ + ...this.status$.value, workspaceList, }); @@ -134,7 +134,7 @@ export class WorkspaceListService { } const metadata = await provider.create(initial); // update workspace list - this.setStatus(this.addWorkspace(this.status.value, metadata)); + this.setStatus(this.addWorkspace(this.status$.value, metadata)); return metadata; } @@ -157,7 +157,7 @@ export class WorkspaceListService { await provider.delete(workspaceMetadata.id); // delete workspace from list - this.setStatus(this.deleteWorkspace(this.status.value, workspaceMetadata)); + this.setStatus(this.deleteWorkspace(this.status$.value, workspaceMetadata)); } /** @@ -201,7 +201,7 @@ export class WorkspaceListService { added?: WorkspaceMetadata[]; deleted?: WorkspaceMetadata[]; }) { - let status = this.status.value; + let status = this.status$.value; for (const added of changed.added ?? []) { status = this.addWorkspace(status, added); @@ -239,7 +239,7 @@ export class WorkspaceListService { }) .finally(() => { this.setStatus({ - ...this.status.value, + ...this.status$.value, loading: false, }); }); @@ -250,7 +250,7 @@ export class WorkspaceListService { this.providers.map(async provider => { try { const list = await provider.getList(); - const oldList = this.workspaceList.value.filter( + const oldList = this.workspaceList$.value.filter( w => w.flavour === provider.name ); this.handleWorkspaceChange({ diff --git a/packages/frontend/core/src/components/affine/affine-error-boundary/error-basic/info-logger.tsx b/packages/frontend/core/src/components/affine/affine-error-boundary/error-basic/info-logger.tsx index de0cc65eaf..4510fc8249 100644 --- a/packages/frontend/core/src/components/affine/affine-error-boundary/error-basic/info-logger.tsx +++ b/packages/frontend/core/src/components/affine/affine-error-boundary/error-basic/info-logger.tsx @@ -14,7 +14,7 @@ export const DumpInfo = (_props: DumpInfoProps) => { const location = useLocation(); const workspaceList = useService(WorkspaceListService); const currentWorkspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); const path = location.pathname; const query = useParams(); diff --git a/packages/frontend/core/src/components/affine/awareness/index.tsx b/packages/frontend/core/src/components/affine/awareness/index.tsx index 4c9d8df2f9..45d4d5980a 100644 --- a/packages/frontend/core/src/components/affine/awareness/index.tsx +++ b/packages/frontend/core/src/components/affine/awareness/index.tsx @@ -9,7 +9,7 @@ import { CurrentWorkspaceService } from '../../../modules/workspace/current-work const SyncAwarenessInnerLoggedIn = () => { const { user } = useSession(); const currentWorkspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); useEffect(() => { diff --git a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx index 87febfdaa4..70a89d755c 100644 --- a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx +++ b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx @@ -479,7 +479,7 @@ const PageHistoryManager = ({ ); const page = useService(Doc); - const [mode, setMode] = useState(page.mode.value); + const [mode, setMode] = useState(page.mode$.value); const title = useDocCollectionPageTitle(docCollection, pageId); diff --git a/packages/frontend/core/src/components/affine/page-properties/tags-inline-editor.tsx b/packages/frontend/core/src/components/affine/page-properties/tags-inline-editor.tsx index 6cb0c4b8c9..e6b0e6e67c 100644 --- a/packages/frontend/core/src/components/affine/page-properties/tags-inline-editor.tsx +++ b/packages/frontend/core/src/components/affine/page-properties/tags-inline-editor.tsx @@ -42,8 +42,8 @@ const InlineTagsList = ({ children, }: PropsWithChildren) => { const tagService = useService(TagService); - const tags = useLiveData(tagService.tags); - const tagIds = useLiveData(tagService.tagIdsByPageId(pageId)); + const tags = useLiveData(tagService.tags$); + const tagIds = useLiveData(tagService.tagIdsByPageId$(pageId)); return (
@@ -83,9 +83,9 @@ export const EditTagMenu = ({ const t = useAFFiNEI18N(); const legacyProperties = useService(WorkspaceLegacyProperties); const tagService = useService(TagService); - const tag = useLiveData(tagService.tagByTagId(tagId)); - const tagColor = useLiveData(tag?.color); - const tagValue = useLiveData(tag?.value); + const tag = useLiveData(tagService.tagByTagId$(tagId)); + const tagColor = useLiveData(tag?.color$); + const tagValue = useLiveData(tag?.value$); const navigate = useNavigateHelper(); const menuProps = useMemo(() => { @@ -135,11 +135,11 @@ export const EditTagMenu = ({ options.push('-'); options.push( - tagColors.map(([name, color]) => { + tagColors.map(([name, color], i) => { return { text: name, icon: ( -
+
{ const t = useAFFiNEI18N(); const tagService = useService(TagService); - const tags = useLiveData(tagService.tags); - const tagIds = useLiveData(tagService.tagIdsByPageId(pageId)); + const tags = useLiveData(tagService.tags$); + const tagIds = useLiveData(tagService.tagIdsByPageId$(pageId)); const [inputValue, setInputValue] = useState(''); const [open, setOpen] = useState(false); const [selectedTagIds, setSelectedTagIds] = useState([]); @@ -203,15 +203,11 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => { [setOpen, setSelectedTagIds] ); - const exactMatch = useLiveData(tagService.tagByTagValue(inputValue)); + const exactMatch = useLiveData(tagService.tagByTagValue$(inputValue)); - const filteredLiveData = useMemo(() => { - if (inputValue) { - return tagService.filterTagsByName(inputValue); - } - return tagService.tags; - }, [inputValue, tagService]); - const filteredTags = useLiveData(filteredLiveData); + const filteredTags = useLiveData( + inputValue ? tagService.filterTagsByName$(inputValue) : tagService.tags$ + ); const onInputChange = useCallback( (e: React.ChangeEvent) => { @@ -295,7 +291,7 @@ export const TagsEditor = ({ pageId, readonly }: TagsEditorProps) => { className={styles.tagSelectorItem} data-testid="tag-selector-item" data-tag-id={tag.id} - data-tag-value={tag.value} + data-tag-value={tag.value$} onClick={() => { onAddTag(tag.id); }} @@ -351,7 +347,7 @@ export const TagsInlineEditor = ({ className, }: TagsInlineEditorProps) => { const tagService = useService(TagService); - const tagIds = useLiveData(tagService.tagIdsByPageId(pageId)); + const tagIds = useLiveData(tagService.tagIdsByPageId$(pageId)); const empty = !tagIds || tagIds.length === 0; return ( { const workspaces = useLiveData( - useService(WorkspaceManager).list.workspaceList + useService(WorkspaceManager).list.workspaceList$ ); return ( <> diff --git a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/delete-leave-workspace/index.tsx b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/delete-leave-workspace/index.tsx index 59251420d2..70d95982b2 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/delete-leave-workspace/index.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/delete-leave-workspace/index.tsx @@ -34,7 +34,7 @@ export const DeleteLeaveWorkspace = ({ const setSettingModal = useSetAtom(openSettingModalAtom); const workspaceManager = useService(WorkspaceManager); - const workspaceList = useLiveData(workspaceManager.list.workspaceList); + const workspaceList = useLiveData(workspaceManager.list.workspaceList$); const currentWorkspace = useService(Workspace); const pushNotification = useSetAtom(pushNotificationAtom); diff --git a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/profile.tsx b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/profile.tsx index 7d57995ce8..4a22523bf5 100644 --- a/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/profile.tsx +++ b/packages/frontend/core/src/components/affine/setting-modal/workspace-setting/new-workspace-setting-detail/profile.tsx @@ -31,7 +31,7 @@ export const ProfilePanel = ({ isOwner, workspace }: ProfilePanelProps) => { const t = useAFFiNEI18N(); const pushNotification = useSetAtom(pushNotificationAtom); - const workspaceIsReady = useLiveData(workspace?.engine.rootDocState)?.ready; + const workspaceIsReady = useLiveData(workspace?.engine.rootDocState$)?.ready; const [avatarBlob, setAvatarBlob] = useState(null); const [name, setName] = useState(''); diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-export.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-export.tsx index 7e22856c7e..d52f7e504b 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-export.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-export.tsx @@ -26,7 +26,7 @@ export const ShareExport = ({ urlType: 'workspace', }); const exportHandler = useExportPage(currentPage); - const currentMode = useLiveData(page.mode); + const currentMode = useLiveData(page.mode$); return ( <> diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx index b0d03ba216..cc5f8efd6d 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx @@ -66,7 +66,7 @@ export const AffineSharePage = (props: ShareMenuProps) => { disableShare, } = useIsSharedPage(workspaceId, currentPage.id); - const currentPageMode = useLiveData(page.mode); + const currentPageMode = useLiveData(page.mode$); const defaultMode = useMemo(() => { if (isSharedPage) { diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx index d7568104e9..39df3a4b8c 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-header/menu/index.tsx @@ -55,7 +55,7 @@ export const PageHeaderMenuButton = ({ meta => meta.id === pageId ); const page = useService(Doc); - const currentMode = useLiveData(page.mode); + const currentMode = useLiveData(page.mode$); const { favorite, toggleFavorite } = useFavorite(pageId); diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx index 6f22e8eacc..d0d2b171be 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-mode-switch/index.tsx @@ -48,7 +48,7 @@ export const EditorModeSwitch = ({ const trash = pageMeta?.trash ?? false; const page = useService(Doc); - const currentMode = useLiveData(page.mode); + const currentMode = useLiveData(page.mode$); useEffect(() => { if (trash || isPublic) { diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx index afed76738d..f55a54c1e1 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-page-list/utils.tsx @@ -19,7 +19,7 @@ export const usePageHelper = (docCollection: DocCollection) => { const isPreferredEdgeless = useCallback( (pageId: string) => - pageRecordList.record(pageId).value?.mode.value === 'edgeless', + pageRecordList.record$(pageId).value?.mode$.value === 'edgeless', [pageRecordList] ); @@ -27,7 +27,7 @@ export const usePageHelper = (docCollection: DocCollection) => { (mode?: 'page' | 'edgeless') => { const page = createDoc(); initEmptyPage(page); - pageRecordList.record(page.id).value?.setMode(mode || 'page'); + pageRecordList.record$(page.id).value?.setMode(mode || 'page'); openPage(docCollection.id, page.id); return page; }, diff --git a/packages/frontend/core/src/components/page-detail-editor.tsx b/packages/frontend/core/src/components/page-detail-editor.tsx index 719d6110f7..625a3c7835 100644 --- a/packages/frontend/core/src/components/page-detail-editor.tsx +++ b/packages/frontend/core/src/components/page-detail-editor.tsx @@ -49,7 +49,7 @@ const PageDetailEditorMain = memo(function PageDetailEditorMain({ isPublic, publishMode, }: PageDetailEditorProps & { page: BlockSuiteDoc }) { - const currentMode = useLiveData(useService(Doc).mode); + const currentMode = useLiveData(useService(Doc).mode$); const mode = useMemo(() => { const shareMode = publishMode || currentMode; diff --git a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx index d44771f357..09760ca69d 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-list-header.tsx @@ -94,8 +94,8 @@ export const TagPageListHeader = ({ tag: Tag; workspaceId: string; }) => { - const tagColor = useLiveData(tag.color); - const tagTitle = useLiveData(tag.value); + const tagColor = useLiveData(tag.color$); + const tagTitle = useLiveData(tag.value$); const t = useAFFiNEI18N(); const { jumpToTags, jumpToCollection } = useNavigateHelper(); @@ -183,13 +183,9 @@ export const SwitchTag = ({ onClick }: SwitchTagProps) => { const t = useAFFiNEI18N(); const [inputValue, setInputValue] = useState(''); const tagService = useService(TagService); - const filteredLiveData = useMemo(() => { - if (inputValue) { - return tagService.filterTagsByName(inputValue); - } - return tagService.tags; - }, [inputValue, tagService]); - const filteredTags = useLiveData(filteredLiveData); + const filteredTags = useLiveData( + inputValue ? tagService.filterTagsByName$(inputValue) : tagService.tags$ + ); const onInputChange = useCallback( (e: React.ChangeEvent) => { @@ -238,8 +234,8 @@ export const SwitchTag = ({ onClick }: SwitchTagProps) => { }; const TagLink = ({ tag, onClick }: { tag: Tag; onClick: () => void }) => { - const tagColor = useLiveData(tag.color); - const tagTitle = useLiveData(tag.value); + const tagColor = useLiveData(tag.color$); + const tagTitle = useLiveData(tag.value$); return ( ) => { const tagsService = useService(TagService); - const tagsLiveData = tagsService.tagsByPageId(pageId); - const tags = useLiveData(tagsLiveData); + const tags = useLiveData(tagsService.tagsByPageId$(pageId)); return (
diff --git a/packages/frontend/core/src/components/page-list/docs/page-tags.tsx b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx index 550c2ac5aa..9009a93d1a 100644 --- a/packages/frontend/core/src/components/page-list/docs/page-tags.tsx +++ b/packages/frontend/core/src/components/page-list/docs/page-tags.tsx @@ -57,8 +57,8 @@ export const TagItem = ({ style, maxWidth, }: TagItemProps) => { - const value = useLiveData(tag?.value); - const color = useLiveData(tag?.color); + const value = useLiveData(tag?.value$); + const color = useLiveData(tag?.color$); const handleRemove: MouseEventHandler = useCallback( e => { e.stopPropagation(); @@ -112,13 +112,13 @@ const TagItemNormal = ({ return maxItems ? tags.slice(0, maxItems) : tags; }, [maxItems, tags]); - const tagsOrderedLiveData = useMemo(() => { - return LiveData.computed(get => - [...nTags].sort((a, b) => get(a.value).length - get(b.value).length) - ); - }, [nTags]); - - const tagsOrdered = useLiveData(tagsOrderedLiveData); + const tagsOrdered = useLiveData( + useMemo(() => { + return LiveData.computed(get => + [...nTags].sort((a, b) => get(a.value$).length - get(b.value$).length) + ); + }, [nTags]) + ); return useMemo( () => diff --git a/packages/frontend/core/src/components/page-list/page-group.tsx b/packages/frontend/core/src/components/page-list/page-group.tsx index bc66846d3f..1f4b105bd5 100644 --- a/packages/frontend/core/src/components/page-list/page-group.tsx +++ b/packages/frontend/core/src/components/page-list/page-group.tsx @@ -275,11 +275,11 @@ function tagIdToTagOption( const PageTitle = ({ id }: { id: string }) => { const page = useLiveData( - useService(PageRecordList).records.map(record => { + useService(PageRecordList).records$.map(record => { return record.find(p => p.id === id); }) ); - const title = useLiveData(page?.title); + const title = useLiveData(page?.title$); const t = useAFFiNEI18N(); return title || t['Untitled'](); }; diff --git a/packages/frontend/core/src/components/page-list/tags/create-tag.tsx b/packages/frontend/core/src/components/page-list/tags/create-tag.tsx index bf70506fbb..720cd27f4a 100644 --- a/packages/frontend/core/src/components/page-list/tags/create-tag.tsx +++ b/packages/frontend/core/src/components/page-list/tags/create-tag.tsx @@ -33,8 +33,8 @@ export const CreateOrEditTag = ({ tagMeta?: TagMeta; }) => { const tagService = useService(TagService); - const tagOptions = useLiveData(tagService.tagMetas); - const tag = useLiveData(tagService.tagByTagId(tagMeta?.id)); + const tagOptions = useLiveData(tagService.tagMetas$); + const tag = useLiveData(tagService.tagByTagId$(tagMeta?.id)); const t = useAFFiNEI18N(); const [menuOpen, setMenuOpen] = useState(false); diff --git a/packages/frontend/core/src/components/pure/cmdk/data-hooks.tsx b/packages/frontend/core/src/components/pure/cmdk/data-hooks.tsx index 07e0a31601..67d55f6dbe 100644 --- a/packages/frontend/core/src/components/pure/cmdk/data-hooks.tsx +++ b/packages/frontend/core/src/components/pure/cmdk/data-hooks.tsx @@ -107,8 +107,8 @@ export const pageToCommand = ( subTitle?: string, blockId?: string ): CMDKCommand => { - const pageMode = workspace.services.get(PageRecordList).record(page.id).value - ?.mode.value; + const pageMode = workspace.services.get(PageRecordList).record$(page.id).value + ?.mode$.value; const title = getPageTitle(page.id) || t['Untitled'](); const commandLabel = { @@ -320,7 +320,7 @@ export const collectionToCommand = ( export const useCollectionsCommands = () => { // todo: considering collections for searching pages const collectionService = useService(CollectionService); - const collections = useLiveData(collectionService.collections); + const collections = useLiveData(collectionService.collections$); const query = useAtomValue(cmdkQueryAtom); const navigationHelper = useNavigateHelper(); const t = useAFFiNEI18N(); @@ -356,7 +356,7 @@ export const useCMDKCommandGroups = () => { const collectionCommands = useCollectionsCommands(); const currentPage = useServiceOptional(Doc); - const currentPageMode = useLiveData(currentPage?.mode); + const currentPageMode = useLiveData(currentPage?.mode$); const affineCommands = useMemo(() => { return getAllCommand({ pageMode: currentPageMode, diff --git a/packages/frontend/core/src/components/pure/help-island/index.tsx b/packages/frontend/core/src/components/pure/help-island/index.tsx index 5fad3de39c..6959b92c78 100644 --- a/packages/frontend/core/src/components/pure/help-island/index.tsx +++ b/packages/frontend/core/src/components/pure/help-island/index.tsx @@ -30,7 +30,7 @@ const showList = environment.isDesktop ? DESKTOP_SHOW_LIST : DEFAULT_SHOW_LIST; export const HelpIsland = () => { const page = useServiceOptional(Doc); const pageId = page?.id; - const mode = useLiveData(page?.mode); + const mode = useLiveData(page?.mode$); const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom); const [spread, setShowSpread] = useState(false); const t = useAFFiNEI18N(); diff --git a/packages/frontend/core/src/components/pure/trash-page-footer/index.tsx b/packages/frontend/core/src/components/pure/trash-page-footer/index.tsx index 18c6c3cf6c..bb399aa12e 100644 --- a/packages/frontend/core/src/components/pure/trash-page-footer/index.tsx +++ b/packages/frontend/core/src/components/pure/trash-page-footer/index.tsx @@ -19,7 +19,7 @@ import * as styles from './styles.css'; export const TrashPageFooter = ({ pageId }: { pageId: string }) => { const workspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); assertExists(workspace); const docCollection = workspace.docCollection; diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx index 3fd422a882..98db52157b 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/collections-list.tsx @@ -89,7 +89,7 @@ const CollectionRenderer = ({ }; return filterPage(collection, pageData); }); - const location = useLiveData(useService(Workbench).location); + const location = useLiveData(useService(Workbench).location$); const currentPath = location.pathname; const path = `/collection/${collection.id}`; @@ -174,7 +174,7 @@ export const CollectionsList = ({ onCreate, }: CollectionsListProps) => { const metas = useBlockSuiteDocMeta(workspace); - const collections = useLiveData(useService(CollectionService).collections); + const collections = useLiveData(useService(CollectionService).collections$); const t = useAFFiNEI18N(); if (collections.length === 0) { return ( diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/page.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/page.tsx index 019c255097..a8fca7e7cf 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/page.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/collections/page.tsx @@ -36,8 +36,8 @@ export const Page = ({ const pageId = page.id; const active = params.pageId === pageId; - const pageRecord = useLiveData(useService(PageRecordList).record(pageId)); - const pageMode = useLiveData(pageRecord?.mode); + const pageRecord = useLiveData(useService(PageRecordList).record$(pageId)); + const pageMode = useLiveData(pageRecord?.mode$); const dragItemId = getDragItemId('collectionPage', pageId); const icon = useMemo(() => { diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/components/reference-page.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/components/reference-page.tsx index 2a187e67f4..67c3d1c698 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/components/reference-page.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/components/reference-page.tsx @@ -27,8 +27,8 @@ export const ReferencePage = ({ const params = useParams(); const active = params.pageId === pageId; - const pageRecord = useLiveData(useService(PageRecordList).record(pageId)); - const pageMode = useLiveData(pageRecord?.mode); + const pageRecord = useLiveData(useService(PageRecordList).record$(pageId)); + const pageMode = useLiveData(pageRecord?.mode$); const icon = useMemo(() => { return pageMode === 'edgeless' ? : ; }, [pageMode]); diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/favorite/favourite-page.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/favorite/favourite-page.tsx index e1894bbcaa..9d44e4bd61 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/favorite/favourite-page.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/favorite/favourite-page.tsx @@ -29,8 +29,8 @@ export const FavouritePage = ({ const params = useParams(); const active = params.pageId === pageId; const dragItemId = getDragItemId('favouritePage', pageId); - const pageRecord = useLiveData(useService(PageRecordList).record(pageId)); - const pageMode = useLiveData(pageRecord?.mode); + const pageRecord = useLiveData(useService(PageRecordList).record$(pageId)); + const pageMode = useLiveData(pageRecord?.mode$); const icon = useMemo(() => { return pageMode === 'edgeless' ? : ; diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx index 303db9826c..95d2fae480 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/index.tsx @@ -121,7 +121,7 @@ const UserWithWorkspaceListInner = ({ }, [onEventEnd, setOpenCreateWorkspaceModal]); const workspaceManager = useService(WorkspaceManager); - const workspaces = useLiveData(workspaceManager.list.workspaceList); + const workspaces = useLiveData(workspaceManager.list.workspaceList$); // revalidate workspace list when mounted useEffect(() => { diff --git a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/workspace-list/index.tsx b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/workspace-list/index.tsx index 23b3a90f12..51db030500 100644 --- a/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/workspace-list/index.tsx +++ b/packages/frontend/core/src/components/pure/workspace-slider-bar/user-with-workspace-list/workspace-list/index.tsx @@ -105,7 +105,7 @@ export const AFFiNEWorkspaceList = ({ onEventEnd?: () => void; }) => { const workspaces = useLiveData( - useService(WorkspaceManager).list.workspaceList + useService(WorkspaceManager).list.workspaceList$ ); const setOpenCreateWorkspaceModal = useSetAtom(openCreateWorkspaceModalAtom); @@ -113,7 +113,7 @@ export const AFFiNEWorkspaceList = ({ const { jumpToSubPath } = useNavigateHelper(); const currentWorkspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom); diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index f6adf8f8cb..6ddae61383 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -99,7 +99,7 @@ export const RootAppSidebar = ({ const { appSettings } = useAppSettingHelper(); const docCollection = currentWorkspace.docCollection; const t = useAFFiNEI18N(); - const currentPath = useLiveData(useService(Workbench).location).pathname; + const currentPath = useLiveData(useService(Workbench).location$).pathname; const onClickNewPage = useAsyncCallback(async () => { const page = createPage(); diff --git a/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts b/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts index d38d66e6e7..cc48ca589b 100644 --- a/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts +++ b/packages/frontend/core/src/hooks/affine/use-block-suite-meta-helper.ts @@ -111,7 +111,7 @@ export function useBlockSuiteMetaHelper(docCollection: DocCollection) { const duplicate = useAsyncCallback( async (pageId: string, openPageAfterDuplication: boolean = true) => { - const currentPageMode = pageRecordList.record(pageId).value?.mode.value; + const currentPageMode = pageRecordList.record$(pageId).value?.mode$.value; const currentPageMeta = getDocMeta(pageId); const newPage = createDoc(); const currentPage = docCollection.getDoc(pageId); @@ -137,7 +137,7 @@ export function useBlockSuiteMetaHelper(docCollection: DocCollection) { currentPageMeta.title.replace(lastDigitRegex, '') + `(${newNumber})`; pageRecordList - .record(newPage.id) + .record$(newPage.id) .value?.setMode(currentPageMode || 'page'); setDocTitle(newPage.id, newPageTitle); openPageAfterDuplication && openPage(docCollection.id, newPage.id); diff --git a/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx b/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx index ee4213e607..bffcd4a02c 100644 --- a/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx +++ b/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; export function useDocEngineStatus() { const workspace = useService(Workspace); - const engineState = useLiveData(workspace.engine.docEngineState); + const engineState = useLiveData(workspace.engine.docEngineState$); const progress = (engineState.total - engineState.syncing) / engineState.total; diff --git a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx index 17753fdd30..5c7ef90057 100644 --- a/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx +++ b/packages/frontend/core/src/hooks/affine/use-register-blocksuite-editor-commands.tsx @@ -21,7 +21,7 @@ import { useTrashModalHelper } from './use-trash-modal-helper'; export function useRegisterBlocksuiteEditorCommands() { const page = useService(Doc); const pageId = page.id; - const mode = useLiveData(page.mode); + const mode = useLiveData(page.mode$); const t = useAFFiNEI18N(); const workspace = useService(Workspace); const docCollection = workspace.docCollection; diff --git a/packages/frontend/core/src/layouts/workspace-layout.tsx b/packages/frontend/core/src/layouts/workspace-layout.tsx index c6d9e8afa7..c362a457fe 100644 --- a/packages/frontend/core/src/layouts/workspace-layout.tsx +++ b/packages/frontend/core/src/layouts/workspace-layout.tsx @@ -56,14 +56,14 @@ export const QuickSearch = () => { ); const workbench = useService(Workbench); - const currentPath = useLiveData(workbench.location.map(l => l.pathname)); + const currentPath = useLiveData(workbench.location$.map(l => l.pathname)); const pageRecordList = useService(PageRecordList); const currentPathId = matchPath('/:pageId', currentPath)?.params.pageId; // TODO: getting pageid from route is fragile, get current page from context const currentPage = useLiveData( - currentPathId ? pageRecordList.record(currentPathId) : null + currentPathId ? pageRecordList.record$(currentPathId) : null ); - const pageMeta = useLiveData(currentPage?.meta); + const pageMeta = useLiveData(currentPage?.meta$); return ( ; } - readonly collections = LiveData.from( + readonly collections$ = LiveData.from( new Observable(subscriber => { subscriber.next(this.collectionsYArray?.toArray() ?? []); const fn = () => { @@ -46,7 +46,7 @@ export class CollectionService { [] ); - readonly collectionsTrash = LiveData.from( + readonly collectionsTrash$ = LiveData.from( new Observable(subscriber => { subscriber.next(this.collectionsTrashYArray?.toArray() ?? []); const fn = () => { @@ -148,7 +148,7 @@ export class CollectionService { deletePagesFromCollections(ids: string[]) { const idSet = new Set(ids); this.doc.transact(() => { - this.collections.value.forEach(collection => { + this.collections$.value.forEach(collection => { this.deletePagesFromCollection(collection, idSet); }); }); diff --git a/packages/frontend/core/src/modules/infra-web/global-scope/index.tsx b/packages/frontend/core/src/modules/infra-web/global-scope/index.tsx index 6207e2ee2a..037d5adf14 100644 --- a/packages/frontend/core/src/modules/infra-web/global-scope/index.tsx +++ b/packages/frontend/core/src/modules/infra-web/global-scope/index.tsx @@ -16,7 +16,7 @@ export const GlobalScopeProvider: React.FC< }); const workspaceProvider = useLiveData( - currentWorkspaceService.currentWorkspace + currentWorkspaceService.currentWorkspace$ )?.services; return ( diff --git a/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx b/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx index c32a8292ea..2ccf41c48a 100644 --- a/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx +++ b/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx @@ -57,8 +57,8 @@ const PageItem = ({ className, ...attrs }: PageItemProps) => { - const title = useLiveData(pageRecord.title); - const mode = useLiveData(pageRecord.mode); + const title = useLiveData(pageRecord.title$); + const mode = useLiveData(pageRecord.mode$); const workspace = useService(Workspace); const { isJournal } = useJournalInfoHelper( workspace.docCollection, @@ -171,7 +171,7 @@ const sortPagesByDate = ( return [...pages].sort((a, b) => { return ( (order === 'asc' ? 1 : -1) * - dayjs(b.meta.value[field]).diff(dayjs(a.meta.value[field])) + dayjs(b.meta$.value[field]).diff(dayjs(a.meta$.value[field])) ); }); }; @@ -193,7 +193,7 @@ const JournalDailyCountBlock = ({ date }: JournalBlockProps) => { const t = useAFFiNEI18N(); const [activeItem, setActiveItem] = useState('createdToday'); const pageRecordList = useService(PageRecordList); - const pageRecords = useLiveData(pageRecordList.records); + const pageRecords = useLiveData(pageRecordList.records$); const navigateHelper = useNavigateHelper(); @@ -201,10 +201,10 @@ const JournalDailyCountBlock = ({ date }: JournalBlockProps) => { (field: 'createDate' | 'updatedDate') => { return sortPagesByDate( pageRecords.filter(pageRecord => { - if (pageRecord.meta.value.trash) return false; + if (pageRecord.meta$.value.trash) return false; return ( - pageRecord.meta.value[field] && - dayjs(pageRecord.meta.value[field]).isSame(date, 'day') + pageRecord.meta$.value[field] && + dayjs(pageRecord.meta$.value[field]).isSame(date, 'day') ); }), field @@ -321,7 +321,7 @@ const ConflictList = ({ setTrashModal({ open: true, pageIds: [pageRecord.id], - pageTitles: [pageRecord.meta.value.title], + pageTitles: [pageRecord.meta$.value.title], }); }, [setTrashModal] @@ -363,7 +363,7 @@ const JournalConflictBlock = ({ date }: JournalBlockProps) => { const pageRecordList = useService(PageRecordList); const journalHelper = useJournalHelper(workspace.docCollection); const docs = journalHelper.getJournalsByDate(date.format('YYYY-MM-DD')); - const pageRecords = useLiveData(pageRecordList.records).filter(v => { + const pageRecords = useLiveData(pageRecordList.records$).filter(v => { return docs.some(doc => doc.id === v.id); }); diff --git a/packages/frontend/core/src/modules/navigation/entities/navigator.ts b/packages/frontend/core/src/modules/navigation/entities/navigator.ts index b5e148e92e..32e8f8c68f 100644 --- a/packages/frontend/core/src/modules/navigation/entities/navigator.ts +++ b/packages/frontend/core/src/modules/navigation/entities/navigator.ts @@ -7,12 +7,12 @@ import type { Workbench } from '../../workbench'; export class Navigator { constructor(private readonly workbench: Workbench) {} - private readonly history = this.workbench.activeView.map( + private readonly history$ = this.workbench.activeView$.map( view => view.history ); - private readonly location = LiveData.from( - this.history.pipe( + private readonly location$ = LiveData.from( + this.history$.pipe( switchMap( history => new Observable<{ index: number; entries: Location[] }>(subscriber => { @@ -29,11 +29,11 @@ export class Navigator { { index: 0, entries: [] } ); - readonly backable = this.location.map( + readonly backable$ = this.location$.map( ({ index, entries }) => index > 0 && entries.length > 1 ); - readonly forwardable = this.location.map( + readonly forwardable$ = this.location$.map( ({ index, entries }) => index < entries.length - 1 ); @@ -41,7 +41,7 @@ export class Navigator { if (!environment.isDesktop) { window.history.back(); } else { - this.history.value.back(); + this.history$.value.back(); } } @@ -49,7 +49,7 @@ export class Navigator { if (!environment.isDesktop) { window.history.forward(); } else { - this.history.value.forward(); + this.history$.value.forward(); } } } diff --git a/packages/frontend/core/src/modules/navigation/view/navigation-buttons.tsx b/packages/frontend/core/src/modules/navigation/view/navigation-buttons.tsx index 2fc0b95857..f74b8693ac 100644 --- a/packages/frontend/core/src/modules/navigation/view/navigation-buttons.tsx +++ b/packages/frontend/core/src/modules/navigation/view/navigation-buttons.tsx @@ -33,8 +33,8 @@ export const NavigationButtons = () => { const navigator = useService(Navigator); - const backable = useLiveData(navigator.backable); - const forwardable = useLiveData(navigator.forwardable); + const backable = useLiveData(navigator.backable$); + const forwardable = useLiveData(navigator.forwardable$); const handleBack = useCallback(() => { navigator.back(); diff --git a/packages/frontend/core/src/modules/right-sidebar/entities/right-sidebar.ts b/packages/frontend/core/src/modules/right-sidebar/entities/right-sidebar.ts index 88dac9d7c2..7aa11aa857 100644 --- a/packages/frontend/core/src/modules/right-sidebar/entities/right-sidebar.ts +++ b/packages/frontend/core/src/modules/right-sidebar/entities/right-sidebar.ts @@ -7,22 +7,22 @@ const RIGHT_SIDEBAR_KEY = 'app:settings:rightsidebar'; export class RightSidebar { constructor(private readonly globalState: GlobalState) {} - readonly isOpen = LiveData.from( + readonly isOpen$ = LiveData.from( this.globalState.watch(RIGHT_SIDEBAR_KEY), false ).map(Boolean); - readonly views = new LiveData([]); - readonly front = this.views.map( + readonly views$ = new LiveData([]); + readonly front$ = this.views$.map( stack => stack[0] as RightSidebarView | undefined ); - readonly hasViews = this.views.map(stack => stack.length > 0); + readonly hasViews$ = this.views$.map(stack => stack.length > 0); open() { this._set(true); } toggle() { - this._set(!this.isOpen.value); + this._set(!this.isOpen$.value); } close() { @@ -37,15 +37,15 @@ export class RightSidebar { * @private use `RightSidebarViewIsland` instead */ _append(view: RightSidebarView) { - this.views.next([...this.views.value, view]); + this.views$.next([...this.views$.value, view]); } /** * @private use `RightSidebarViewIsland` instead */ _moveToFront(view: RightSidebarView) { - if (this.views.value.includes(view)) { - this.views.next([view, ...this.views.value.filter(v => v !== view)]); + if (this.views$.value.includes(view)) { + this.views$.next([view, ...this.views$.value.filter(v => v !== view)]); } } @@ -53,6 +53,6 @@ export class RightSidebar { * @private use `RightSidebarViewIsland` instead */ _remove(view: RightSidebarView) { - this.views.next(this.views.value.filter(v => v !== view)); + this.views$.next(this.views$.value.filter(v => v !== view)); } } diff --git a/packages/frontend/core/src/modules/right-sidebar/view/container.tsx b/packages/frontend/core/src/modules/right-sidebar/view/container.tsx index f27d5e7109..fc90949197 100644 --- a/packages/frontend/core/src/modules/right-sidebar/view/container.tsx +++ b/packages/frontend/core/src/modules/right-sidebar/view/container.tsx @@ -19,8 +19,8 @@ export const RightSidebarContainer = () => { const [resizing, setResizing] = useState(false); const rightSidebar = useService(RightSidebar); - const frontView = useLiveData(rightSidebar.front); - const open = useLiveData(rightSidebar.isOpen) && frontView !== undefined; + const frontView = useLiveData(rightSidebar.front$); + const open = useLiveData(rightSidebar.isOpen$) && frontView !== undefined; const [floating, setFloating] = useState(false); const appSidebarOpened = useAtomValue(appSidebarOpenAtom); diff --git a/packages/frontend/core/src/modules/tag/entities/tag.ts b/packages/frontend/core/src/modules/tag/entities/tag.ts index 6e49467dc0..7ae7c730e4 100644 --- a/packages/frontend/core/src/modules/tag/entities/tag.ts +++ b/packages/frontend/core/src/modules/tag/entities/tag.ts @@ -10,24 +10,24 @@ export class Tag { private readonly pageRecordList: PageRecordList ) {} - private readonly tagOption = this.properties.tagOptions$.map( + private readonly tagOption$ = this.properties.tagOptions$.map( tags => tags.find(tag => tag.id === this.id) as TagSchema ); - value = this.tagOption.map(tag => tag?.value || ''); + value$ = this.tagOption$.map(tag => tag?.value || ''); - color = this.tagOption.map(tag => tag?.color || ''); + color$ = this.tagOption$.map(tag => tag?.color || ''); - createDate = this.tagOption.map(tag => tag?.createDate || Date.now()); + createDate$ = this.tagOption$.map(tag => tag?.createDate || Date.now()); - updateDate = this.tagOption.map(tag => tag?.updateDate || Date.now()); + updateDate$ = this.tagOption$.map(tag => tag?.updateDate || Date.now()); rename(value: string) { this.properties.updateTagOption(this.id, { id: this.id, value, - color: this.color.value, - createDate: this.createDate.value, + color: this.color$.value, + createDate: this.createDate$.value, updateDate: Date.now(), }); } @@ -35,37 +35,37 @@ export class Tag { changeColor(color: string) { this.properties.updateTagOption(this.id, { id: this.id, - value: this.value.value, + value: this.value$.value, color, - createDate: this.createDate.value, + createDate: this.createDate$.value, updateDate: Date.now(), }); } tag(pageId: string) { - const pageRecord = this.pageRecordList.record(pageId).value; + const pageRecord = this.pageRecordList.record$(pageId).value; if (!pageRecord) { return; } pageRecord?.setMeta({ - tags: [...pageRecord.meta.value.tags, this.id], + tags: [...pageRecord.meta$.value.tags, this.id], }); } untag(pageId: string) { - const pageRecord = this.pageRecordList.record(pageId).value; + const pageRecord = this.pageRecordList.record$(pageId).value; if (!pageRecord) { return; } pageRecord?.setMeta({ - tags: pageRecord.meta.value.tags.filter(tagId => tagId !== this.id), + tags: pageRecord.meta$.value.tags.filter(tagId => tagId !== this.id), }); } - readonly pageIds = LiveData.computed(get => { - const pages = get(this.pageRecordList.records); + readonly pageIds$ = LiveData.computed(get => { + const pages = get(this.pageRecordList.records$); return pages - .filter(page => get(page.meta).tags.includes(this.id)) + .filter(page => get(page.meta$).tags.includes(this.id)) .map(page => page.id); }); } diff --git a/packages/frontend/core/src/modules/tag/service/tag.ts b/packages/frontend/core/src/modules/tag/service/tag.ts index 28c90f0ed2..e040747669 100644 --- a/packages/frontend/core/src/modules/tag/service/tag.ts +++ b/packages/frontend/core/src/modules/tag/service/tag.ts @@ -10,7 +10,7 @@ export class TagService { private readonly pageRecordList: PageRecordList ) {} - readonly tags = this.properties.tagOptions$.map(tags => + readonly tags$ = this.properties.tagOptions$.map(tags => tags.map(tag => new Tag(tag.id, this.properties, this.pageRecordList)) ); @@ -34,33 +34,33 @@ export class TagService { this.properties.removeTagOption(tagId); } - tagsByPageId(pageId: string) { + tagsByPageId$(pageId: string) { return LiveData.computed(get => { - const pageRecord = get(this.pageRecordList.record(pageId)); + const pageRecord = get(this.pageRecordList.record$(pageId)); if (!pageRecord) return []; - const tagIds = get(pageRecord.meta).tags; + const tagIds = get(pageRecord.meta$).tags; - return get(this.tags).filter(tag => tagIds.includes(tag.id)); + return get(this.tags$).filter(tag => tagIds.includes(tag.id)); }); } - tagIdsByPageId(pageId: string) { - return this.tagsByPageId(pageId).map(tags => tags.map(tag => tag.id)); + tagIdsByPageId$(pageId: string) { + return this.tagsByPageId$(pageId).map(tags => tags.map(tag => tag.id)); } - tagByTagId(tagId?: string) { - return this.tags.map(tags => tags.find(tag => tag.id === tagId)); + tagByTagId$(tagId?: string) { + return this.tags$.map(tags => tags.find(tag => tag.id === tagId)); } - tagMetas = LiveData.computed(get => { - return get(this.tags).map(tag => { + tagMetas$ = LiveData.computed(get => { + return get(this.tags$).map(tag => { return { id: tag.id, - title: get(tag.value), - color: get(tag.color), - pageCount: get(tag.pageIds).length, - createDate: get(tag.createDate), - updatedDate: get(tag.updateDate), + title: get(tag.value$), + color: get(tag.color$), + pageCount: get(tag.pageIds$).length, + createDate: get(tag.createDate$), + updatedDate: get(tag.updateDate$), }; }); }); @@ -71,15 +71,17 @@ export class TagService { return trimmedValue.includes(trimmedQuery); } - filterTagsByName(name: string) { + filterTagsByName$(name: string) { return LiveData.computed(get => { - return get(this.tags).filter(tag => this.filterFn(get(tag.value), name)); + return get(this.tags$).filter(tag => + this.filterFn(get(tag.value$), name) + ); }); } - tagByTagValue(value: string) { + tagByTagValue$(value: string) { return LiveData.computed(get => { - return get(this.tags).find(tag => this.filterFn(get(tag.value), value)); + return get(this.tags$).find(tag => this.filterFn(get(tag.value$), value)); }); } } diff --git a/packages/frontend/core/src/modules/tag/view/delete-tag-modal.tsx b/packages/frontend/core/src/modules/tag/view/delete-tag-modal.tsx index 9b3c3641a4..ed41f68be2 100644 --- a/packages/frontend/core/src/modules/tag/view/delete-tag-modal.tsx +++ b/packages/frontend/core/src/modules/tag/view/delete-tag-modal.tsx @@ -17,11 +17,11 @@ export const DeleteTagConfirmModal = ({ }) => { const t = useAFFiNEI18N(); const tagService = useService(TagService); - const tags = useLiveData(tagService.tags); + const tags = useLiveData(tagService.tags$); const selectedTags = useMemo(() => { return tags.filter(tag => selectedTagIds.includes(tag.id)); }, [selectedTagIds, tags]); - const tagName = useLiveData(selectedTags[0]?.value || ''); + const tagName = useLiveData(selectedTags[0]?.value$ || ''); const handleDelete = useCallback(() => { selectedTagIds.forEach(tagId => { diff --git a/packages/frontend/core/src/modules/workbench/entities/view.ts b/packages/frontend/core/src/modules/workbench/entities/view.ts index 821798eb7e..dc3ce94e85 100644 --- a/packages/frontend/core/src/modules/workbench/entities/view.ts +++ b/packages/frontend/core/src/modules/workbench/entities/view.ts @@ -21,7 +21,7 @@ export class View { initialIndex: 0, }); - location = LiveData.from( + location$ = LiveData.from( new Observable(subscriber => { subscriber.next(this.history.location); return this.history.listen(update => { @@ -31,7 +31,7 @@ export class View { this.history.location ); - entries = LiveData.from( + entries$ = LiveData.from( new Observable(subscriber => { subscriber.next(this.history.entries); return this.history.listen(() => { @@ -41,7 +41,7 @@ export class View { this.history.entries ); - size = new LiveData(100); + size$ = new LiveData(100); header = createIsland(); body = createIsland(); @@ -59,6 +59,6 @@ export class View { } setSize(size?: number) { - this.size.next(size ?? 100); + this.size$.next(size ?? 100); } } diff --git a/packages/frontend/core/src/modules/workbench/entities/workbench.ts b/packages/frontend/core/src/modules/workbench/entities/workbench.ts index 53f3dbabdf..bd943c01a2 100644 --- a/packages/frontend/core/src/modules/workbench/entities/workbench.ts +++ b/packages/frontend/core/src/modules/workbench/entities/workbench.ts @@ -13,32 +13,32 @@ interface WorkbenchOpenOptions { } export class Workbench { - readonly views = new LiveData([new View()]); + readonly views$ = new LiveData([new View()]); - activeViewIndex = new LiveData(0); - activeView = LiveData.from( - combineLatest([this.views, this.activeViewIndex]).pipe( + activeViewIndex$ = new LiveData(0); + activeView$ = LiveData.from( + combineLatest([this.views$, this.activeViewIndex$]).pipe( map(([views, index]) => views[index]) ), - this.views.value[this.activeViewIndex.value] + this.views$.value[this.activeViewIndex$.value] ); - basename = new LiveData('/'); + basename$ = new LiveData('/'); - location = LiveData.from( - this.activeView.pipe(switchMap(view => view.location)), - this.views.value[this.activeViewIndex.value].history.location + location$ = LiveData.from( + this.activeView$.pipe(switchMap(view => view.location$)), + this.views$.value[this.activeViewIndex$.value].history.location ); active(index: number) { - this.activeViewIndex.next(index); + this.activeViewIndex$.next(index); } createView(at: WorkbenchPosition = 'beside', defaultLocation: To) { const view = new View(defaultLocation); - const newViews = [...this.views.value]; + const newViews = [...this.views$.value]; newViews.splice(this.indexAt(at), 0, view); - this.views.next(newViews); + this.views$.next(newViews); return newViews.indexOf(view); } @@ -91,33 +91,33 @@ export class Workbench { } viewAt(positionIndex: WorkbenchPosition): View | undefined { - return this.views.value[this.indexAt(positionIndex)]; + return this.views$.value[this.indexAt(positionIndex)]; } close(view: View) { - if (this.views.value.length === 1) return; - const index = this.views.value.indexOf(view); + if (this.views$.value.length === 1) return; + const index = this.views$.value.indexOf(view); if (index === -1) return; - const newViews = [...this.views.value]; + const newViews = [...this.views$.value]; newViews.splice(index, 1); - const activeViewIndex = this.activeViewIndex.value; + const activeViewIndex = this.activeViewIndex$.value; if (activeViewIndex !== 0 && activeViewIndex >= index) { this.active(activeViewIndex - 1); } - this.views.next(newViews); + this.views$.next(newViews); } closeOthers(view: View) { - view.size.next(100); - this.views.next([view]); + view.size$.next(100); + this.views$.next([view]); this.active(0); } moveView(from: number, to: number) { - const views = [...this.views.value]; + const views = [...this.views$.value]; const [removed] = views.splice(from, 1); views.splice(to, 0, removed); - this.views.next(views); + this.views$.next(views); this.active(to); } @@ -128,18 +128,18 @@ export class Workbench { * @returns */ resize(index: number, percent: number) { - const view = this.views.value[index]; - const nextView = this.views.value[index + 1]; + const view = this.views$.value[index]; + const nextView = this.views$.value[index + 1]; if (!nextView) return; - const totalViewSize = this.views.value.reduce( - (sum, v) => sum + v.size.value, + const totalViewSize = this.views$.value.reduce( + (sum, v) => sum + v.size$.value, 0 ); const percentOfTotal = totalViewSize * percent; - const newSize = Number((view.size.value + percentOfTotal).toFixed(4)); + const newSize = Number((view.size$.value + percentOfTotal).toFixed(4)); const newNextSize = Number( - (nextView.size.value - percentOfTotal).toFixed(4) + (nextView.size$.value - percentOfTotal).toFixed(4) ); // TODO: better strategy to limit size if (newSize / totalViewSize < 0.2 || newNextSize / totalViewSize < 0.2) @@ -150,16 +150,16 @@ export class Workbench { private indexAt(positionIndex: WorkbenchPosition): number { if (positionIndex === 'active') { - return this.activeViewIndex.value; + return this.activeViewIndex$.value; } if (positionIndex === 'beside') { - return this.activeViewIndex.value + 1; + return this.activeViewIndex$.value + 1; } if (positionIndex === 'head') { return 0; } if (positionIndex === 'tail') { - return this.views.value.length; + return this.views$.value.length; } return positionIndex; } diff --git a/packages/frontend/core/src/modules/workbench/view/browser-adapter.ts b/packages/frontend/core/src/modules/workbench/view/browser-adapter.ts index aea568c5a1..d1991f3b1b 100644 --- a/packages/frontend/core/src/modules/workbench/view/browser-adapter.ts +++ b/packages/frontend/core/src/modules/workbench/view/browser-adapter.ts @@ -29,7 +29,7 @@ export function useBindWorkbenchToBrowserRouter( const navigate = useNavigate(); const browserLocation = useLocation(); - const view = useLiveData(workbench.activeView); + const view = useLiveData(workbench.activeView$); useEffect(() => { return view.history.listen(update => { diff --git a/packages/frontend/core/src/modules/workbench/view/desktop-adapter.ts b/packages/frontend/core/src/modules/workbench/view/desktop-adapter.ts index 8eca99de39..e2b652d0b0 100644 --- a/packages/frontend/core/src/modules/workbench/view/desktop-adapter.ts +++ b/packages/frontend/core/src/modules/workbench/view/desktop-adapter.ts @@ -31,9 +31,9 @@ export function useBindWorkbenchToDesktopRouter( return; } if ( - workbench.location.value.pathname === newLocation.pathname && - workbench.location.value.search === newLocation.search && - workbench.location.value.hash === newLocation.hash + workbench.location$.value.pathname === newLocation.pathname && + workbench.location$.value.search === newLocation.search && + workbench.location$.value.hash === newLocation.hash ) { return; } diff --git a/packages/frontend/core/src/modules/workbench/view/route-container.tsx b/packages/frontend/core/src/modules/workbench/view/route-container.tsx index 8d0a3d2bdd..4fcf1f2e51 100644 --- a/packages/frontend/core/src/modules/workbench/view/route-container.tsx +++ b/packages/frontend/core/src/modules/workbench/view/route-container.tsx @@ -48,8 +48,8 @@ export const RouteContainer = ({ route }: Props) => { const viewPosition = useViewPosition(); const leftSidebarOpen = useAtomValue(appSidebarOpenAtom); const rightSidebar = useService(RightSidebar); - const rightSidebarOpen = useLiveData(rightSidebar.isOpen); - const rightSidebarHasViews = useLiveData(rightSidebar.hasViews); + const rightSidebarOpen = useLiveData(rightSidebar.isOpen$); + const rightSidebarHasViews = useLiveData(rightSidebar.hasViews$); const handleToggleRightSidebar = useCallback(() => { rightSidebar.toggle(); }, [rightSidebar]); diff --git a/packages/frontend/core/src/modules/workbench/view/split-view/panel.tsx b/packages/frontend/core/src/modules/workbench/view/split-view/panel.tsx index 71b90cf3a3..38fdc1b4ef 100644 --- a/packages/frontend/core/src/modules/workbench/view/split-view/panel.tsx +++ b/packages/frontend/core/src/modules/workbench/view/split-view/panel.tsx @@ -45,10 +45,10 @@ export const SplitViewPanel = memo(function SplitViewPanel({ }: SplitViewPanelProps) { const [indicatorPressed, setIndicatorPressed] = useState(false); const ref = useRef(null); - const size = useLiveData(view.size); + const size = useLiveData(view.size$); const workbench = useService(Workbench); - const activeView = useLiveData(workbench.activeView); - const views = useLiveData(workbench.views); + const activeView = useLiveData(workbench.activeView$); + const views = useLiveData(workbench.views$); const isLast = views[views.length - 1] === view; const { @@ -116,7 +116,7 @@ export const SplitViewPanel = memo(function SplitViewPanel({ const SplitViewMenu = ({ view }: { view: View }) => { const t = useAFFiNEI18N(); const workbench = useService(Workbench); - const views = useLiveData(workbench.views); + const views = useLiveData(workbench.views$); const viewIndex = views.findIndex(v => v === view); diff --git a/packages/frontend/core/src/modules/workbench/view/use-is-active-view.tsx b/packages/frontend/core/src/modules/workbench/view/use-is-active-view.tsx index 9d94ceac1b..396e8be706 100644 --- a/packages/frontend/core/src/modules/workbench/view/use-is-active-view.tsx +++ b/packages/frontend/core/src/modules/workbench/view/use-is-active-view.tsx @@ -7,6 +7,6 @@ import { useView } from './use-view'; export function useIsActiveView() { const workbench = useService(Workbench); const currentView = useView(); - const activeView = useLiveData(workbench.activeView); + const activeView = useLiveData(workbench.activeView$); return currentView === activeView; } diff --git a/packages/frontend/core/src/modules/workbench/view/use-view-position.tsx b/packages/frontend/core/src/modules/workbench/view/use-view-position.tsx index ccc329c1d8..06c6f6f478 100644 --- a/packages/frontend/core/src/modules/workbench/view/use-view-position.tsx +++ b/packages/frontend/core/src/modules/workbench/view/use-view-position.tsx @@ -10,11 +10,11 @@ export const useViewPosition = () => { const view = useView(); const [position, setPosition] = useState(() => - calcPosition(view, workbench.views.value) + calcPosition(view, workbench.views$.value) ); useEffect(() => { - const subscription = workbench.views.subscribe(views => { + const subscription = workbench.views$.subscribe(views => { setPosition(calcPosition(view, views)); }); return () => { diff --git a/packages/frontend/core/src/modules/workbench/view/view-root.tsx b/packages/frontend/core/src/modules/workbench/view/view-root.tsx index 6c9a181162..c885bf5418 100644 --- a/packages/frontend/core/src/modules/workbench/view/view-root.tsx +++ b/packages/frontend/core/src/modules/workbench/view/view-root.tsx @@ -33,7 +33,7 @@ const warpedRoutes = viewRoutes.map(({ path, lazy }) => { export const ViewRoot = ({ view }: { view: View }) => { const viewRouter = useMemo(() => createMemoryRouter(warpedRoutes), []); - const location = useLiveData(view.location); + const location = useLiveData(view.location$); useEffect(() => { viewRouter.navigate(location).catch(err => { diff --git a/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx b/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx index ad75fa83f6..d40a7937df 100644 --- a/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx +++ b/packages/frontend/core/src/modules/workbench/view/workbench-link.tsx @@ -16,7 +16,7 @@ export const WorkbenchLink = ({ >) => { const workbench = useService(Workbench); const { appSettings } = useAppSettingHelper(); - const basename = useLiveData(workbench.basename); + const basename = useLiveData(workbench.basename$); const handleClick = useCallback( (event: React.MouseEvent) => { event.preventDefault(); diff --git a/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx b/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx index a7d1d4099b..9d71a6ab7d 100644 --- a/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx +++ b/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx @@ -21,7 +21,7 @@ export const WorkbenchRoot = () => { // for debugging (window as any).workbench = workbench; - const views = useLiveData(workbench.views); + const views = useLiveData(workbench.views$); const location = useLocation(); const basename = location.pathname.match(/\/workspace\/[^/]+/g)?.[0] ?? '/'; @@ -40,8 +40,8 @@ export const WorkbenchRoot = () => { ); useEffect(() => { - workbench.basename.next(basename); - }, [basename, workbench.basename]); + workbench.basename$.next(basename); + }, [basename, workbench.basename$]); return ( (null); + currentWorkspace$ = new LiveData(null); /** * open workspace, current workspace will be set to the workspace * @param workspace */ openWorkspace(workspace: Workspace) { - this.currentWorkspace.next(workspace); + this.currentWorkspace$.next(workspace); } /** * close current workspace, current workspace will be null */ closeWorkspace() { - this.currentWorkspace.next(null); + this.currentWorkspace$.next(null); } } diff --git a/packages/frontend/core/src/pages/index.tsx b/packages/frontend/core/src/pages/index.tsx index 8314d22d3e..27c4600f4c 100644 --- a/packages/frontend/core/src/pages/index.tsx +++ b/packages/frontend/core/src/pages/index.tsx @@ -27,7 +27,7 @@ export const Component = () => { const [navigating, setNavigating] = useState(false); const [creating, setCreating] = useState(false); - const list = useLiveData(useService(WorkspaceListService).workspaceList); + const list = useLiveData(useService(WorkspaceListService).workspaceList$); const { openPage } = useNavigateHelper(); diff --git a/packages/frontend/core/src/pages/share/share-detail-page.tsx b/packages/frontend/core/src/pages/share/share-detail-page.tsx index bf68ad0979..5043745b4f 100644 --- a/packages/frontend/core/src/pages/share/share-detail-page.tsx +++ b/packages/frontend/core/src/pages/share/share-detail-page.tsx @@ -186,7 +186,7 @@ export const Component = () => { workspaceManager, ]); - const pageTitle = useLiveData(page?.title); + const pageTitle = useLiveData(page?.title$); usePageDocumentTitle(pageTitle); const loginStatus = useCurrentLoginStatus(); diff --git a/packages/frontend/core/src/pages/workspace/all-collection/index.tsx b/packages/frontend/core/src/pages/workspace/all-collection/index.tsx index c7e6cbc313..15881301df 100644 --- a/packages/frontend/core/src/pages/workspace/all-collection/index.tsx +++ b/packages/frontend/core/src/pages/workspace/all-collection/index.tsx @@ -26,7 +26,7 @@ export const AllCollection = () => { const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true); const collectionService = useService(CollectionService); - const collections = useLiveData(collectionService.collections); + const collections = useLiveData(collectionService.collections$); const config = useAllPageListConfig(); const collectionMetas = useMemo(() => { diff --git a/packages/frontend/core/src/pages/workspace/all-tag/index.tsx b/packages/frontend/core/src/pages/workspace/all-tag/index.tsx index c1aa71c47a..1bdd872cc2 100644 --- a/packages/frontend/core/src/pages/workspace/all-tag/index.tsx +++ b/packages/frontend/core/src/pages/workspace/all-tag/index.tsx @@ -32,11 +32,11 @@ const EmptyTagListHeader = () => { export const AllTag = () => { const tagService = useService(TagService); - const tags = useLiveData(tagService.tags); + const tags = useLiveData(tagService.tags$); const [open, setOpen] = useState(false); const [selectedTagIds, setSelectedTagIds] = useState([]); - const tagMetas: TagMeta[] = useLiveData(tagService.tagMetas); + const tagMetas: TagMeta[] = useLiveData(tagService.tagMetas$); const handleCloseModal = useCallback( (open: boolean) => { diff --git a/packages/frontend/core/src/pages/workspace/collection/index.tsx b/packages/frontend/core/src/pages/workspace/collection/index.tsx index 7bcdc79c6a..4380630568 100644 --- a/packages/frontend/core/src/pages/workspace/collection/index.tsx +++ b/packages/frontend/core/src/pages/workspace/collection/index.tsx @@ -67,7 +67,7 @@ export const CollectionDetail = ({ export const Component = function CollectionPage() { const collectionService = useService(CollectionService); - const collections = useLiveData(collectionService.collections); + const collections = useLiveData(collectionService.collections$); const navigate = useNavigateHelper(); const params = useParams(); const workspace = useService(Workspace); @@ -76,7 +76,7 @@ export const Component = function CollectionPage() { useEffect(() => { if (!collection) { navigate.jumpToSubPath(workspace.id, WorkspaceSubPath.ALL); - const collection = collectionService.collectionsTrash.value.find( + const collection = collectionService.collectionsTrash$.value.find( v => v.collection.id === params.collectionId ); let text = 'Collection does not exist'; @@ -94,7 +94,7 @@ export const Component = function CollectionPage() { } }, [ collection, - collectionService.collectionsTrash.value, + collectionService.collectionsTrash$.value, navigate, params.collectionId, pushNotification, diff --git a/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx b/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx index 4dcc0e285b..c97336799e 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx +++ b/packages/frontend/core/src/pages/workspace/detail-page/detail-page.tsx @@ -108,9 +108,9 @@ const DetailPageImpl = memo(function DetailPageImpl() { const isInTrash = pageMeta?.trash; - const mode = useLiveData(page.mode); + const mode = useLiveData(page.mode$); useRegisterBlocksuiteEditorCommands(); - const title = useLiveData(page.title); + const title = useLiveData(page.title$); usePageDocumentTitle(title); const onLoad = useCallback( @@ -156,13 +156,13 @@ const DetailPageImpl = memo(function DetailPageImpl() { const disposable = new DisposableGroup(); pageService.getEditorMode = (pageId: string) => - pageRecordList.record(pageId).value?.mode.value ?? 'page'; + pageRecordList.record$(pageId).value?.mode$.value ?? 'page'; pageService.getDocUpdatedAt = (pageId: string) => { - const linkedPage = pageRecordList.record(pageId).value; + const linkedPage = pageRecordList.record$(pageId).value; if (!linkedPage) return new Date(); - const updatedDate = linkedPage.meta.value.updatedDate; - const createDate = linkedPage.meta.value.createDate; + const updatedDate = linkedPage.meta$.value.updatedDate; + const createDate = linkedPage.meta$.value.createDate; return updatedDate ? new Date(updatedDate) : new Date(createDate); }; @@ -278,9 +278,9 @@ export const DetailPage = ({ pageId }: { pageId: string }): ReactElement => { const currentWorkspace = useService(Workspace); const pageRecordList = useService(PageRecordList); - const pageListReady = useLiveData(pageRecordList.isReady); + const pageListReady = useLiveData(pageRecordList.isReady$); - const pageRecords = useLiveData(pageRecordList.records); + const pageRecords = useLiveData(pageRecordList.records$); const pageRecord = useMemo( () => pageRecords.find(page => page.id === pageId), @@ -310,7 +310,7 @@ export const DetailPage = ({ pageId }: { pageId: string }): ReactElement => { }; }, [currentWorkspace, pageId]); - const jumpOnce = useLiveData(pageRecord?.meta.map(meta => meta.jumpOnce)); + const jumpOnce = useLiveData(pageRecord?.meta$.map(meta => meta.jumpOnce)); useEffect(() => { if (jumpOnce) { diff --git a/packages/frontend/core/src/pages/workspace/index.tsx b/packages/frontend/core/src/pages/workspace/index.tsx index b5bb1db848..939ca91eae 100644 --- a/packages/frontend/core/src/pages/workspace/index.tsx +++ b/packages/frontend/core/src/pages/workspace/index.tsx @@ -39,7 +39,7 @@ export const Component = (): ReactElement => { const params = useParams(); const { workspaceList, loading: listLoading } = useLiveData( - useService(WorkspaceListService).status + useService(WorkspaceListService).status$ ); const workspaceManager = useService(WorkspaceManager); @@ -71,7 +71,7 @@ export const Component = (): ReactElement => { // avoid doing operation, before workspace is loaded const isRootDocReady = - useLiveData(workspace?.engine.rootDocState)?.ready ?? false; + useLiveData(workspace?.engine.rootDocState$)?.ready ?? false; // if listLoading is false, we can show 404 page, otherwise we should show loading page. if (listLoading === false && meta === undefined) { diff --git a/packages/frontend/core/src/pages/workspace/tag/index.tsx b/packages/frontend/core/src/pages/workspace/tag/index.tsx index 64917900cd..87d799e1d8 100644 --- a/packages/frontend/core/src/pages/workspace/tag/index.tsx +++ b/packages/frontend/core/src/pages/workspace/tag/index.tsx @@ -8,7 +8,7 @@ import { ViewBodyIsland, ViewHeaderIsland, } from '@affine/core/modules/workbench'; -import { LiveData, useLiveData, useService } from '@toeverything/infra'; +import { useLiveData, useService } from '@toeverything/infra'; import { Workspace } from '@toeverything/infra'; import { useMemo } from 'react'; import { useParams } from 'react-router-dom'; @@ -23,21 +23,9 @@ export const TagDetail = ({ tagId }: { tagId?: string }) => { const pageMetas = useBlockSuiteDocMeta(currentWorkspace.docCollection); const tagService = useService(TagService); - const currentTagLiveData = tagService.tagByTagId(tagId); - const currentTag = useLiveData(currentTagLiveData); + const currentTag = useLiveData(tagService.tagByTagId$(tagId)); - const pageIdsLiveData = useMemo( - () => - LiveData.computed(get => { - const liveTag = get(currentTagLiveData); - if (liveTag?.pageIds) { - return get(liveTag.pageIds); - } - return []; - }), - [currentTagLiveData] - ); - const pageIds = useLiveData(pageIdsLiveData); + const pageIds = useLiveData(currentTag?.pageIds$); const filteredPageMetas = useMemo(() => { const pageIdsSet = new Set(pageIds); diff --git a/packages/frontend/core/src/providers/modal-provider.tsx b/packages/frontend/core/src/providers/modal-provider.tsx index 27efcd3466..f3e064fa60 100644 --- a/packages/frontend/core/src/providers/modal-provider.tsx +++ b/packages/frontend/core/src/providers/modal-provider.tsx @@ -192,7 +192,7 @@ export const AuthModal = (): ReactElement => { export function CurrentWorkspaceModals() { const currentWorkspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); const [openDisableCloudAlertModal, setOpenDisableCloudAlertModal] = useAtom( openDisableCloudAlertModalAtom @@ -227,10 +227,10 @@ export const SignOutConfirmModal = () => { const { openPage } = useNavigateHelper(); const [open, setOpen] = useAtom(openSignOutModalAtom); const currentWorkspace = useLiveData( - useService(CurrentWorkspaceService).currentWorkspace + useService(CurrentWorkspaceService).currentWorkspace$ ); const workspaces = useLiveData( - useService(WorkspaceManager).list.workspaceList + useService(WorkspaceManager).list.workspaceList$ ); const onConfirm = useAsyncCallback(async () => { diff --git a/packages/frontend/core/src/utils/island.tsx b/packages/frontend/core/src/utils/island.tsx index e66052b1b1..8596881e9f 100644 --- a/packages/frontend/core/src/utils/island.tsx +++ b/packages/frontend/core/src/utils/island.tsx @@ -3,7 +3,7 @@ import { useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; export const createIsland = () => { - const targetLiveData = new LiveData(null); + const targetLiveData$ = new LiveData(null); let mounted = false; let provided = false; return { @@ -14,16 +14,16 @@ export const createIsland = () => { throw new Error('Island should not be mounted more than once'); } mounted = true; - targetLiveData.next(target.current); + targetLiveData$.next(target.current); return () => { mounted = false; - targetLiveData.next(null); + targetLiveData$.next(null); }; }, []); return
; }, Provider: ({ children }: React.PropsWithChildren) => { - const target = useLiveData(targetLiveData); + const target = useLiveData(targetLiveData$); useEffect(() => { if (provided === true && process.env.NODE_ENV !== 'production') { throw new Error('Island should not be provided more than once'); diff --git a/packages/frontend/electron/src/helper/db/ensure-db.ts b/packages/frontend/electron/src/helper/db/ensure-db.ts index ae8ee92a23..593ce9fc72 100644 --- a/packages/frontend/electron/src/helper/db/ensure-db.ts +++ b/packages/frontend/electron/src/helper/db/ensure-db.ts @@ -38,9 +38,9 @@ export const db$Map = new Map>(); const beforeQuit$ = defer(() => fromEvent(process, 'beforeExit')); // return a stream that emit a single event when the subject completes -function completed(subject: Subject) { +function completed(subject$: Subject) { return new Observable(subscriber => { - const sub = subject.subscribe({ + const sub = subject$.subscribe({ complete: () => { subscriber.next(); subscriber.complete(); @@ -50,7 +50,7 @@ function completed(subject: Subject) { }); } -function getWorkspaceDB$(id: string) { +function getWorkspaceDB(id: string) { if (!db$Map.has(id)) { db$Map.set( id, @@ -103,7 +103,7 @@ function getWorkspaceDB$(id: string) { function startPollingSecondaryDB(db: WorkspaceSQLiteDB) { return merge( getWorkspaceMeta(db.workspaceId), - workspaceSubjects.meta.pipe( + workspaceSubjects.meta$.pipe( map(({ meta }) => meta), filter(meta => meta.id === db.workspaceId) ) @@ -141,5 +141,5 @@ function startPollingSecondaryDB(db: WorkspaceSQLiteDB) { } export function ensureSQLiteDB(id: string) { - return lastValueFrom(getWorkspaceDB$(id).pipe(take(1))); + return lastValueFrom(getWorkspaceDB(id).pipe(take(1))); } diff --git a/packages/frontend/electron/src/helper/db/index.ts b/packages/frontend/electron/src/helper/db/index.ts index 4f3f5c43b7..1fabc02f43 100644 --- a/packages/frontend/electron/src/helper/db/index.ts +++ b/packages/frontend/electron/src/helper/db/index.ts @@ -48,7 +48,7 @@ export const dbEvents = { docId?: string; }) => void ) => { - const sub = dbSubjects.externalUpdate.subscribe(fn); + const sub = dbSubjects.externalUpdate$.subscribe(fn); return () => { sub.unsubscribe(); }; diff --git a/packages/frontend/electron/src/helper/db/subjects.ts b/packages/frontend/electron/src/helper/db/subjects.ts index 263d68cc91..a1acbbe62f 100644 --- a/packages/frontend/electron/src/helper/db/subjects.ts +++ b/packages/frontend/electron/src/helper/db/subjects.ts @@ -1,7 +1,7 @@ import { Subject } from 'rxjs'; export const dbSubjects = { - externalUpdate: new Subject<{ + externalUpdate$: new Subject<{ workspaceId: string; update: Uint8Array; docId?: string; diff --git a/packages/frontend/electron/src/helper/db/workspace-db-adapter.ts b/packages/frontend/electron/src/helper/db/workspace-db-adapter.ts index ae404fffac..f276c72185 100644 --- a/packages/frontend/electron/src/helper/db/workspace-db-adapter.ts +++ b/packages/frontend/electron/src/helper/db/workspace-db-adapter.ts @@ -66,7 +66,7 @@ export class WorkspaceSQLiteDB extends BaseSQLiteAdapter { if (origin === 'renderer') { await this.addUpdateToSQLite(insertRows); } else if (origin === 'external') { - dbSubjects.externalUpdate.next({ + dbSubjects.externalUpdate$.next({ workspaceId: this.workspaceId, update, docId, diff --git a/packages/frontend/electron/src/helper/workspace/handlers.ts b/packages/frontend/electron/src/helper/workspace/handlers.ts index 07f62f1212..4d6e22f231 100644 --- a/packages/frontend/electron/src/helper/workspace/handlers.ts +++ b/packages/frontend/electron/src/helper/workspace/handlers.ts @@ -97,7 +97,7 @@ export async function storeWorkspaceMeta( ...meta, }; await fs.writeJSON(metaPath, newMeta); - workspaceSubjects.meta.next({ + workspaceSubjects.meta$.next({ workspaceId, meta: newMeta, }); diff --git a/packages/frontend/electron/src/helper/workspace/index.ts b/packages/frontend/electron/src/helper/workspace/index.ts index 5d7a4dd2fb..22c73e2ddb 100644 --- a/packages/frontend/electron/src/helper/workspace/index.ts +++ b/packages/frontend/electron/src/helper/workspace/index.ts @@ -10,7 +10,7 @@ export const workspaceEvents = { onMetaChange: ( fn: (meta: { workspaceId: string; meta: WorkspaceMeta }) => void ) => { - const sub = workspaceSubjects.meta.subscribe(fn); + const sub = workspaceSubjects.meta$.subscribe(fn); return () => { sub.unsubscribe(); }; diff --git a/packages/frontend/electron/src/helper/workspace/subjects.ts b/packages/frontend/electron/src/helper/workspace/subjects.ts index 7d3a2427ec..21cd3a15a2 100644 --- a/packages/frontend/electron/src/helper/workspace/subjects.ts +++ b/packages/frontend/electron/src/helper/workspace/subjects.ts @@ -3,5 +3,5 @@ import { Subject } from 'rxjs'; import type { WorkspaceMeta } from '../type'; export const workspaceSubjects = { - meta: new Subject<{ workspaceId: string; meta: WorkspaceMeta }>(), + meta$: new Subject<{ workspaceId: string; meta: WorkspaceMeta }>(), }; diff --git a/packages/frontend/electron/src/main/application-menu/create.ts b/packages/frontend/electron/src/main/application-menu/create.ts index b7fd6faa43..70a3fa0f02 100644 --- a/packages/frontend/electron/src/main/application-menu/create.ts +++ b/packages/frontend/electron/src/main/application-menu/create.ts @@ -26,7 +26,7 @@ export function createApplicationMenu() { label: `About ${app.getName()}`, click: async () => { await showMainWindow(); - applicationMenuSubjects.openAboutPageInSettingModal.next(); + applicationMenuSubjects.openAboutPageInSettingModal$.next(); }, }, { type: 'separator' }, @@ -52,7 +52,7 @@ export function createApplicationMenu() { click: async () => { await initAndShowMainWindow(); // fixme: if the window is just created, the new page action will not be triggered - applicationMenuSubjects.newPageAction.next(); + applicationMenuSubjects.newPageAction$.next(); }, }, { type: 'separator' }, diff --git a/packages/frontend/electron/src/main/application-menu/index.ts b/packages/frontend/electron/src/main/application-menu/index.ts index 618875f2ae..61c88f2085 100644 --- a/packages/frontend/electron/src/main/application-menu/index.ts +++ b/packages/frontend/electron/src/main/application-menu/index.ts @@ -12,14 +12,14 @@ export const applicationMenuEvents = { * File -> New Doc */ onNewPageAction: (fn: () => void) => { - const sub = applicationMenuSubjects.newPageAction.subscribe(fn); + const sub = applicationMenuSubjects.newPageAction$.subscribe(fn); return () => { sub.unsubscribe(); }; }, openAboutPageInSettingModal: (fn: () => void) => { const sub = - applicationMenuSubjects.openAboutPageInSettingModal.subscribe(fn); + applicationMenuSubjects.openAboutPageInSettingModal$.subscribe(fn); return () => { sub.unsubscribe(); }; diff --git a/packages/frontend/electron/src/main/application-menu/subject.ts b/packages/frontend/electron/src/main/application-menu/subject.ts index 7d7ae54fff..bee518184a 100644 --- a/packages/frontend/electron/src/main/application-menu/subject.ts +++ b/packages/frontend/electron/src/main/application-menu/subject.ts @@ -1,6 +1,6 @@ import { Subject } from 'rxjs'; export const applicationMenuSubjects = { - newPageAction: new Subject(), - openAboutPageInSettingModal: new Subject(), + newPageAction$: new Subject(), + openAboutPageInSettingModal$: new Subject(), }; diff --git a/packages/frontend/electron/src/main/main-window.ts b/packages/frontend/electron/src/main/main-window.ts index a00b1dd7a0..37fcda22fc 100644 --- a/packages/frontend/electron/src/main/main-window.ts +++ b/packages/frontend/electron/src/main/main-window.ts @@ -104,7 +104,7 @@ async function createWindow(additionalArguments: string[]) { logger.info('main window is ready to show'); if (browserWindow.isMaximized() || browserWindow.isFullScreen()) { - uiSubjects.onMaximized.next(true); + uiSubjects.onMaximized$.next(true); } handleWebContentsResize().catch(logger.error); @@ -141,20 +141,20 @@ async function createWindow(additionalArguments: string[]) { browserWindow.setSize(size[0] + 1, size[1] + 1); browserWindow.setSize(size[0], size[1]); }); - uiSubjects.onMaximized.next(false); + uiSubjects.onMaximized$.next(false); }); browserWindow.on('maximize', () => { - uiSubjects.onMaximized.next(true); + uiSubjects.onMaximized$.next(true); }); // full-screen == maximized in UI on windows browserWindow.on('enter-full-screen', () => { - uiSubjects.onMaximized.next(true); + uiSubjects.onMaximized$.next(true); }); browserWindow.on('unmaximize', () => { - uiSubjects.onMaximized.next(false); + uiSubjects.onMaximized$.next(false); }); /** @@ -172,7 +172,7 @@ async function createWindow(additionalArguments: string[]) { } // singleton -let browserWindow$: Promise | undefined; +let browserWindow: Promise | undefined; // a hidden window that prevents the app from quitting on MacOS let hiddenMacWindow: BrowserWindow | undefined; @@ -181,11 +181,11 @@ let hiddenMacWindow: BrowserWindow | undefined; * Init main BrowserWindow. Will create a new window if it's not created yet. */ export async function initAndShowMainWindow() { - if (!browserWindow$ || (await browserWindow$.then(w => w.isDestroyed()))) { + if (!browserWindow || (await browserWindow.then(w => w.isDestroyed()))) { const additionalArguments = await getWindowAdditionalArguments(); - browserWindow$ = createWindow(additionalArguments); + browserWindow = createWindow(additionalArguments); } - const mainWindow = await browserWindow$; + const mainWindow = await browserWindow; if (IS_DEV) { // do not gain focus in dev mode @@ -209,8 +209,8 @@ export async function initAndShowMainWindow() { } export async function getMainWindow() { - if (!browserWindow$) return; - const window = await browserWindow$; + if (!browserWindow) return; + const window = await browserWindow; if (window.isDestroyed()) return; return window; } @@ -251,7 +251,7 @@ export async function setCookie( arg0: CookiesSetDetails | string, arg1?: string ) { - const window = await browserWindow$; + const window = await browserWindow; if (!window) { // do nothing if window is not ready return; @@ -271,7 +271,7 @@ export async function setCookie( } export async function removeCookie(url: string, name: string): Promise { - const window = await browserWindow$; + const window = await browserWindow; if (!window) { // do nothing if window is not ready return; @@ -280,7 +280,7 @@ export async function removeCookie(url: string, name: string): Promise { } export async function getCookie(url?: string, name?: string) { - const window = await browserWindow$; + const window = await browserWindow; if (!window) { // do nothing if window is not ready return; diff --git a/packages/frontend/electron/src/main/onboarding.ts b/packages/frontend/electron/src/main/onboarding.ts index a2923ea373..8b24c44667 100644 --- a/packages/frontend/electron/src/main/onboarding.ts +++ b/packages/frontend/electron/src/main/onboarding.ts @@ -96,23 +96,23 @@ async function createOnboardingWindow(additionalArguments: string[]) { return browserWindow; } -let onBoardingWindow$: Promise | undefined; +let onBoardingWindow: Promise | undefined; export async function getOrCreateOnboardingWindow() { const additionalArguments = await getWindowAdditionalArguments(); if ( - !onBoardingWindow$ || - (await onBoardingWindow$.then(w => w.isDestroyed())) + !onBoardingWindow || + (await onBoardingWindow.then(w => w.isDestroyed())) ) { - onBoardingWindow$ = createOnboardingWindow(additionalArguments); + onBoardingWindow = createOnboardingWindow(additionalArguments); } - return onBoardingWindow$; + return onBoardingWindow; } export async function getOnboardingWindow() { - if (!onBoardingWindow$) return; - const window = await onBoardingWindow$; + if (!onBoardingWindow) return; + const window = await onBoardingWindow; if (window.isDestroyed()) return; return window; } diff --git a/packages/frontend/electron/src/main/ui/events.ts b/packages/frontend/electron/src/main/ui/events.ts index be8f4225e4..16569a4d8b 100644 --- a/packages/frontend/electron/src/main/ui/events.ts +++ b/packages/frontend/electron/src/main/ui/events.ts @@ -6,7 +6,7 @@ import { uiSubjects } from './subject'; */ export const uiEvents = { onMaximized: (fn: (maximized: boolean) => void) => { - const sub = uiSubjects.onMaximized.subscribe(fn); + const sub = uiSubjects.onMaximized$.subscribe(fn); return () => { sub.unsubscribe(); }; diff --git a/packages/frontend/electron/src/main/ui/subject.ts b/packages/frontend/electron/src/main/ui/subject.ts index bfd6fae9e8..488971bbd2 100644 --- a/packages/frontend/electron/src/main/ui/subject.ts +++ b/packages/frontend/electron/src/main/ui/subject.ts @@ -1,5 +1,5 @@ import { Subject } from 'rxjs'; export const uiSubjects = { - onMaximized: new Subject(), + onMaximized$: new Subject(), }; diff --git a/packages/frontend/electron/src/main/updater/electron-updater.ts b/packages/frontend/electron/src/main/updater/electron-updater.ts index afac40a6bb..39bccd0091 100644 --- a/packages/frontend/electron/src/main/updater/electron-updater.ts +++ b/packages/frontend/electron/src/main/updater/electron-updater.ts @@ -67,7 +67,7 @@ export const downloadUpdate = async () => { return; } downloading = true; - updaterSubjects.downloadProgress.next(0); + updaterSubjects.downloadProgress$.next(0); autoUpdater.downloadUpdate().catch(e => { downloading = false; logger.error('Failed to download update', e); @@ -115,7 +115,7 @@ export const registerUpdater = async () => { console.error(err); }); } - updaterSubjects.updateAvailable.next({ + updaterSubjects.updateAvailable$.next({ version: info.version, allowAutoUpdate, }); @@ -125,11 +125,11 @@ export const registerUpdater = async () => { }); autoUpdater.on('download-progress', e => { logger.info(`Download progress: ${e.percent}`); - updaterSubjects.downloadProgress.next(e.percent); + updaterSubjects.downloadProgress$.next(e.percent); }); autoUpdater.on('update-downloaded', e => { downloading = false; - updaterSubjects.updateReady.next({ + updaterSubjects.updateReady$.next({ version: e.version, allowAutoUpdate, }); diff --git a/packages/frontend/electron/src/main/updater/event.ts b/packages/frontend/electron/src/main/updater/event.ts index 02a368185d..1d70d1e292 100644 --- a/packages/frontend/electron/src/main/updater/event.ts +++ b/packages/frontend/electron/src/main/updater/event.ts @@ -9,26 +9,26 @@ export interface UpdateMeta { export const updaterSubjects = { // means it is ready for restart and install the new version - updateAvailable: new Subject(), - updateReady: new Subject(), - downloadProgress: new BehaviorSubject(0), + updateAvailable$: new Subject(), + updateReady$: new Subject(), + downloadProgress$: new BehaviorSubject(0), }; export const updaterEvents = { onUpdateAvailable: (fn: (versionMeta: UpdateMeta) => void) => { - const sub = updaterSubjects.updateAvailable.subscribe(fn); + const sub = updaterSubjects.updateAvailable$.subscribe(fn); return () => { sub.unsubscribe(); }; }, onUpdateReady: (fn: (versionMeta: UpdateMeta) => void) => { - const sub = updaterSubjects.updateReady.subscribe(fn); + const sub = updaterSubjects.updateReady$.subscribe(fn); return () => { sub.unsubscribe(); }; }, onDownloadProgress: (fn: (progress: number) => void) => { - const sub = updaterSubjects.downloadProgress.subscribe(fn); + const sub = updaterSubjects.downloadProgress$.subscribe(fn); return () => { sub.unsubscribe(); }; diff --git a/packages/frontend/electron/src/main/windows-manager/windows.ts b/packages/frontend/electron/src/main/windows-manager/windows.ts deleted file mode 100644 index cbc5a19c78..0000000000 --- a/packages/frontend/electron/src/main/windows-manager/windows.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { BrowserWindow } from 'electron'; - -import type { LaunchStage } from './types'; - -export const windows$: Record | undefined> = - { - main: undefined, - onboarding: undefined, - }; diff --git a/packages/frontend/electron/src/preload/electron-api.ts b/packages/frontend/electron/src/preload/electron-api.ts index aaec001f6d..5fb73a18d1 100644 --- a/packages/frontend/electron/src/preload/electron-api.ts +++ b/packages/frontend/electron/src/preload/electron-api.ts @@ -141,7 +141,7 @@ function getMainAPIs() { return { apis, events }; } -const helperPort$ = new Promise(resolve => +const helperPort = new Promise(resolve => ipcRenderer.on('helper-connection', e => { console.info('[preload] helper-connection', e); resolve(e.ports[0]); @@ -183,7 +183,7 @@ function getHelperAPIs() { }; const rpc = AsyncCall(rendererToHelperServer, { - channel: helperPort$.then(helperPort => + channel: helperPort.then(helperPort => createMessagePortChannel(helperPort) ), log: false, diff --git a/packages/frontend/electron/test/db/workspace-db-adapter.spec.ts b/packages/frontend/electron/test/db/workspace-db-adapter.spec.ts index 2394df4ad4..c16fb46ead 100644 --- a/packages/frontend/electron/test/db/workspace-db-adapter.spec.ts +++ b/packages/frontend/electron/test/db/workspace-db-adapter.spec.ts @@ -90,7 +90,7 @@ test('on applyUpdate (from renderer), will trigger update', async () => { const db = await openWorkspaceDatabase(workspaceId); db.update$.subscribe(onUpdate); - const sub = dbSubjects.externalUpdate.subscribe(onExternalUpdate); + const sub = dbSubjects.externalUpdate$.subscribe(onExternalUpdate); db.applyUpdate(getTestUpdates(), 'renderer'); expect(onUpdate).toHaveBeenCalled(); sub.unsubscribe(); @@ -134,7 +134,7 @@ test('on applyUpdate (from external), will trigger update & send external update const db = await openWorkspaceDatabase(workspaceId); db.update$.subscribe(onUpdate); - const sub = dbSubjects.externalUpdate.subscribe(onExternalUpdate); + const sub = dbSubjects.externalUpdate$.subscribe(onExternalUpdate); db.applyUpdate(getTestUpdates(), 'external'); expect(onUpdate).toHaveBeenCalled(); expect(onExternalUpdate).toHaveBeenCalled(); diff --git a/tests/storybook/src/stories/workspace-list.stories.tsx b/tests/storybook/src/stories/workspace-list.stories.tsx index 07338f0dea..fe0e47a612 100644 --- a/tests/storybook/src/stories/workspace-list.stories.tsx +++ b/tests/storybook/src/stories/workspace-list.stories.tsx @@ -13,7 +13,7 @@ export default { } satisfies Meta; export const Default = () => { - const list = useLiveData(useService(WorkspaceManager).list.workspaceList); + const list = useLiveData(useService(WorkspaceManager).list.workspaceList$); return ( =4.0.0" + checksum: 10/2be2886635ade572638a77a2313fadb689435f89f5e56cefdca27d81970eabd76575f57cf950abcff9949e20ce4dd65ce6b6dafff3f95db7fe6aecbaf54a9004 + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.9": version: 0.3.9 resolution: "eslint-import-resolver-node@npm:0.3.9" @@ -20575,6 +20697,26 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-rxjs@npm:^5.0.3": + version: 5.0.3 + resolution: "eslint-plugin-rxjs@npm:5.0.3" + dependencies: + "@typescript-eslint/experimental-utils": "npm:^5.0.0" + common-tags: "npm:^1.8.0" + decamelize: "npm:^5.0.0" + eslint-etc: "npm:^5.1.0" + requireindex: "npm:~1.2.0" + rxjs-report-usage: "npm:^1.0.4" + tslib: "npm:^2.0.0" + tsutils: "npm:^3.0.0" + tsutils-etc: "npm:^1.4.1" + peerDependencies: + eslint: ^8.0.0 + typescript: ">=4.0.0" + checksum: 10/dde92c7175e717e3075d427fdabcaf71e51b3a4b770efaef954697ce4caad3fc77a5610b8eab7e628033d619510367f876d1ef184f177488d2c85d5391d193c0 + languageName: node + linkType: hard + "eslint-plugin-simple-import-sort@npm:^12.0.0": version: 12.0.0 resolution: "eslint-plugin-simple-import-sort@npm:12.0.0" @@ -20658,7 +20800,7 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:5.1.1": +"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" dependencies: @@ -22300,7 +22442,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": +"glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0, glob@npm:~7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -30151,7 +30293,7 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1, prompts@npm:^2.4.0, prompts@npm:^2.4.1": +"prompts@npm:^2.0.1, prompts@npm:^2.4.0, prompts@npm:^2.4.1, prompts@npm:~2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" dependencies: @@ -31283,6 +31425,13 @@ __metadata: languageName: node linkType: hard +"requireindex@npm:~1.2.0": + version: 1.2.0 + resolution: "requireindex@npm:1.2.0" + checksum: 10/266d1cb31f6cbc4b6cf2e898f5bbc45581f7919bcf61bba5c45d0adb69b722b9ff5a13727be3350cde4520d7cd37f39df45d58a29854baaa4552cd6b05ae4a1a + languageName: node + linkType: hard + "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -31689,6 +31838,23 @@ __metadata: languageName: node linkType: hard +"rxjs-report-usage@npm:^1.0.4": + version: 1.0.6 + resolution: "rxjs-report-usage@npm:1.0.6" + dependencies: + "@babel/parser": "npm:^7.10.3" + "@babel/traverse": "npm:^7.10.3" + "@babel/types": "npm:^7.10.3" + bent: "npm:~7.3.6" + chalk: "npm:~4.1.0" + glob: "npm:~7.2.0" + prompts: "npm:~2.4.2" + bin: + rxjs-report-usage: bin/rxjs-report-usage + checksum: 10/b0488c2ccbed8915a3fc9f0303a87628ee546f89a371f06116a3a442d254d7967b09a00e74f12971d712617269f63458228c1dbc909da1f58935646da6b02399 + languageName: node + linkType: hard + "rxjs@npm:^7.5.5, rxjs@npm:^7.8.0, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" @@ -33906,13 +34072,40 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.11.1, tslib@npm:^1.13.0": +"tslib@npm:^1.11.1, tslib@npm:^1.13.0, tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb languageName: node linkType: hard +"tsutils-etc@npm:^1.4.1": + version: 1.4.2 + resolution: "tsutils-etc@npm:1.4.2" + dependencies: + "@types/yargs": "npm:^17.0.0" + yargs: "npm:^17.0.0" + peerDependencies: + tsutils: ^3.0.0 + typescript: ">=4.0.0" + bin: + ts-flags: bin/ts-flags + ts-kind: bin/ts-kind + checksum: 10/b204bf464837e5b3f0ba89bee06ce86b9a554a49648de57932bf65a16163c5f472d3e3c26c6f71d178b5fa5b7655a88af1d7725100891db2b2f0f9edb0107a59 + languageName: node + linkType: hard + +"tsutils@npm:^3.0.0, tsutils@npm:^3.17.1, tsutils@npm:^3.21.0": + version: 3.21.0 + resolution: "tsutils@npm:3.21.0" + dependencies: + tslib: "npm:^1.8.1" + peerDependencies: + typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + checksum: 10/ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2 + languageName: node + linkType: hard + "typanion@npm:^3.14.0, typanion@npm:^3.8.0": version: 3.14.0 resolution: "typanion@npm:3.14.0"