diff --git a/packages/web/src/Effects.ts b/packages/web/src/Effects.ts index b2a2c842..2a23fabf 100644 --- a/packages/web/src/Effects.ts +++ b/packages/web/src/Effects.ts @@ -1,8 +1,7 @@ -import { effects as datasourceEffects } from "./dataSources/effects" import { useDownloadsEffects } from "./download/effects" import { useCleanupDanglingLinks } from "./links/useCleanupDanglingLinks" - -const effects = [...datasourceEffects, useDownloadsEffects] + +const effects = [useDownloadsEffects] export const Effects = () => { effects.forEach((effectHook) => effectHook()) diff --git a/packages/web/src/constants.shared.ts b/packages/web/src/constants.shared.ts index 231f70d4..e5c2b0a7 100644 --- a/packages/web/src/constants.shared.ts +++ b/packages/web/src/constants.shared.ts @@ -15,4 +15,4 @@ export const API_URL = import.meta.env.VITE_API_URL || `http://localhost:5173/api/dev` export const API_COUCH_URI = import.meta.env.VITE_API_COUCH_URI || `https://${hostname}:4003` -export const CLEANUP_DANGLING_LINKS_INTERVAL = 1000 * 60 * 5 // 5mn +export const CLEANUP_DANGLING_LINKS_INTERVAL = 1000 * 60 * 10 // 10mn diff --git a/packages/web/src/dataSources/DataSourcesActionsDrawer.tsx b/packages/web/src/dataSources/DataSourcesActionsDrawer.tsx index b1be617b..0c0b5feb 100644 --- a/packages/web/src/dataSources/DataSourcesActionsDrawer.tsx +++ b/packages/web/src/dataSources/DataSourcesActionsDrawer.tsx @@ -1,6 +1,5 @@ import { Drawer, - ListItem, List, ListItemIcon, ListItemText, @@ -14,9 +13,11 @@ import { RadioButtonUncheckedOutlined, CheckCircleRounded } from "@mui/icons-material" -import { useSynchronizeDataSource } from "./helpers" +import { + useDataSourceIncrementalModify, + useSynchronizeDataSource +} from "./helpers" import { useDataSource } from "./useDataSource" -import { toggleDatasourceProtected } from "./triggers" import { useSignalValue } from "reactjrx" import { libraryStateSignal } from "../library/states" import { useRemoveDataSource } from "./useRemoveDataSource" @@ -29,6 +30,7 @@ export const DataSourcesActionsDrawer: FC<{ const { mutate: removeDataSource } = useRemoveDataSource() const { data: dataSource } = useDataSource(openWith) const library = useSignalValue(libraryStateSignal) + const { mutate: modifyDataSource } = useDataSourceIncrementalModify() return ( <> @@ -46,17 +48,22 @@ export const DataSourcesActionsDrawer: FC<{ - { - toggleDatasourceProtected(openWith) - const datasourceWillBeHidden = !dataSource?.isProtected && !library.isLibraryUnlocked if (datasourceWillBeHidden) { onClose() } + + modifyDataSource({ + id: openWith, + mutationFunction: (old) => ({ + ...old, + isProtected: !old.isProtected + }) + }) }} > @@ -67,11 +74,10 @@ export const DataSourcesActionsDrawer: FC<{ primary="Mark as protected" secondary="This will lock and hide books behind it. Use unlock features to display them" /> - + - { onClose() removeDataSource({ id: openWith }) @@ -81,7 +87,7 @@ export const DataSourcesActionsDrawer: FC<{ - + diff --git a/packages/web/src/dataSources/effects.ts b/packages/web/src/dataSources/effects.ts deleted file mode 100644 index 7091dd40..00000000 --- a/packages/web/src/dataSources/effects.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - catchError, - switchMap, - from, - mergeMap, - EMPTY, - withLatestFrom, - filter -} from "rxjs" -import { isDefined, useSubscribeEffect } from "reactjrx" -import { latestDatabase$ } from "../rxdb/RxDbProvider" -import { toggleDatasourceProtected$ } from "./triggers" -import { Report } from "../debug/report.shared" - -const useToggleDataSourceProtectedAction = () => { - useSubscribeEffect( - () => - toggleDatasourceProtected$.pipe( - withLatestFrom(latestDatabase$), - mergeMap(([id, db]) => - from(db.datasource.findOne({ selector: { _id: id } }).exec()).pipe( - filter(isDefined), - switchMap((doc) => - from( - doc?.incrementalPatch({ - isProtected: !doc.isProtected - }) - ) - ), - catchError((err) => { - Report.error(err) - - return EMPTY - }) - ) - ) - ), - [] - ) -} - -export const effects = [useToggleDataSourceProtectedAction] diff --git a/packages/web/src/dataSources/helpers.ts b/packages/web/src/dataSources/helpers.ts index 97d808c0..3a31ff49 100644 --- a/packages/web/src/dataSources/helpers.ts +++ b/packages/web/src/dataSources/helpers.ts @@ -2,20 +2,23 @@ import { useDatabase } from "../rxdb" import { DataSourceDocType, ObokuErrorCode } from "@oboku/shared" import { Report } from "../debug/report.shared" import { plugins } from "../plugins/configure" -import { useCallback, useMemo } from "react" +import { useMemo } from "react" import { useNetworkState } from "react-use" import { useSyncReplicate } from "../rxdb/replication/useSyncReplicate" -import { catchError, EMPTY, from, switchMap, map, of, filter } from "rxjs" +import { catchError, EMPTY, from, switchMap, map, filter, first } from "rxjs" import { usePluginSynchronize } from "../plugins/usePluginSynchronize" import { isDefined, useMutation } from "reactjrx" import { isPluginError } from "../plugins/plugin-front" import { getDataSourcePlugin } from "./getDataSourcePlugin" import { httpClient } from "../http/httpClient" import { createDialog } from "../common/dialogs/createDialog" +import { latestDatabase$ } from "../rxdb/RxDbProvider" +import { ModifyFunction } from "rxdb" export const useSynchronizeDataSource = () => { const { db: database } = useDatabase() - const { atomicUpdateDataSource } = useAtomicUpdateDataSource() + const { mutateAsync: atomicUpdateDataSource } = + useDataSourceIncrementalPatch() const synchronizeDataSource = usePluginSynchronize() const network = useNetworkState() const { mutateAsync: sync } = useSyncReplicate() @@ -38,20 +41,27 @@ export const useSynchronizeDataSource = () => { filter(isDefined), switchMap((dataSource) => from(synchronizeDataSource(dataSource))), switchMap((data) => { - return atomicUpdateDataSource(_id, (old) => { - old.syncStatus = `fetching` - - return old - }).pipe( + return from( + atomicUpdateDataSource({ + id: _id, + patch: { + syncStatus: "fetching" + } + }) + ).pipe( switchMap(() => from(sync([database.datasource]))), switchMap(() => from(httpClient.syncDataSource(_id, data.data))), catchError((e) => - atomicUpdateDataSource(_id, (old) => ({ - ...old, - syncStatus: null, - lastSyncErrorCode: - ObokuErrorCode.ERROR_DATASOURCE_NETWORK_UNREACHABLE - })).pipe( + from( + atomicUpdateDataSource({ + id: _id, + patch: { + syncStatus: null, + lastSyncErrorCode: + ObokuErrorCode.ERROR_DATASOURCE_NETWORK_UNREACHABLE + } + }) + ).pipe( map((_) => { throw e }) @@ -108,23 +118,51 @@ export const useRemoveDataSource = () => { db?.datasource.findOne({ selector: { _id: id } }).remove() }) } -export const useAtomicUpdateDataSource = () => { - const { db: database } = useDatabase() - const atomicUpdateDataSource = useCallback( - (id: string, mutationFunction: any) => - of(database).pipe( - filter(isDefined), +export const useDataSourceIncrementalPatch = () => { + return useMutation({ + mutationFn: ({ + id, + patch + }: { + id: string + patch: Partial + }) => + latestDatabase$.pipe( + first(), switchMap((db) => from(db.datasource.findOne({ selector: { _id: id } }).exec()) ), - filter(isDefined), - switchMap((item) => from(item.incrementalModify(mutationFunction))) - ), - [database] - ) + switchMap((item) => { + if (!item) return EMPTY + + return from(item.incrementalPatch(patch)) + }) + ) + }) +} + +export const useDataSourceIncrementalModify = () => { + return useMutation({ + mutationFn: ({ + id, + mutationFunction + }: { + id: string + mutationFunction: ModifyFunction + }) => + latestDatabase$.pipe( + first(), + switchMap((db) => + from(db.datasource.findOne({ selector: { _id: id } }).exec()) + ), + switchMap((item) => { + if (!item) return EMPTY - return { atomicUpdateDataSource } + return from(item.incrementalModify(mutationFunction)) + }) + ) + }) } export const useDataSourceHelpers = ( diff --git a/packages/web/src/dataSources/triggers.ts b/packages/web/src/dataSources/triggers.ts deleted file mode 100644 index 53541543..00000000 --- a/packages/web/src/dataSources/triggers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ObservedValueOf, Subject } from "rxjs" - -const toggleDatasourceProtectedSubject = new Subject() - -export const toggleDatasourceProtected = ( - options: ObservedValueOf -) => toggleDatasourceProtectedSubject.next(options) - -export const toggleDatasourceProtected$ = - toggleDatasourceProtectedSubject.asObservable()