fix: add @typescript-eslint/no-floating-promises rule (#2764)

Co-authored-by: himself65 <himself65@outlook.com>
(cherry picked from commit 1c8f1a05d0)
This commit is contained in:
LongYinan
2023-06-13 14:55:23 +08:00
committed by himself65
parent 3f7a7467dc
commit 0f0d08cd22
25 changed files with 342 additions and 239 deletions
+22 -11
View File
@@ -152,6 +152,27 @@ const config = {
'@typescript-eslint/no-var-requires': 0, '@typescript-eslint/no-var-requires': 0,
}, },
}, },
...allPackages.map(pkg => ({
files: [`${pkg}/src/**/*.ts`, `${pkg}/src/**/*.tsx`],
parserOptions: {
project: resolve(__dirname, './tsconfig.eslint.json'),
},
rules: {
'@typescript-eslint/no-restricted-imports': [
'error',
{
patterns: createPattern(pkg),
},
],
'@typescript-eslint/no-floating-promises': [
'error',
{
ignoreVoid: false,
ignoreIIFE: false,
},
],
},
})),
{ {
files: [ files: [
'**/__tests__/**/*', '**/__tests__/**/*',
@@ -173,19 +194,9 @@ const config = {
'ts-check': false, 'ts-check': false,
}, },
], ],
'@typescript-eslint/no-floating-promises': 0,
}, },
}, },
...allPackages.map(pkg => ({
files: [`${pkg}/src/**/*.ts`, `${pkg}/src/**/*.tsx`],
rules: {
'@typescript-eslint/no-restricted-imports': [
'error',
{
patterns: createPattern(pkg),
},
],
},
})),
], ],
}; };
+3 -1
View File
@@ -110,7 +110,9 @@ export async function saveDBFileAs(
await fs.copyFile(db.path, filePath); await fs.copyFile(db.path, filePath);
logger.log('saved', filePath); logger.log('saved', filePath);
mainRPC.showItemInFolder(filePath); mainRPC.showItemInFolder(filePath).catch(err => {
console.error(err);
});
return { filePath }; return { filePath };
} catch (err) { } catch (err) {
logger.error('saveDBFileAs', err); logger.error('saveDBFileAs', err);
+3 -1
View File
@@ -64,7 +64,9 @@ function setupRendererConnection(rendererPort: Electron.MessagePortMain) {
for (const [key, eventRegister] of Object.entries(namespaceEvents)) { for (const [key, eventRegister] of Object.entries(namespaceEvents)) {
const subscription = eventRegister((...args: any[]) => { const subscription = eventRegister((...args: any[]) => {
const chan = `${namespace}:${key}`; const chan = `${namespace}:${key}`;
rpc.postEvent(chan, ...args); rpc.postEvent(chan, ...args).catch(err => {
console.error(err);
});
}); });
process.on('exit', () => { process.on('exit', () => {
subscription(); subscription();
@@ -15,8 +15,8 @@ AsyncCall(commandProxy, {
channel: new MessageEventChannel(parentPort), channel: new MessageEventChannel(parentPort),
}); });
import('@toeverything/plugin-infra/manager').then( import('@toeverything/plugin-infra/manager')
({ rootStore, affinePluginsAtom }) => { .then(({ rootStore, affinePluginsAtom }) => {
const bookmarkPluginPath = join( const bookmarkPluginPath = join(
process.env.PLUGIN_DIR ?? resolve(__dirname, '../plugins'), process.env.PLUGIN_DIR ?? resolve(__dirname, '../plugins'),
'./bookmark-block/index.mjs' './bookmark-block/index.mjs'
@@ -39,5 +39,7 @@ import('@toeverything/plugin-infra/manager').then(
} }
}); });
}); });
} })
); .catch(err => {
console.error(err);
});
+3 -1
View File
@@ -50,4 +50,6 @@ import { contextBridge, ipcRenderer } from 'electron';
} catch (error) { } catch (error) {
console.error('Failed to expose affine APIs to window object!', error); console.error('Failed to expose affine APIs to window object!', error);
} }
})(); })().catch(err => {
console.error('Failed to bootstrap preload script!', err);
});
+6 -2
View File
@@ -75,7 +75,9 @@ export function useHistoryAtom() {
if (forward) { if (forward) {
const target = Math.min(prev.stack.length - 1, prev.current + 1); const target = Math.min(prev.stack.length - 1, prev.current + 1);
const url = prev.stack[target]; const url = prev.stack[target];
void router.push(url); router.push(url).catch(err => {
console.error(err);
});
return { return {
...prev, ...prev,
current: target, current: target,
@@ -84,7 +86,9 @@ export function useHistoryAtom() {
} else { } else {
const target = Math.max(0, prev.current - 1); const target = Math.max(0, prev.current - 1);
const url = prev.stack[target]; const url = prev.stack[target];
void router.push(url); router.push(url).catch(err => {
console.error(err);
});
return { return {
...prev, ...prev,
current: target, current: target,
+17 -12
View File
@@ -49,19 +49,24 @@ rootWorkspacesMetadataAtom.onMount = setAtom => {
}, 0); }, 0);
if (environment.isDesktop) { if (environment.isDesktop) {
window.apis?.workspace.list().then(workspaceIDs => { window.apis?.workspace
if (abortController.signal.aborted) return; .list()
const newMetadata = workspaceIDs.map(w => ({ .then(workspaceIDs => {
id: w[0], if (abortController.signal.aborted) return;
flavour: WorkspaceFlavour.LOCAL, const newMetadata = workspaceIDs.map(w => ({
})); id: w[0],
setAtom(metadata => { flavour: WorkspaceFlavour.LOCAL,
return [ }));
...metadata, setAtom(metadata => {
...newMetadata.filter(m => !metadata.find(m2 => m2.id === m.id)), return [
]; ...metadata,
...newMetadata.filter(m => !metadata.find(m2 => m2.id === m.id)),
];
});
})
.catch(err => {
console.error(err);
}); });
});
} }
return () => { return () => {
@@ -116,9 +116,14 @@ const useDefaultDBLocation = () => {
const [defaultDBLocation, setDefaultDBLocation] = useState(''); const [defaultDBLocation, setDefaultDBLocation] = useState('');
useEffect(() => { useEffect(() => {
window.apis?.db.getDefaultStorageLocation().then(dir => { window.apis?.db
setDefaultDBLocation(dir); .getDefaultStorageLocation()
}); .then(dir => {
setDefaultDBLocation(dir);
})
.catch(err => {
console.error(err);
});
}, []); }, []);
return defaultDBLocation; return defaultDBLocation;
@@ -281,7 +286,9 @@ export const CreateWorkspaceModal = ({
} }
onClose(); onClose();
} }
})(); })().catch(err => {
console.error(err);
});
} else if (mode === 'new') { } else if (mode === 'new') {
setStep(environment.isDesktop ? 'set-db-location' : 'name-workspace'); setStep(environment.isDesktop ? 'set-db-location' : 'name-workspace');
} else { } else {
@@ -12,7 +12,7 @@ import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-s
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import clsx from 'clsx'; import clsx from 'clsx';
import type React from 'react'; import type React from 'react';
import { useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner'; import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner';
import { Upload } from '../../../../pure/file-upload'; import { Upload } from '../../../../pure/file-upload';
@@ -27,9 +27,14 @@ const useShowOpenDBFile = (workspaceId: string) => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
useEffect(() => { useEffect(() => {
if (window.apis && window.events && environment.isDesktop) { if (window.apis && window.events && environment.isDesktop) {
window.apis.workspace.getMeta(workspaceId).then(meta => { window.apis.workspace
setShow(!!meta.secondaryDBPath); .getMeta(workspaceId)
}); .then(meta => {
setShow(!!meta.secondaryDBPath);
})
.catch(err => {
console.error(err);
});
return window.events.workspace.onMetaChange((newMeta: any) => { return window.events.workspace.onMetaChange((newMeta: any) => {
if (newMeta.workspaceId === workspaceId) { if (newMeta.workspaceId === workspaceId) {
const meta = newMeta.meta; const meta = newMeta.meta;
@@ -54,35 +59,11 @@ export const GeneralPanel: React.FC<PanelProps> = ({
const isOwner = useIsWorkspaceOwner(workspace); const isOwner = useIsWorkspaceOwner(workspace);
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const showOpenFolder = useShowOpenDBFile(workspace.id);
const handleUpdateWorkspaceName = (name: string) => { const handleUpdateWorkspaceName = (name: string) => {
setName(name); setName(name);
toast(t['Update workspace name success']()); toast(t['Update workspace name success']());
}; };
const [moveToInProgress, setMoveToInProgress] = useState<boolean>(false);
const handleMoveTo = async () => {
if (moveToInProgress) {
return;
}
try {
setMoveToInProgress(true);
const result = await window.apis?.dialog.moveDBFile(workspace.id);
if (!result?.error && !result?.canceled) {
toast(t['Move folder success']());
} else if (result?.error) {
// @ts-expect-error: result.error is dynamic
toast(t[result.error]());
}
} catch (err) {
toast(t['UNKNOWN_ERROR']());
} finally {
setMoveToInProgress(false);
}
};
const [, update] = useBlockSuiteWorkspaceAvatarUrl( const [, update] = useBlockSuiteWorkspaceAvatarUrl(
workspace.blockSuiteWorkspace workspace.blockSuiteWorkspace
); );
@@ -137,9 +118,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
placeholder={t['Workspace Name']()} placeholder={t['Workspace Name']()}
maxLength={64} maxLength={64}
minLength={0} minLength={0}
onChange={newName => { onChange={setInput}
setInput(newName);
}}
></StyledInput> ></StyledInput>
</div> </div>
@@ -158,63 +137,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
</Button> </Button>
</div> </div>
</div> </div>
<DesktopClientOnly workspaceId={workspace.id} />
{environment.isDesktop && (
<div className={style.row}>
<div className={style.col}>
<div className={style.settingItemLabel}>
{t['Storage Folder']()}
</div>
<div className={style.settingItemLabelHint}>
{t['Storage Folder Hint']()}
</div>
</div>
<div className={style.col}>
{showOpenFolder && (
<div
className={style.storageTypeWrapper}
onClick={() => {
if (environment.isDesktop) {
window.apis?.dialog.revealDBFile(workspace.id);
}
}}
>
<FolderIcon color="var(--affine-primary-color)" />
<div className={style.storageTypeLabelWrapper}>
<div className={style.storageTypeLabel}>
{t['Open folder']()}
</div>
<div className={style.storageTypeLabelHint}>
{t['Open folder hint']()}
</div>
</div>
<ArrowRightSmallIcon color="var(--affine-primary-color)" />
</div>
)}
<div
data-testid="move-folder"
data-disabled={moveToInProgress}
className={style.storageTypeWrapper}
onClick={handleMoveTo}
>
<MoveToIcon color="var(--affine-primary-color)" />
<div className={style.storageTypeLabelWrapper}>
<div className={style.storageTypeLabel}>
{t['Move folder']()}
</div>
<div className={style.storageTypeLabelHint}>
{t['Move folder hint']()}
</div>
</div>
<ArrowRightSmallIcon color="var(--affine-primary-color)" />
</div>
</div>
<div className={style.col}></div>
</div>
)}
<div className={style.row}> <div className={style.row}>
<div className={style.col}> <div className={style.col}>
<div className={style.settingItemLabel}> <div className={style.settingItemLabel}>
@@ -273,3 +196,81 @@ export const GeneralPanel: React.FC<PanelProps> = ({
</> </>
); );
}; };
function DesktopClientOnly({ workspaceId }: { workspaceId: string }) {
const t = useAFFiNEI18N();
const showOpenFolder = useShowOpenDBFile(workspaceId);
const onRevealDBFile = useCallback(() => {
if (environment.isDesktop) {
window.apis?.dialog.revealDBFile(workspaceId).catch(err => {
console.error(err);
});
}
}, [workspaceId]);
const [moveToInProgress, setMoveToInProgress] = useState<boolean>(false);
const handleMoveTo = useCallback(() => {
if (moveToInProgress) {
return;
}
setMoveToInProgress(true);
window.apis?.dialog
.moveDBFile(workspaceId)
.then(result => {
if (!result?.error && !result?.canceled) {
toast(t['Move folder success']());
} else if (result?.error) {
// @ts-expect-error: result.error is dynamic
toast(t[result.error]());
}
})
.catch(() => {
toast(t['UNKNOWN_ERROR']());
})
.finally(() => {
setMoveToInProgress(false);
});
}, [moveToInProgress, t, workspaceId]);
const openFolderNode = showOpenFolder ? (
<div className={style.storageTypeWrapper} onClick={onRevealDBFile}>
<FolderIcon color="var(--affine-primary-color)" />
<div className={style.storageTypeLabelWrapper}>
<div className={style.storageTypeLabel}>{t['Open folder']()}</div>
<div className={style.storageTypeLabelHint}>
{t['Open folder hint']()}
</div>
</div>
<ArrowRightSmallIcon color="var(--affine-primary-color)" />
</div>
) : null;
return (
<div className={style.row}>
<div className={style.col}>
<div className={style.settingItemLabel}>{t['Storage Folder']()}</div>
<div className={style.settingItemLabelHint}>
{t['Storage Folder Hint']()}
</div>
</div>
<div className={style.col}>
{openFolderNode}
<div
data-testid="move-folder"
data-disabled={moveToInProgress}
className={style.storageTypeWrapper}
onClick={handleMoveTo}
>
<MoveToIcon color="var(--affine-primary-color)" />
<div className={style.storageTypeLabelWrapper}>
<div className={style.storageTypeLabel}>{t['Move folder']()}</div>
<div className={style.storageTypeLabelHint}>
{t['Move folder hint']()}
</div>
</div>
<ArrowRightSmallIcon color="var(--affine-primary-color)" />
</div>
</div>
<div className={style.col}></div>
</div>
);
}
@@ -9,7 +9,9 @@ const LanguageMenuContent: FC = () => {
const i18n = useI18N(); const i18n = useI18N();
const changeLanguage = useCallback( const changeLanguage = useCallback(
(event: string) => { (event: string) => {
void i18n.changeLanguage(event); i18n.changeLanguage(event).catch(err => {
console.error(err);
});
}, },
[i18n] [i18n]
); );
@@ -12,6 +12,7 @@ import type { PluginUIAdapter } from '@toeverything/plugin-infra/type';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react'; import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react';
import { forwardRef, memo, useEffect, useMemo, useState } from 'react'; import { forwardRef, memo, useEffect, useMemo, useState } from 'react';
import { noop } from 'rxjs';
import { guideDownloadClientTipAtom } from '../../../atoms/guide'; import { guideDownloadClientTipAtom } from '../../../atoms/guide';
import { contentLayoutAtom } from '../../../atoms/layout'; import { contentLayoutAtom } from '../../../atoms/layout';
@@ -104,27 +105,21 @@ const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
<button <button
data-type="minimize" data-type="minimize"
className={styles.windowAppControl} className={styles.windowAppControl}
onClick={() => { onClick={window.apis?.ui.handleMinimizeApp ?? noop}
window.apis?.ui.handleMinimizeApp();
}}
> >
<MinusIcon /> <MinusIcon />
</button> </button>
<button <button
data-type="maximize" data-type="maximize"
className={styles.windowAppControl} className={styles.windowAppControl}
onClick={() => { onClick={window.apis?.ui.handleMaximizeApp ?? noop}
window.apis?.ui.handleMaximizeApp();
}}
> >
<RoundedRectangleIcon /> <RoundedRectangleIcon />
</button> </button>
<button <button
data-type="close" data-type="close"
className={styles.windowAppControl} className={styles.windowAppControl}
onClick={() => { onClick={window.apis?.ui.handleCloseApp ?? noop}
window.apis?.ui.handleCloseApp();
}}
> >
<CloseIcon /> <CloseIcon />
</button> </button>
@@ -54,7 +54,9 @@ export const Footer: React.FC<FooterProps> = ({
title: query, title: query,
}); });
onClose(); onClose();
void jumpToPage(blockSuiteWorkspace.id, page.id); jumpToPage(blockSuiteWorkspace.id, page.id).catch(err => {
console.error(err);
});
}, [blockSuiteWorkspace, createPage, jumpToPage, onClose, query])} }, [blockSuiteWorkspace, createPage, jumpToPage, onClose, query])}
> >
<StyledModalFooterContent> <StyledModalFooterContent>
@@ -107,7 +107,9 @@ export const RootAppSidebar = ({
const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom); const [sidebarOpen, setSidebarOpen] = useAtom(appSidebarOpenAtom);
useEffect(() => { useEffect(() => {
if (environment.isDesktop && typeof sidebarOpen === 'boolean') { if (environment.isDesktop && typeof sidebarOpen === 'boolean') {
window.apis?.ui.handleSidebarVisibilityChange(sidebarOpen); window.apis?.ui.handleSidebarVisibilityChange(sidebarOpen).catch(err => {
console.error(err);
});
} }
}, [sidebarOpen]); }, [sidebarOpen]);
+9 -3
View File
@@ -174,7 +174,9 @@ export const CurrentWorkspaceContext = ({
useEffect(() => { useEffect(() => {
const id = setTimeout(() => { const id = setTimeout(() => {
if (!exist) { if (!exist) {
void push('/'); push('/').catch(err => {
console.error(err);
});
globalThis.HALTING_PROBLEM_TIMEOUT <<= 1; globalThis.HALTING_PROBLEM_TIMEOUT <<= 1;
} }
}, globalThis.HALTING_PROBLEM_TIMEOUT); }, globalThis.HALTING_PROBLEM_TIMEOUT);
@@ -319,7 +321,9 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
} }
if (!router.query.pageId) { if (!router.query.pageId) {
setCurrentPageId(pageId); setCurrentPageId(pageId);
void jumpToPage(currentWorkspace.id, pageId); jumpToPage(currentWorkspace.id, pageId).catch(err => {
console.error(err);
});
} }
} }
//#endregion //#endregion
@@ -353,7 +357,9 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
} }
); );
setCurrentPageId(currentPageId); setCurrentPageId(currentPageId);
void jumpToPage(currentWorkspace.id, page.id); jumpToPage(currentWorkspace.id, page.id).catch(err => {
console.error(err);
});
} }
}, [ }, [
currentPageId, currentPageId,
+14 -4
View File
@@ -39,21 +39,31 @@ const IndexPageInner = () => {
nonTrashPages.at(0)?.id; nonTrashPages.at(0)?.id;
if (pageId) { if (pageId) {
logger.debug('Found target workspace. Jump to page', pageId); logger.debug('Found target workspace. Jump to page', pageId);
void jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE); jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE).catch(
err => {
console.error(err);
}
);
} else { } else {
const clearId = setTimeout(() => { const clearId = setTimeout(() => {
dispose.dispose(); dispose.dispose();
logger.debug('Found target workspace. Jump to all pages'); logger.debug('Found target workspace. Jump to all pages');
void jumpToSubPath( jumpToSubPath(
targetWorkspace.id, targetWorkspace.id,
WorkspaceSubPath.ALL, WorkspaceSubPath.ALL,
RouteLogic.REPLACE RouteLogic.REPLACE
); ).catch(err => {
console.error(err);
});
}, 1000); }, 1000);
const dispose = const dispose =
targetWorkspace.blockSuiteWorkspace.slots.pageAdded.once(pageId => { targetWorkspace.blockSuiteWorkspace.slots.pageAdded.once(pageId => {
clearTimeout(clearId); clearTimeout(clearId);
void jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE); jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE).catch(
err => {
console.error(err);
}
);
}); });
return () => { return () => {
clearTimeout(clearId); clearTimeout(clearId);
@@ -11,7 +11,7 @@ import { atomWithStorage } from 'jotai/utils';
import Head from 'next/head'; import Head from 'next/head';
import type { NextRouter } from 'next/router'; import type { NextRouter } from 'next/router';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React, { useCallback, useEffect } from 'react'; import React, { useCallback } from 'react';
import { getUIAdapter } from '../../../adapters/workspace'; import { getUIAdapter } from '../../../adapters/workspace';
import { PageLoading } from '../../../components/pure/loading'; import { PageLoading } from '../../../components/pure/loading';
@@ -30,7 +30,7 @@ function useTabRouterSync(
router: NextRouter, router: NextRouter,
currentTab: SettingPanel, currentTab: SettingPanel,
setCurrentTab: (tab: SettingPanel) => void setCurrentTab: (tab: SettingPanel) => void
) { ): void {
if (!router.isReady) { if (!router.isReady) {
return; return;
} }
@@ -43,33 +43,36 @@ function useTabRouterSync(
settingPanelValues.indexOf(queryCurrentTab as SettingPanel) === -1 settingPanelValues.indexOf(queryCurrentTab as SettingPanel) === -1
) { ) {
setCurrentTab(settingPanel.General); setCurrentTab(settingPanel.General);
void router.replace({ router
pathname: router.pathname, .replace({
query: { pathname: router.pathname,
...router.query, query: {
currentTab: settingPanel.General, ...router.query,
}, currentTab: settingPanel.General,
}); },
return; })
.catch(console.error);
} else if (settingPanelValues.indexOf(currentTab as SettingPanel) === -1) { } else if (settingPanelValues.indexOf(currentTab as SettingPanel) === -1) {
setCurrentTab(settingPanel.General); setCurrentTab(settingPanel.General);
void router.replace({ router
pathname: router.pathname, .replace({
query: { pathname: router.pathname,
...router.query, query: {
currentTab: settingPanel.General, ...router.query,
}, currentTab: settingPanel.General,
}); },
return; })
.catch(console.error);
} else if (queryCurrentTab !== currentTab) { } else if (queryCurrentTab !== currentTab) {
void router.replace({ router
pathname: router.pathname, .replace({
query: { pathname: router.pathname,
...router.query, query: {
currentTab: currentTab, ...router.query,
}, currentTab: currentTab,
}); },
return; })
.catch(console.error);
} }
} }
@@ -78,20 +81,24 @@ const SettingPage: NextPageWithLayout = () => {
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [currentTab, setCurrentTab] = useAtom(settingPanelAtom); const [currentTab, setCurrentTab] = useAtom(settingPanelAtom);
useEffect(() => {});
const onChangeTab = useCallback( const onChangeTab = useCallback(
(tab: SettingPanel) => { (tab: SettingPanel) => {
setCurrentTab(tab as SettingPanel); setCurrentTab(tab as SettingPanel);
void router.push({ router
pathname: router.pathname, .push({
query: { pathname: router.pathname,
...router.query, query: {
currentTab: tab, ...router.query,
}, currentTab: tab,
}); },
})
.catch(err => {
console.error(err);
});
}, },
[router, setCurrentTab] [router, setCurrentTab]
); );
useTabRouterSync(router, currentTab, setCurrentTab); useTabRouterSync(router, currentTab, setCurrentTab);
const helper = useAppHelper(); const helper = useAppHelper();
@@ -49,7 +49,9 @@ export const updateAvailableAtom = atomWithObservable(() => {
return rpcToObservable(null as any | null, { return rpcToObservable(null as any | null, {
event: window.events?.updater.onUpdateAvailable, event: window.events?.updater.onUpdateAvailable,
onSubscribe: () => { onSubscribe: () => {
window.apis?.updater.checkForUpdatesAndNotify(); window.apis?.updater.checkForUpdatesAndNotify().catch(err => {
console.error(err);
});
}, },
}); });
}); });
@@ -65,7 +65,10 @@ export function AppUpdaterButton({ className, style }: AddPageButtonProps) {
}, [currentVersion, setChangelogCheckAtom]); }, [currentVersion, setChangelogCheckAtom]);
const onClickUpdate = useCallback(() => { const onClickUpdate = useCallback(() => {
if (updateReady) { if (updateReady) {
window.apis?.updater.quitAndInstall(); window.apis?.updater.quitAndInstall().catch(err => {
// TODO: add error toast here
console.error(err);
});
} else if (updateAvailable) { } else if (updateAvailable) {
if (updateAvailable.allowAutoUpdate) { if (updateAvailable.allowAutoUpdate) {
// wait for download to finish // wait for download to finish
@@ -9,8 +9,15 @@ export const CopyLink = ({ onItemClick, onSelect }: CommonMenuItemProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const copyUrl = useCallback(() => { const copyUrl = useCallback(() => {
navigator.clipboard.writeText(window.location.href); navigator.clipboard
toast(t['Copied link to clipboard']()); .writeText(window.location.href)
.then(() => {
toast(t['Copied link to clipboard']());
})
.catch(err => {
// TODO add error toast here
console.error(err);
});
}, [t]); }, [t]);
return ( return (
@@ -35,8 +35,13 @@ const ExportToPdfMenuItem = ({
if (result !== undefined) { if (result !== undefined) {
return; return;
} }
contentParser.exportPdf(); return contentParser.exportPdf();
})
.then(() => {
onSelect?.({ type: 'pdf' }); onSelect?.({ type: 'pdf' });
})
.catch(err => {
console.error(err);
}); });
}, [currentEditor, onSelect]); }, [currentEditor, onSelect]);
if (currentEditor && currentEditor.mode === 'page') { if (currentEditor && currentEditor.mode === 'page') {
@@ -66,7 +71,9 @@ const ExportToHtmlMenuItem = ({
if (!contentParserRef.current) { if (!contentParserRef.current) {
contentParserRef.current = new ContentParser(currentEditor.page); contentParserRef.current = new ContentParser(currentEditor.page);
} }
contentParserRef.current.exportHtml(); contentParserRef.current.exportHtml().catch(err => {
console.error(err);
});
onSelect?.({ type: 'html' }); onSelect?.({ type: 'html' });
}, [onSelect, currentEditor]); }, [onSelect, currentEditor]);
return ( return (
@@ -123,7 +130,9 @@ const ExportToMarkdownMenuItem = ({
if (!contentParserRef.current) { if (!contentParserRef.current) {
contentParserRef.current = new ContentParser(currentEditor.page); contentParserRef.current = new ContentParser(currentEditor.page);
} }
contentParserRef.current.exportMarkdown(); contentParserRef.current.exportMarkdown().catch(err => {
console.error(err);
});
onSelect?.({ type: 'markdown' }); onSelect?.({ type: 'markdown' });
}, [onSelect, currentEditor]); }, [onSelect, currentEditor]);
return ( return (
@@ -10,7 +10,11 @@ const DesktopThemeSync = memo(function DesktopThemeSync() {
const onceRef = useRef(false); const onceRef = useRef(false);
if (lastThemeRef.current !== theme || !onceRef.current) { if (lastThemeRef.current !== theme || !onceRef.current) {
if (environment.isDesktop && theme) { if (environment.isDesktop && theme) {
window.apis?.ui.handleThemeChange(theme as 'dark' | 'light' | 'system'); window.apis?.ui
.handleThemeChange(theme as 'dark' | 'light' | 'system')
.catch(err => {
console.error(err);
});
} }
lastThemeRef.current = theme; lastThemeRef.current = theme;
onceRef.current = true; onceRef.current = true;
+14 -9
View File
@@ -32,15 +32,20 @@ export function definePlugin<ID extends string>(
if (isServer) { if (isServer) {
if (serverAdapter) { if (serverAdapter) {
serverAdapter.load().then(({ default: adapter }) => { serverAdapter
rootStore.set(affinePluginsAtom, plugins => ({ .load()
...plugins, .then(({ default: adapter }) => {
[definition.id]: { rootStore.set(affinePluginsAtom, plugins => ({
...basePlugin, ...plugins,
serverAdapter: adapter, [definition.id]: {
}, ...basePlugin,
})); serverAdapter: adapter,
}); },
}));
})
.catch(err => {
console.error(err);
});
} }
} else if (isClient) { } else if (isClient) {
if (blockSuiteAdapter) { if (blockSuiteAdapter) {
+4 -2
View File
@@ -171,7 +171,9 @@ const createSQLiteProvider = (
if (origin === sqliteOrigin) { if (origin === sqliteOrigin) {
return; return;
} }
apis.db.applyDocUpdate(blockSuiteWorkspace.id, update); apis.db.applyDocUpdate(blockSuiteWorkspace.id, update).catch(err => {
console.error(err);
});
} }
let unsubscribe = () => {}; let unsubscribe = () => {};
@@ -247,7 +249,7 @@ const createSQLiteDBDownloadProvider = (
const diff = Y.encodeStateAsUpdate(blockSuiteWorkspace.doc, updates); const diff = Y.encodeStateAsUpdate(blockSuiteWorkspace.doc, updates);
// also apply updates to sqlite // also apply updates to sqlite
apis.db.applyDocUpdate(blockSuiteWorkspace.id, diff); await apis.db.applyDocUpdate(blockSuiteWorkspace.id, diff);
const bs = blockSuiteWorkspace.blobs; const bs = blockSuiteWorkspace.blobs;
+38 -37
View File
@@ -12,47 +12,48 @@ import { openAIApiKeyAtom, useChatAtoms } from '../core/hooks';
import { detailContentActionsStyle, detailContentStyle } from './index.css'; import { detailContentActionsStyle, detailContentStyle } from './index.css';
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
import('@blocksuite/blocks').then(({ FormatQuickBar }) => { import('@blocksuite/blocks')
FormatQuickBar.customElements.push((_page, getSelection) => { .then(({ FormatQuickBar }) => {
const div = document.createElement('div'); FormatQuickBar.customElements.push((_page, getSelection) => {
const root = createRoot(div); const div = document.createElement('div');
const root = createRoot(div);
const AskAI = (): ReactElement => { const AskAI = (): ReactElement => {
const { conversationAtom } = useChatAtoms(); const { conversationAtom } = useChatAtoms();
const call = useSetAtom(conversationAtom); const call = useSetAtom(conversationAtom);
const onClickAskAI = useCallback(() => {
const selection = getSelection();
if (selection != null) {
const text = selection.models
.map(model => {
return model.text?.toString();
})
.filter((v): v is string => Boolean(v))
.join('\n');
console.log('selected text:', text);
call(
`I selected some text from the document: \n"${text}."`
).catch(err => {
console.error(err);
});
}
}, [call]);
return ( return <div onClick={onClickAskAI}>Ask AI</div>;
<div };
onClick={() => { root.render(
const selection = getSelection(); <StrictMode>
if (selection != null) { <Provider store={rootStore}>
const text = selection.models <AskAI />
.map(model => { </Provider>
return model.text?.toString(); </StrictMode>
})
.filter((v): v is string => Boolean(v))
.join('\n');
console.log('selected text:', text);
void call(
`I selected some text from the document: \n"${text}."`
);
}
}}
>
Ask AI
</div>
); );
}; return div;
root.render( });
<StrictMode> })
<Provider store={rootStore}> .catch(error => {
<AskAI /> console.error(error);
</Provider>
</StrictMode>
);
return div;
}); });
});
} }
const Actions = () => { const Actions = () => {
+16 -6
View File
@@ -49,9 +49,14 @@ const getConversationAtom = (chat: ConversationChain) => {
throw new Error(); throw new Error();
} }
const memory = chat.memory as BufferMemory; const memory = chat.memory as BufferMemory;
void memory.chatHistory.getMessages().then(messages => { memory.chatHistory
setAtom(messages); .getMessages()
}); .then(messages => {
setAtom(messages);
})
.catch(err => {
console.error(err);
});
const llmStart = (): void => { const llmStart = (): void => {
setAtom(conversations => [...conversations, new AIChatMessage('')]); setAtom(conversations => [...conversations, new AIChatMessage('')]);
}; };
@@ -86,9 +91,14 @@ const getConversationAtom = (chat: ConversationChain) => {
}); });
// refresh messages // refresh messages
const memory = chat.memory as BufferMemory; const memory = chat.memory as BufferMemory;
void memory.chatHistory.getMessages().then(messages => { memory.chatHistory
set(conversationBaseAtom, messages); .getMessages()
}); .then(messages => {
set(conversationBaseAtom, messages);
})
.catch(err => {
console.error(err);
});
} }
); );
conversationWeakMap.set(chat, conversationAtom); conversationWeakMap.set(chat, conversationAtom);