mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-07 20:31:33 +08:00
Merge branch 'canary' into stable
This commit is contained in:
@@ -9,8 +9,9 @@
|
||||
"foxact": "^0.2.20",
|
||||
"image-blob-reduce": "^4.1.0",
|
||||
"jotai": "^2.5.1",
|
||||
"jotai-effect": "^0.2.3",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"p-queue": "^7.4.1",
|
||||
"p-queue": "^8.0.0",
|
||||
"react": "18.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"swr": "2.2.4",
|
||||
@@ -19,13 +20,14 @@
|
||||
"devDependencies": {
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/env": "workspace:*",
|
||||
"@blocksuite/block-std": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/blocks": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/editor": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/global": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/lit": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/store": "0.0.0-20231124123613-7c06e95d-nightly",
|
||||
"@blocksuite/block-std": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@blocksuite/blocks": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@blocksuite/global": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@blocksuite/lit": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@blocksuite/presets": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@blocksuite/store": "0.11.0-nightly-202312070955-2b5bb47",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@toeverything/infra": "workspace:*",
|
||||
"@types/image-blob-reduce": "^4.1.3",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"fake-indexeddb": "^5.0.0",
|
||||
@@ -35,8 +37,8 @@
|
||||
"peerDependencies": {
|
||||
"@blocksuite/block-std": "*",
|
||||
"@blocksuite/blocks": "*",
|
||||
"@blocksuite/editor": "*",
|
||||
"@blocksuite/global": "*",
|
||||
"@blocksuite/presets": "*",
|
||||
"@blocksuite/store": "*",
|
||||
"y-provider": "workspace:*"
|
||||
},
|
||||
@@ -50,10 +52,10 @@
|
||||
"@blocksuite/blocks": {
|
||||
"optional": true
|
||||
},
|
||||
"@blocksuite/editor": {
|
||||
"@blocksuite/global": {
|
||||
"optional": true
|
||||
},
|
||||
"@blocksuite/global": {
|
||||
"@blocksuite/presets": {
|
||||
"optional": true
|
||||
},
|
||||
"@blocksuite/store": {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { isBrowser } from '@affine/env/constant';
|
||||
import { appSettingAtom } from '@toeverything/infra/atom';
|
||||
import type { UpdateMeta } from '@toeverything/infra/type';
|
||||
import { atom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import { atom, useAtom, useAtomValue } from 'jotai';
|
||||
import { atomWithObservable, atomWithStorage } from 'jotai/utils';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { useAsyncCallback } from './affine-async-hooks';
|
||||
|
||||
function rpcToObservable<
|
||||
T,
|
||||
H extends () => Promise<T>,
|
||||
@@ -41,25 +44,21 @@ function rpcToObservable<
|
||||
});
|
||||
}
|
||||
|
||||
// download complete, ready to install
|
||||
export const updateReadyAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as UpdateMeta | null, {
|
||||
event: window.events?.updater.onUpdateReady,
|
||||
});
|
||||
});
|
||||
|
||||
export const updateAvailableStateAtom = atom<UpdateMeta | null>(null);
|
||||
|
||||
export const updateAvailableAtom = atomWithObservable(get => {
|
||||
return rpcToObservable(get(updateAvailableStateAtom), {
|
||||
// update available, but not downloaded yet
|
||||
export const updateAvailableAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as UpdateMeta | null, {
|
||||
event: window.events?.updater.onUpdateAvailable,
|
||||
onSubscribe: () => {
|
||||
window.apis?.updater.checkForUpdatesAndNotify().catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// downloading new update
|
||||
export const downloadProgressAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as number | null, {
|
||||
event: window.events?.updater.onDownloadProgress,
|
||||
@@ -71,6 +70,8 @@ export const changelogCheckedAtom = atomWithStorage<Record<string, boolean>>(
|
||||
{}
|
||||
);
|
||||
|
||||
export const checkingForUpdatesAtom = atom(false);
|
||||
|
||||
export const currentVersionAtom = atom(async () => {
|
||||
if (!isBrowser) {
|
||||
return null;
|
||||
@@ -79,29 +80,43 @@ export const currentVersionAtom = atom(async () => {
|
||||
return currentVersion;
|
||||
});
|
||||
|
||||
export const currentChangelogUnreadAtom = atom(async get => {
|
||||
if (!isBrowser) {
|
||||
const currentChangelogUnreadAtom = atom(
|
||||
async get => {
|
||||
if (!isBrowser) {
|
||||
return false;
|
||||
}
|
||||
const mapping = get(changelogCheckedAtom);
|
||||
const currentVersion = await get(currentVersionAtom);
|
||||
if (currentVersion) {
|
||||
return !mapping[currentVersion];
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async (get, set, v: boolean) => {
|
||||
const currentVersion = await get(currentVersionAtom);
|
||||
if (currentVersion) {
|
||||
set(changelogCheckedAtom, mapping => {
|
||||
return {
|
||||
...mapping,
|
||||
[currentVersion]: v,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
const mapping = get(changelogCheckedAtom);
|
||||
const currentVersion = await get(currentVersionAtom);
|
||||
if (currentVersion) {
|
||||
return !mapping[currentVersion];
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
export const isCheckingForUpdatesAtom = atom(false);
|
||||
export const isAutoDownloadUpdateAtom = atom(true);
|
||||
export const isAutoCheckUpdateAtom = atom(true);
|
||||
);
|
||||
|
||||
export const useAppUpdater = () => {
|
||||
const [appQuitting, setAppQuitting] = useState(false);
|
||||
const updateReady = useAtomValue(updateReadyAtom);
|
||||
const setUpdateAvailableState = useSetAtom(updateAvailableStateAtom);
|
||||
const setIsCheckingForUpdates = useSetAtom(isCheckingForUpdatesAtom);
|
||||
const setIsAutoCheckUpdate = useSetAtom(isAutoCheckUpdateAtom);
|
||||
const setIsAutoDownloadUpdate = useSetAtom(isAutoDownloadUpdateAtom);
|
||||
const [setting, setSetting] = useAtom(appSettingAtom);
|
||||
const downloadProgress = useAtomValue(downloadProgressAtom);
|
||||
const [changelogUnread, setChangelogUnread] = useAtom(
|
||||
currentChangelogUnreadAtom
|
||||
);
|
||||
|
||||
const [checkingForUpdates, setCheckingForUpdates] = useAtom(
|
||||
checkingForUpdatesAtom
|
||||
);
|
||||
|
||||
const quitAndInstall = useCallback(() => {
|
||||
if (updateReady) {
|
||||
@@ -114,73 +129,64 @@ export const useAppUpdater = () => {
|
||||
}, [updateReady]);
|
||||
|
||||
const checkForUpdates = useCallback(async () => {
|
||||
setIsCheckingForUpdates(true);
|
||||
if (checkingForUpdates) {
|
||||
return;
|
||||
}
|
||||
setCheckingForUpdates(true);
|
||||
try {
|
||||
const updateInfo = await window.apis?.updater.checkForUpdatesAndNotify();
|
||||
setIsCheckingForUpdates(false);
|
||||
if (updateInfo) {
|
||||
const updateMeta: UpdateMeta = {
|
||||
version: updateInfo.version,
|
||||
allowAutoUpdate: false,
|
||||
};
|
||||
setUpdateAvailableState(updateMeta);
|
||||
return updateInfo.version;
|
||||
}
|
||||
return false;
|
||||
const updateInfo = await window.apis?.updater.checkForUpdates();
|
||||
return updateInfo?.version ?? false;
|
||||
} catch (err) {
|
||||
setIsCheckingForUpdates(false);
|
||||
console.error('Error checking for updates:', err);
|
||||
return null;
|
||||
} finally {
|
||||
setCheckingForUpdates(false);
|
||||
}
|
||||
}, [setIsCheckingForUpdates, setUpdateAvailableState]);
|
||||
}, [checkingForUpdates, setCheckingForUpdates]);
|
||||
|
||||
const downloadUpdate = useCallback(() => {
|
||||
window.apis?.updater
|
||||
.downloadUpdate()
|
||||
.then(() => {})
|
||||
.catch(err => {
|
||||
console.error('Error downloading update:', err);
|
||||
});
|
||||
window.apis?.updater.downloadUpdate().catch(err => {
|
||||
console.error('Error downloading update:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleAutoDownload = useCallback(
|
||||
(enable: boolean) => {
|
||||
window.apis?.updater
|
||||
.setConfig({
|
||||
autoDownloadUpdate: enable,
|
||||
})
|
||||
.then(() => {
|
||||
setIsAutoDownloadUpdate(enable);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error setting auto download:', err);
|
||||
});
|
||||
setSetting({
|
||||
autoDownloadUpdate: enable,
|
||||
});
|
||||
},
|
||||
[setIsAutoDownloadUpdate]
|
||||
[setSetting]
|
||||
);
|
||||
|
||||
const toggleAutoCheck = useCallback(
|
||||
(enable: boolean) => {
|
||||
window.apis?.updater
|
||||
.setConfig({
|
||||
autoCheckUpdate: enable,
|
||||
})
|
||||
.then(() => {
|
||||
setIsAutoCheckUpdate(enable);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error setting auto check:', err);
|
||||
});
|
||||
setSetting({
|
||||
autoCheckUpdate: enable,
|
||||
});
|
||||
},
|
||||
[setIsAutoCheckUpdate]
|
||||
[setSetting]
|
||||
);
|
||||
|
||||
const readChangelog = useAsyncCallback(async () => {
|
||||
await setChangelogUnread(true);
|
||||
}, [setChangelogUnread]);
|
||||
|
||||
return {
|
||||
quitAndInstall,
|
||||
appQuitting,
|
||||
checkForUpdates,
|
||||
downloadUpdate,
|
||||
toggleAutoDownload,
|
||||
toggleAutoCheck,
|
||||
appQuitting,
|
||||
checkingForUpdates,
|
||||
autoCheck: setting.autoCheckUpdate,
|
||||
autoDownload: setting.autoDownloadUpdate,
|
||||
changelogUnread,
|
||||
readChangelog,
|
||||
updateReady,
|
||||
updateAvailable: useAtomValue(updateAvailableAtom),
|
||||
downloadProgress,
|
||||
currentVersion: useAtomValue(currentVersionAtom),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ export function useBlockSuitePagePreview(page: Page | null): Atom<string> {
|
||||
page.slots.ready.on(() => {
|
||||
set(getPagePreviewText(page));
|
||||
}),
|
||||
page.slots.yUpdated.on(() => {
|
||||
page.slots.blockUpdated.on(() => {
|
||||
set(getPagePreviewText(page));
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -5,12 +5,9 @@ import { useBlockSuiteWorkspacePage } from './use-block-suite-workspace-page';
|
||||
|
||||
const weakMap = new WeakMap<Page, Atom<string[]>>();
|
||||
function getPageReferences(page: Page): string[] {
|
||||
// todo: is there a way to use page indexer to get all references?
|
||||
return ['affine:paragraph', 'affine:list', 'affine:database']
|
||||
.flatMap(f => page.getBlockByFlavour(f))
|
||||
.flatMap(b => b.text?.toDelta())
|
||||
.map(v => v?.attributes?.reference?.pageId)
|
||||
.filter(Boolean);
|
||||
return Object.values(
|
||||
page.workspace.indexer.backlink.linkIndexMap[page.id] ?? {}
|
||||
).flatMap(linkNodes => linkNodes.map(linkNode => linkNode.pageId));
|
||||
}
|
||||
|
||||
const getPageReferencesAtom = (page: Page | null) => {
|
||||
@@ -25,7 +22,7 @@ const getPageReferencesAtom = (page: Page | null) => {
|
||||
page.slots.ready.on(() => {
|
||||
set(getPageReferences(page));
|
||||
}),
|
||||
page.slots.yUpdated.on(() => {
|
||||
page.workspace.indexer.backlink.slots.indexUpdated.on(() => {
|
||||
set(getPageReferences(page));
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -4,24 +4,22 @@ import debounce from 'lodash.debounce';
|
||||
import { type RefObject, useEffect, useState } from 'react';
|
||||
|
||||
export function useIsTinyScreen({
|
||||
mainContainer,
|
||||
container,
|
||||
leftStatic,
|
||||
leftSlot,
|
||||
centerDom,
|
||||
rightStatic,
|
||||
rightSlot,
|
||||
}: {
|
||||
mainContainer: HTMLElement | null;
|
||||
container: HTMLElement | null;
|
||||
leftStatic: RefObject<HTMLElement>;
|
||||
leftSlot: RefObject<HTMLElement>[];
|
||||
centerDom: RefObject<HTMLElement>;
|
||||
rightStatic: RefObject<HTMLElement>;
|
||||
rightSlot: RefObject<HTMLElement>[];
|
||||
}) {
|
||||
const [isTinyScreen, setIsTinyScreen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mainContainer) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const handleResize = debounce(() => {
|
||||
@@ -33,8 +31,6 @@ export function useIsTinyScreen({
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
|
||||
const rightStaticWidth = rightStatic.current?.clientWidth || 0;
|
||||
|
||||
const rightSlotWidth = rightSlot.reduce((accWidth, dom) => {
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
@@ -46,14 +42,13 @@ export function useIsTinyScreen({
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = mainContainer.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const centerRect = centerDom.current.getBoundingClientRect();
|
||||
|
||||
if (
|
||||
leftStaticWidth + leftSlotWidth + containerRect.left >=
|
||||
centerRect.left ||
|
||||
containerRect.right - centerRect.right <=
|
||||
rightSlotWidth + rightStaticWidth
|
||||
containerRect.right - centerRect.right <= rightSlotWidth
|
||||
) {
|
||||
setIsTinyScreen(true);
|
||||
} else {
|
||||
@@ -67,20 +62,12 @@ export function useIsTinyScreen({
|
||||
handleResize();
|
||||
});
|
||||
|
||||
resizeObserver.observe(mainContainer);
|
||||
resizeObserver.observe(container);
|
||||
|
||||
return () => {
|
||||
resizeObserver.unobserve(mainContainer);
|
||||
resizeObserver.unobserve(container);
|
||||
};
|
||||
}, [
|
||||
centerDom,
|
||||
isTinyScreen,
|
||||
leftSlot,
|
||||
leftStatic,
|
||||
mainContainer,
|
||||
rightSlot,
|
||||
rightStatic,
|
||||
]);
|
||||
}, [centerDom, isTinyScreen, leftSlot, leftStatic, container, rightSlot]);
|
||||
|
||||
return isTinyScreen;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"references": [
|
||||
{ "path": "../../common/env" },
|
||||
{ "path": "../../common/y-indexeddb" },
|
||||
{ "path": "../../common/debug" }
|
||||
{ "path": "../../common/debug" },
|
||||
{ "path": "../../common/infra" }
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user