diff --git a/packages/frontend/component/src/components/auth-components/auth-header.tsx b/packages/frontend/component/src/components/auth-components/auth-header.tsx index c012cdc10b..e2104dff06 100644 --- a/packages/frontend/component/src/components/auth-components/auth-header.tsx +++ b/packages/frontend/component/src/components/auth-components/auth-header.tsx @@ -1,13 +1,16 @@ import { Logo1Icon } from '@blocksuite/icons/rc'; +import clsx from 'clsx'; import type { FC } from 'react'; import { authHeaderWrapper } from './share.css'; + export const AuthHeader: FC<{ title: string; subTitle?: string; -}> = ({ title, subTitle }) => { + className?: string; +}> = ({ title, subTitle, className }) => { return ( -
+

{title} diff --git a/packages/frontend/core/src/desktop/pages/auth/sign-in.tsx b/packages/frontend/core/src/desktop/pages/auth/sign-in.tsx index 781e5465cd..f6db194d82 100644 --- a/packages/frontend/core/src/desktop/pages/auth/sign-in.tsx +++ b/packages/frontend/core/src/desktop/pages/auth/sign-in.tsx @@ -46,6 +46,9 @@ export const SignIn = ({ (status: AuthSessionStatus) => { if (status === 'authenticated') { if (redirectUrl) { + if (redirectUrl.toUpperCase() === 'CLOSE_POPUP') { + window.close(); + } navigate(redirectUrl, { replace: true, }); diff --git a/packages/frontend/core/src/desktop/pages/import-clipper/index.tsx b/packages/frontend/core/src/desktop/pages/import-clipper/index.tsx index d1261521b2..4d9ebf4032 100644 --- a/packages/frontend/core/src/desktop/pages/import-clipper/index.tsx +++ b/packages/frontend/core/src/desktop/pages/import-clipper/index.tsx @@ -1,9 +1,9 @@ import { Button } from '@affine/component'; +import { AuthHeader } from '@affine/component/auth-components'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; -import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper'; import { useWorkspaceName } from '@affine/core/components/hooks/use-workspace-info'; import { WorkspaceSelector } from '@affine/core/components/workspace-selector'; -import { AuthService } from '@affine/core/modules/cloud'; +import { AuthService, ServerService } from '@affine/core/modules/cloud'; import { type ClipperInput, ImportClipperService, @@ -16,7 +16,7 @@ import { useI18n } from '@affine/i18n'; import { AllDocsIcon } from '@blocksuite/icons/rc'; import { LiveData, useLiveData, useService } from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import * as styles from './style.css'; @@ -36,7 +36,6 @@ export const Component = () => { const t = useI18n(); const session = useService(AuthService).session; const notLogin = useLiveData(session.status$) === 'unauthenticated'; - const isSessionRevalidating = useLiveData(session.isRevalidating$); const [importing, setImporting] = useState(false); const [importingError, setImportingError] = useState(null); @@ -44,16 +43,22 @@ export const Component = () => { const [clipperInputSnapshot, setClipperInputSnapshot] = useState(null); const isMissingInput = !clipperInputSnapshot; + const workspaceStrategy = clipperInputSnapshot?.workspace ?? 'select-by-user'; + const serverService = useService(ServerService); const workspacesService = useService(WorkspacesService); + const serverConfig = useLiveData(serverService.server.config$); const workspaces = useLiveData(workspacesService.list.workspaces$); const [rawSelectedWorkspace, setSelectedWorkspace] = useState(null); + const [lastOpenedWorkspaceId] = useState(() => + localStorage.getItem('last_workspace_id') + ); const selectedWorkspace = rawSelectedWorkspace ?? + workspaces.find(w => w.id === lastOpenedWorkspaceId) ?? workspaces.find(w => w.flavour !== 'local') ?? workspaces.at(0); const selectedWorkspaceName = useWorkspaceName(selectedWorkspace); - const { jumpToSignIn } = useNavigateHelper(); const noWorkspace = workspaces.length === 0; @@ -65,12 +70,6 @@ export const Component = () => { session.revalidate(); }, [session]); - useEffect(() => { - if (!isSessionRevalidating && notLogin) { - jumpToSignIn('/clipper/import'); - } - }, [isSessionRevalidating, jumpToSignIn, notLogin]); - useEffect(() => { if (!clipperInputSnapshot) { setClipperInputSnapshot(clipperInput); @@ -99,6 +98,9 @@ export const Component = () => { selectedWorkspace, clipperInputSnapshot ); + window.postMessage({ + type: 'affine-clipper:import:success', + }); window.close(); } catch (err) { setImportingError(err); @@ -119,6 +121,9 @@ export const Component = () => { 'Workspace', clipperInputSnapshot ); + window.postMessage({ + type: 'affine-clipper:import:success', + }); window.close(); } catch (err) { setImportingError(err); @@ -127,8 +132,70 @@ export const Component = () => { } }, [clipperInputSnapshot, importClipperService]); + const handleClickSignIn = useCallback(() => { + window.open( + `/sign-in?redirect_uri=${encodeURIComponent('CLOSE_POPUP')}`, + '_blank', + 'popup' + ); + }, []); + + const autoImportTriggered = useRef(false); + + useEffect(() => { + if (isMissingInput) { + return; + } + // use ref to avoid multiple auto import + // and make sure the following code only runs once + if (autoImportTriggered.current) { + return; + } + autoImportTriggered.current = true; + + // if not login, we don't auto import + if (notLogin) { + return; + } + + // if the workspace strategy is last-open-workspace, we automatically click the import button + if ( + workspaceStrategy === 'last-open-workspace' && + selectedWorkspace?.id === lastOpenedWorkspaceId + ) { + handleImportToSelectedWorkspace(); + } + }, [ + workspaceStrategy, + selectedWorkspace, + handleImportToSelectedWorkspace, + lastOpenedWorkspaceId, + isMissingInput, + notLogin, + ]); + const disabled = isMissingInput || importing || notLogin; + if (notLogin) { + // not login + return ( +

+ + +
+ ); + } + return (
diff --git a/packages/frontend/core/src/desktop/pages/import-clipper/style.css.ts b/packages/frontend/core/src/desktop/pages/import-clipper/style.css.ts index aea6017096..11c9569c2d 100644 --- a/packages/frontend/core/src/desktop/pages/import-clipper/style.css.ts +++ b/packages/frontend/core/src/desktop/pages/import-clipper/style.css.ts @@ -12,6 +12,10 @@ export const container = style({ padding: '16px', }); +export const authHeader = style({ + width: '100%', +}); + export const buttonContainer = style({ paddingTop: '16px', }); diff --git a/packages/frontend/core/src/modules/import-clipper/services/import.ts b/packages/frontend/core/src/modules/import-clipper/services/import.ts index bc05f6391b..3bb223fbf7 100644 --- a/packages/frontend/core/src/modules/import-clipper/services/import.ts +++ b/packages/frontend/core/src/modules/import-clipper/services/import.ts @@ -13,6 +13,7 @@ export interface ClipperInput { contentMarkdown: string; contentHtml: string; attachments: Record; + workspace?: 'select-by-user' | 'last-open-workspace'; } export class ImportClipperService extends Service { @@ -37,6 +38,7 @@ export class ImportClipperService extends Service { const docsService = workspace.scope.get(DocsService); if (docId) { // only support page mode for now + await docsService.changeDocTitle(docId, clipperInput.title); docsService.list.setPrimaryMode(docId, 'page'); workspace.engine.doc.addPriority(workspace.id, 100); workspace.engine.doc.addPriority(docId, 100);