feat(core): open in app for self-hosted (#9231)

<div class='graphite__hidden'>
          <div>🎥 Video uploaded on Graphite:</div>
            <a href="https://app.graphite.dev/media/video/T2klNLEk0wxLh4NRDzhk/545994dd-6f7d-468d-a90c-45cb382fdb9d.mp4">
              <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/T2klNLEk0wxLh4NRDzhk/545994dd-6f7d-468d-a90c-45cb382fdb9d.mp4">
            </a>
          </div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/545994dd-6f7d-468d-a90c-45cb382fdb9d.mp4">20241222-1456-24.5006677.mp4</video>

fix AF-1815
This commit is contained in:
pengx17
2024-12-24 03:04:01 +00:00
parent 884bbd2ada
commit 17c2293986
14 changed files with 140 additions and 43 deletions
@@ -78,9 +78,11 @@ export const AddSelfhostedStep = ({
...prev,
initialServerBaseUrl: undefined,
}));
onConnect();
if (serversService.getServerByBaseUrl(state.initialServerBaseUrl)) {
onConnect();
}
}
}, [changeState, onConnect, state]);
}, [changeState, onConnect, serversService, state]);
return (
<>
@@ -1,4 +1,5 @@
import { DefaultServerService, type Server } from '@affine/core/modules/cloud';
import type { AuthSessionStatus } from '@affine/core/modules/cloud/entities/session';
import { FrameworkScope, useService } from '@toeverything/infra';
import { useState } from 'react';
@@ -22,11 +23,13 @@ export interface SignInState {
}
export const SignInPanel = ({
onClose,
onSkip,
server: initialServerBaseUrl,
initStep,
onAuthenticated,
}: {
onClose: () => void;
onAuthenticated?: (status: AuthSessionStatus) => void;
onSkip: () => void;
server?: string;
initStep?: SignInStep | undefined;
}) => {
@@ -47,18 +50,23 @@ export const SignInPanel = ({
return (
<FrameworkScope scope={server.scope}>
{step === 'signIn' ? (
<SignInStep state={state} changeState={setState} close={onClose} />
<SignInStep
state={state}
changeState={setState}
onSkip={onSkip}
onAuthenticated={onAuthenticated}
/>
) : step === 'signInWithEmail' ? (
<SignInWithEmailStep
state={state}
changeState={setState}
close={onClose}
onAuthenticated={onAuthenticated}
/>
) : step === 'signInWithPassword' ? (
<SignInWithPasswordStep
state={state}
changeState={setState}
close={onClose}
onAuthenticated={onAuthenticated}
/>
) : step === 'addSelfhosted' ? (
<AddSelfhostedStep state={state} changeState={setState} />
@@ -8,6 +8,7 @@ import {
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { AuthService, CaptchaService } from '@affine/core/modules/cloud';
import type { AuthSessionStatus } from '@affine/core/modules/cloud/entities/session';
import { Unreachable } from '@affine/env/constant';
import { Trans, useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra';
@@ -27,11 +28,11 @@ import * as style from './style.css';
export const SignInWithEmailStep = ({
state,
changeState,
close,
onAuthenticated,
}: {
state: SignInState;
changeState: Dispatch<SetStateAction<SignInState>>;
close: () => void;
onAuthenticated?: (status: AuthSessionStatus) => void;
}) => {
const initialSent = useRef(false);
const [resendCountDown, setResendCountDown] = useState(0);
@@ -66,13 +67,13 @@ export const SignInWithEmailStep = ({
useEffect(() => {
if (loginStatus === 'authenticated') {
close();
notify.success({
title: t['com.affine.auth.toast.title.signed-in'](),
message: t['com.affine.auth.toast.message.signed-in'](),
});
}
}, [close, loginStatus, t]);
onAuthenticated?.(loginStatus);
}, [loginStatus, onAuthenticated, t]);
const sendEmail = useAsyncCallback(async () => {
if (isSending || (!verifyToken && needCaptcha)) return;
@@ -11,6 +11,7 @@ import {
CaptchaService,
ServerService,
} from '@affine/core/modules/cloud';
import type { AuthSessionStatus } from '@affine/core/modules/cloud/entities/session';
import { Unreachable } from '@affine/env/constant';
import { ServerDeploymentType } from '@affine/graphql';
import { useI18n } from '@affine/i18n';
@@ -25,11 +26,11 @@ import * as styles from './style.css';
export const SignInWithPasswordStep = ({
state,
changeState,
close,
onAuthenticated,
}: {
state: SignInState;
changeState: Dispatch<SetStateAction<SignInState>>;
close: () => void;
onAuthenticated?: (status: AuthSessionStatus) => void;
}) => {
const t = useI18n();
const authService = useService(AuthService);
@@ -62,13 +63,13 @@ export const SignInWithPasswordStep = ({
useEffect(() => {
if (loginStatus === 'authenticated') {
close();
notify.success({
title: t['com.affine.auth.toast.title.signed-in'](),
message: t['com.affine.auth.toast.message.signed-in'](),
});
}
}, [close, loginStatus, t]);
onAuthenticated?.(loginStatus);
}, [loginStatus, onAuthenticated, t]);
const onSignIn = useAsyncCallback(async () => {
if (isLoading || (!verifyToken && needCaptcha)) return;
@@ -3,6 +3,7 @@ import { AuthInput, ModalHeader } from '@affine/component/auth-components';
import { OAuth } from '@affine/core/components/affine/auth/oauth';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { AuthService, ServerService } from '@affine/core/modules/cloud';
import type { AuthSessionStatus } from '@affine/core/modules/cloud/entities/session';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { ServerDeploymentType } from '@affine/graphql';
import { Trans, useI18n } from '@affine/i18n';
@@ -30,11 +31,13 @@ function validateEmail(email: string) {
export const SignInStep = ({
state,
changeState,
close,
onSkip,
onAuthenticated,
}: {
state: SignInState;
changeState: Dispatch<SetStateAction<SignInState>>;
close: () => void;
onSkip: () => void;
onAuthenticated?: (status: AuthSessionStatus) => void;
}) => {
const t = useI18n();
const serverService = useService(ServerService);
@@ -61,13 +64,13 @@ export const SignInStep = ({
useEffect(() => {
if (loginStatus === 'authenticated') {
close();
notify.success({
title: t['com.affine.auth.toast.title.signed-in'](),
message: t['com.affine.auth.toast.message.signed-in'](),
});
}
}, [close, loginStatus, t]);
onAuthenticated?.(loginStatus);
}, [loginStatus, onAuthenticated, t]);
const onContinue = useAsyncCallback(async () => {
if (!validateEmail(email)) {
@@ -205,7 +208,7 @@ export const SignInStep = ({
</div>
<Button
variant="plain"
onClick={() => close()}
onClick={onSkip}
className={style.skipLink}
suffix={<ArrowRightBigIcon className={style.skipLinkIcon} />}
>