mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
fix(electron): share page in electron issues (#8703)
fix AF-1592 fix AF-1612
This commit is contained in:
@@ -116,6 +116,12 @@ window.addEventListener('focus', () => {
|
||||
frameworkProvider.get(LifecycleService).applicationFocus();
|
||||
});
|
||||
frameworkProvider.get(LifecycleService).applicationStart();
|
||||
window.addEventListener('unload', () => {
|
||||
frameworkProvider
|
||||
.get(DesktopApiService)
|
||||
.api.handler.ui.pingAppLayoutReady(false)
|
||||
.catch(console.error);
|
||||
});
|
||||
|
||||
events?.applicationMenu.openAboutPageInSettingModal(() =>
|
||||
frameworkProvider.get(GlobalDialogService).open('setting', {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useAppSettingHelper } from '@affine/core/components/hooks/affine/use-app-setting-helper';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { ThemeProvider } from '@affine/core/components/theme-provider';
|
||||
import { configureAppSidebarModule } from '@affine/core/modules/app-sidebar';
|
||||
import { ShellAppSidebarFallback } from '@affine/core/modules/app-sidebar/views';
|
||||
@@ -43,6 +44,11 @@ export function App() {
|
||||
<div className={styles.body}>
|
||||
<ShellAppSidebarFallback />
|
||||
</div>
|
||||
{environment.isWindows && (
|
||||
<div style={{ position: 'fixed', right: 0, top: 0, zIndex: 5 }}>
|
||||
<WindowsAppControls />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</I18nProvider>
|
||||
</ThemeProvider>
|
||||
|
||||
@@ -47,7 +47,9 @@ if (process.env.SKIP_ONBOARDING) {
|
||||
*/
|
||||
const isSingleInstance = app.requestSingleInstanceLock();
|
||||
if (!isSingleInstance) {
|
||||
logger.info('Another instance is running, exiting...');
|
||||
logger.info(
|
||||
'Another instance is running or responding deep link, exiting...'
|
||||
);
|
||||
app.quit();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@ import {
|
||||
pingAppLayoutReady,
|
||||
showDevTools,
|
||||
showTab,
|
||||
updateActiveViewMeta,
|
||||
updateWorkbenchMeta,
|
||||
updateWorkbenchViewMeta,
|
||||
} from '../windows-manager';
|
||||
import { showTabContextMenu } from '../windows-manager/context-menu';
|
||||
import { getOrCreateCustomThemeWindow } from '../windows-manager/custom-theme-window';
|
||||
import type { WorkbenchViewMeta } from '../windows-manager/tab-views-meta-schema';
|
||||
import { getChallengeResponse } from './challenge';
|
||||
import { uiSubjects } from './subject';
|
||||
|
||||
@@ -173,6 +175,9 @@ export const uiHandlers = {
|
||||
getTabViewsMeta: async () => {
|
||||
return getTabViewsMeta();
|
||||
},
|
||||
updateActiveViewMeta: async (e, meta: Partial<WorkbenchViewMeta>) => {
|
||||
return updateActiveViewMeta(e.sender, meta);
|
||||
},
|
||||
getTabsStatus: async () => {
|
||||
return getTabsStatus();
|
||||
},
|
||||
@@ -197,8 +202,8 @@ export const uiHandlers = {
|
||||
uiSubjects.onToggleRightSidebar$.next(tabId);
|
||||
}
|
||||
},
|
||||
pingAppLayoutReady: async e => {
|
||||
pingAppLayoutReady(e.sender);
|
||||
pingAppLayoutReady: async (e, ready = true) => {
|
||||
pingAppLayoutReady(e.sender, ready);
|
||||
},
|
||||
showDevTools: async (_, ...args: Parameters<typeof showDevTools>) => {
|
||||
return showDevTools(...args);
|
||||
|
||||
@@ -270,7 +270,14 @@ export class WebContentViewsManager {
|
||||
}
|
||||
};
|
||||
|
||||
getViewIdFromWebContentsId = (id: number) => {
|
||||
setTabUIUnready = (tabId: string) => {
|
||||
this.appTabsUIReady$.next(
|
||||
new Set([...this.appTabsUIReady$.value].filter(key => key !== tabId))
|
||||
);
|
||||
this.reorderViews();
|
||||
};
|
||||
|
||||
getWorkbenchIdFromWebContentsId = (id: number) => {
|
||||
return Array.from(this.tabViewsMap.entries()).find(
|
||||
([, view]) => view.webContents.id === id
|
||||
)?.[0];
|
||||
@@ -303,7 +310,7 @@ export class WebContentViewsManager {
|
||||
|
||||
updateWorkbenchViewMeta = (
|
||||
workbenchId: string,
|
||||
viewId: string,
|
||||
viewId: string | number,
|
||||
patch: Partial<WorkbenchViewMeta>
|
||||
) => {
|
||||
const workbench = this.tabViewsMeta.workbenches.find(
|
||||
@@ -313,7 +320,10 @@ export class WebContentViewsManager {
|
||||
return;
|
||||
}
|
||||
const views = workbench.views;
|
||||
const viewIndex = views.findIndex(v => v.id === viewId);
|
||||
const viewIndex =
|
||||
typeof viewId === 'string'
|
||||
? views.findIndex(v => v.id === viewId)
|
||||
: viewId;
|
||||
if (viewIndex === -1) {
|
||||
return;
|
||||
}
|
||||
@@ -821,12 +831,6 @@ export class WebContentViewsManager {
|
||||
view.webContents.on('did-finish-load', () => {
|
||||
unsub = helperProcessManager.connectRenderer(view.webContents);
|
||||
});
|
||||
view.webContents.on('will-navigate', () => {
|
||||
// means the view is reloaded
|
||||
this.appTabsUIReady$.next(
|
||||
new Set([...this.appTabsUIReady$.value].filter(key => key !== viewId))
|
||||
);
|
||||
});
|
||||
} else {
|
||||
view.webContents.on('focus', () => {
|
||||
globalThis.setTimeout(() => {
|
||||
@@ -943,7 +947,7 @@ export const updateWorkbenchMeta = (
|
||||
|
||||
export const updateWorkbenchViewMeta = (
|
||||
workbenchId: string,
|
||||
viewId: string,
|
||||
viewId: string | number,
|
||||
meta: Partial<WorkbenchViewMeta>
|
||||
) => {
|
||||
WebContentViewsManager.instance.updateWorkbenchViewMeta(
|
||||
@@ -956,6 +960,24 @@ export const updateWorkbenchViewMeta = (
|
||||
export const getWorkbenchMeta = (id: string) => {
|
||||
return TabViewsMetaState.value.workbenches.find(w => w.id === id);
|
||||
};
|
||||
|
||||
export const updateActiveViewMeta = (
|
||||
wc: WebContents,
|
||||
meta: Partial<WorkbenchViewMeta>
|
||||
) => {
|
||||
const workbenchId =
|
||||
WebContentViewsManager.instance.getWorkbenchIdFromWebContentsId(wc.id);
|
||||
const workbench = workbenchId ? getWorkbenchMeta(workbenchId) : undefined;
|
||||
|
||||
if (workbench && workbenchId) {
|
||||
return WebContentViewsManager.instance.updateWorkbenchViewMeta(
|
||||
workbenchId,
|
||||
workbench.activeViewIndex,
|
||||
meta
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const getTabViewsMeta = () => TabViewsMetaState.value;
|
||||
export const isActiveTab = (wc: WebContents) => {
|
||||
return (
|
||||
@@ -1042,12 +1064,15 @@ export const showDevTools = (id?: string) => {
|
||||
.catch(console.error);
|
||||
};
|
||||
|
||||
export const pingAppLayoutReady = (wc: WebContents) => {
|
||||
const viewId = WebContentViewsManager.instance.getViewIdFromWebContentsId(
|
||||
wc.id
|
||||
);
|
||||
export const pingAppLayoutReady = (wc: WebContents, ready: boolean) => {
|
||||
const viewId =
|
||||
WebContentViewsManager.instance.getWorkbenchIdFromWebContentsId(wc.id);
|
||||
if (viewId) {
|
||||
WebContentViewsManager.instance.setTabUIReady(viewId);
|
||||
if (ready) {
|
||||
WebContentViewsManager.instance.setTabUIReady(viewId);
|
||||
} else {
|
||||
WebContentViewsManager.instance.setTabUIUnready(viewId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export const SharePageNotFoundError = () => {
|
||||
left: '16px',
|
||||
fontSize: '24px',
|
||||
cursor: 'pointer',
|
||||
color: 'inherit',
|
||||
}}
|
||||
>
|
||||
<Logo1Icon />
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '@affine/core/modules/editor';
|
||||
import { PeekViewManagerModal } from '@affine/core/modules/peek-view';
|
||||
import { ShareReaderService } from '@affine/core/modules/share-doc';
|
||||
import { ViewIcon, ViewTitle } from '@affine/core/modules/workbench';
|
||||
import { CloudBlobStorage } from '@affine/core/modules/workspace-engine';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -42,7 +43,13 @@ import {
|
||||
WorkspacesService,
|
||||
} from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
type ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { PageNotFound } from '../../404';
|
||||
@@ -100,17 +107,12 @@ export const SharePage = ({
|
||||
shareReaderService.reader.loadShare({ workspaceId, docId });
|
||||
}, [shareReaderService, docId, workspaceId]);
|
||||
|
||||
let element: ReactNode = null;
|
||||
|
||||
if (isLoading) {
|
||||
return <AppContainer fallback />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
// TODO(@eyhn): show error details
|
||||
return <SharePageNotFoundError />;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
return (
|
||||
element = null;
|
||||
} else if (data) {
|
||||
element = (
|
||||
<SharePageInner
|
||||
workspaceId={data.workspaceId}
|
||||
docId={data.docId}
|
||||
@@ -123,9 +125,13 @@ export const SharePage = ({
|
||||
templateSnapshotUrl={templateSnapshotUrl}
|
||||
/>
|
||||
);
|
||||
} else if (error) {
|
||||
element = <SharePageNotFoundError />;
|
||||
} else {
|
||||
return <PageNotFound noPermission />;
|
||||
element = <PageNotFound noPermission />;
|
||||
}
|
||||
|
||||
return <AppContainer fallback={!element}>{element}</AppContainer>;
|
||||
};
|
||||
|
||||
const SharePageInner = ({
|
||||
@@ -230,7 +236,8 @@ const SharePageInner = ({
|
||||
graphQLService,
|
||||
]);
|
||||
|
||||
const pageTitle = useLiveData(page?.title$);
|
||||
const t = useI18n();
|
||||
const pageTitle = useLiveData(page?.title$) ?? t['unnamed']();
|
||||
const { jumpToPageBlock, openPage } = useNavigateHelper();
|
||||
|
||||
usePageDocumentTitle(pageTitle);
|
||||
@@ -276,43 +283,45 @@ const SharePageInner = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<AppContainer>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<FrameworkScope scope={page.scope}>
|
||||
<FrameworkScope scope={editor.scope}>
|
||||
<div className={styles.root}>
|
||||
<div className={styles.mainContainer}>
|
||||
<ShareHeader
|
||||
pageId={page.id}
|
||||
publishMode={publishMode}
|
||||
isTemplate={isTemplate}
|
||||
templateName={templateName}
|
||||
snapshotUrl={templateSnapshotUrl}
|
||||
/>
|
||||
<Scrollable.Root>
|
||||
<Scrollable.Viewport
|
||||
className={clsx(
|
||||
'affine-page-viewport',
|
||||
styles.editorContainer
|
||||
)}
|
||||
>
|
||||
<PageDetailEditor onLoad={onEditorLoad} />
|
||||
{publishMode === 'page' ? <ShareFooter /> : null}
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
</Scrollable.Root>
|
||||
<EditorOutlineViewer
|
||||
editor={editorContainer}
|
||||
show={publishMode === 'page'}
|
||||
/>
|
||||
<SharePageFooter />
|
||||
</div>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<FrameworkScope scope={page.scope}>
|
||||
<FrameworkScope scope={editor.scope}>
|
||||
<ViewIcon icon={publishMode === 'page' ? 'doc' : 'edgeless'} />
|
||||
<ViewTitle title={pageTitle} />
|
||||
<div className={styles.root}>
|
||||
<div className={styles.mainContainer}>
|
||||
<ShareHeader
|
||||
pageId={page.id}
|
||||
publishMode={publishMode}
|
||||
isTemplate={isTemplate}
|
||||
templateName={templateName}
|
||||
snapshotUrl={templateSnapshotUrl}
|
||||
/>
|
||||
<Scrollable.Root>
|
||||
<Scrollable.Viewport
|
||||
className={clsx(
|
||||
'affine-page-viewport',
|
||||
styles.editorContainer
|
||||
)}
|
||||
>
|
||||
<PageDetailEditor onLoad={onEditorLoad} />
|
||||
{publishMode === 'page' && !BUILD_CONFIG.isElectron ? (
|
||||
<ShareFooter />
|
||||
) : null}
|
||||
</Scrollable.Viewport>
|
||||
<Scrollable.Scrollbar />
|
||||
</Scrollable.Root>
|
||||
<EditorOutlineViewer
|
||||
editor={editorContainer}
|
||||
show={publishMode === 'page'}
|
||||
/>
|
||||
{!BUILD_CONFIG.isElectron && <SharePageFooter />}
|
||||
</div>
|
||||
<PeekViewManagerModal />
|
||||
</FrameworkScope>
|
||||
</div>
|
||||
<PeekViewManagerModal />
|
||||
</FrameworkScope>
|
||||
</FrameworkScope>
|
||||
</AppContainer>
|
||||
</FrameworkScope>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AffineErrorBoundary } from '@affine/core/components/affine/affine-error-boundary';
|
||||
import { AffineErrorComponent } from '@affine/core/components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { PageNotFound } from '@affine/core/desktop/pages/404';
|
||||
import { MobileWorkbenchRoot } from '@affine/core/desktop/pages/workspace/workbench-root';
|
||||
import { workbenchRoutes } from '@affine/core/mobile/workbench-router';
|
||||
import {
|
||||
useLiveData,
|
||||
@@ -23,6 +22,7 @@ import {
|
||||
} from 'react-router-dom';
|
||||
|
||||
import { WorkspaceLayout } from './layout';
|
||||
import { MobileWorkbenchRoot } from './workbench-root';
|
||||
|
||||
type Route = { Component: React.ComponentType };
|
||||
/**
|
||||
|
||||
@@ -1,29 +1,47 @@
|
||||
import { useServiceOptional } from '@toeverything/infra';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { DesktopApiService } from '../../desktop-api';
|
||||
import type { ViewIconName } from '../constants';
|
||||
import { ViewService } from '../services/view';
|
||||
|
||||
export const ViewTitle = ({ title }: { title: string }) => {
|
||||
const view = useServiceOptional(ViewService)?.view;
|
||||
const desktopApi = useServiceOptional(DesktopApiService);
|
||||
|
||||
useEffect(() => {
|
||||
if (view) {
|
||||
view.setTitle(title);
|
||||
} else if (desktopApi) {
|
||||
desktopApi.handler.ui
|
||||
.updateActiveViewMeta({
|
||||
title,
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
}, [title, view]);
|
||||
}, [desktopApi, title, view]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const ViewIcon = ({ icon }: { icon: ViewIconName }) => {
|
||||
const view = useServiceOptional(ViewService)?.view;
|
||||
|
||||
const desktopApi = useServiceOptional(DesktopApiService);
|
||||
useEffect(() => {
|
||||
if (view) {
|
||||
view.setIcon(icon);
|
||||
} else if (desktopApi) {
|
||||
desktopApi.handler.ui
|
||||
.updateActiveViewMeta({
|
||||
iconName: icon,
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
}, [icon, view]);
|
||||
}, [desktopApi, icon, view]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user