Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions desktop/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"windows": [
{
"title": "",
"width": 800,
"height": 600,
"width": 900,
"height": 650,
"maximized": true,
"visible": false,
"transparent": false,
Expand All @@ -30,8 +30,8 @@
"y": 25
},
"backgroundThrottling": "disabled",
"minWidth": 800,
"minHeight": 500
"minWidth": 900,
"minHeight": 650
}
],
"macOSPrivateApi": true,
Expand Down
49 changes: 20 additions & 29 deletions desktop/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import { CommunityOnboardingFlow } from "@/features/onboarding/ui/CommunityOnboa
import {
MachineOnboardingFlow,
type MachineOnboardingPage,
type PostOnboardingNavigation,
} from "@/features/onboarding/ui/MachineOnboardingFlow";
import { OnboardingFlow } from "@/features/onboarding/ui/OnboardingFlow";
import { PendingInviteGate } from "@/features/onboarding/ui/PendingInviteGate";
Expand Down Expand Up @@ -299,9 +298,11 @@ function CommunityIdentityReplacementSentinel({
}

function AppReady({
continueOnboarding,
isSharedIdentity,
isCommunitySwitch,
}: {
continueOnboarding: boolean;
isSharedIdentity: boolean;
isCommunitySwitch: boolean;
}) {
Expand All @@ -319,12 +320,18 @@ function AppReady({
return <RelaunchRequiredScreen />;
}

if (onboarding.stage === "onboarding") {
if (
onboarding.stage === "onboarding" ||
(continueOnboarding && onboarding.stage === "blocking")
) {
return (
<OnboardingFlow
actions={onboarding.flow.actions}
identityLost={onboarding.identityLost}
initialProfile={onboarding.flow.initialProfile}
initialProfileDecisionSettled={
onboarding.flow.initialProfileDecisionSettled
}
key={onboarding.currentPubkey ?? "anonymous"}
/>
);
Expand All @@ -351,10 +358,12 @@ function AppReady({
}

function CommunityApp({
continueOnboarding,
currentPubkey,
onBackToMachineConfig,
sharedIdentity,
}: {
continueOnboarding: boolean;
currentPubkey: string | null;
onBackToMachineConfig: () => void;
sharedIdentity: boolean;
Expand Down Expand Up @@ -415,6 +424,7 @@ function CommunityApp({
hasSwitchedCommunityRef.current = true;
}
const isCommunitySwitch = hasSwitchedCommunityRef.current;
const isContinuingOnboarding = continueOnboarding && !isCommunitySwitch;

const community = useCommunityInit(
activeCommunity,
Expand Down Expand Up @@ -581,7 +591,7 @@ function CommunityApp({
// overlay just keeps the bee on screen long enough to be seen, then fades.
// Community switches keep their quiet gate.
const showBootSplashOverlay =
bootSplashPhase !== "done" && !isCommunitySwitch;
bootSplashPhase !== "done" && !isCommunitySwitch && !isContinuingOnboarding;

let appContent: ReactNode = null;
if (!transaction) {
Expand Down Expand Up @@ -636,6 +646,7 @@ function CommunityApp({
/>
<CommunityThemeController />
<AppReady
continueOnboarding={isContinuingOnboarding}
isCommunitySwitch={isCommunitySwitch}
key={communityKey}
isSharedIdentity={sharedIdentity}
Expand All @@ -654,7 +665,7 @@ function CommunityApp({
</div>
) : null}
</CommunityQueryProvider>
) : isCommunitySwitch ? (
) : isCommunitySwitch || isContinuingOnboarding ? (
<CommunitySwitchGate />
) : (
<AppLoadingGate />
Expand Down Expand Up @@ -692,43 +703,23 @@ function MachineBootstrap({ sharedIdentity }: { sharedIdentity: boolean }) {
});
const [machineInitialPage, setMachineInitialPage] =
useState<MachineOnboardingPage>();
const [postOnboardingNav, setPostOnboardingNav] =
useState<PostOnboardingNavigation | null>(null);
const [continueOnboarding, setContinueOnboarding] = useState(false);

const reopenMachineConfig = useCallback(() => {
setContinueOnboarding(false);
setMachineInitialPage("config");
machine.reopen();
}, [machine.reopen]);

const completeMachineOnboarding = useCallback(
(pubkey?: string) => {
(pubkey?: string, options?: { continueToProfile?: boolean }) => {
setContinueOnboarding(options?.continueToProfile === true);
setMachineInitialPage(undefined);
machine.complete(pubkey);
},
[machine.complete],
);

const navigateAfterOnboarding = useCallback(
(nav: PostOnboardingNavigation) => {
setPostOnboardingNav(nav);
},
[],
);

// Execute the pending navigation once the RouterProvider is mounted (i.e.
// machine.stage transitions to "ready"). We wait for the ready stage rather
// than using setTimeout(0) so the router is guaranteed to exist before we call
// router.navigate().
useEffect(() => {
if (machine.stage === "ready" && postOnboardingNav) {
void router.navigate({
to: postOnboardingNav.to,
search: postOnboardingNav.search ?? {},
});
setPostOnboardingNav(null);
}
}, [machine.stage, postOnboardingNav]);

const openAddCommunity = useCallback(
(payload: AddCommunityDeepLinkPayload & { requestId: string }) =>
activeCommunity
Expand Down Expand Up @@ -765,6 +756,7 @@ function MachineBootstrap({ sharedIdentity }: { sharedIdentity: boolean }) {
if (machine.stage === "ready") {
return (
<CommunityApp
continueOnboarding={continueOnboarding}
currentPubkey={machine.currentPubkey}
onBackToMachineConfig={reopenMachineConfig}
sharedIdentity={sharedIdentity}
Expand All @@ -789,7 +781,6 @@ function MachineBootstrap({ sharedIdentity }: { sharedIdentity: boolean }) {
continueWithRecoveredIdentity={machine.continueWithRecoveredIdentity}
identityLost={machine.identityLost}
initialPage={machineInitialPage}
navigateAfterComplete={navigateAfterOnboarding}
queryClient={machine.queryClient}
/>
{shouldAcknowledgeDeepLink ? <PendingInviteGate /> : null}
Expand Down
123 changes: 0 additions & 123 deletions desktop/src/app/postOnboardingNav.test.mjs

This file was deleted.

27 changes: 21 additions & 6 deletions desktop/src/features/agents/acpRuntimesQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,17 +272,32 @@ export function useAcpRuntimesQueryForced(options?: {
queryFn: () => discoverAcpRuntimes({ force: true }),
enabled: false,
});
const forceRefresh = React.useCallback(
() => refreshAcpRuntimes(queryClient),
[queryClient],
);
const [hasForcedCheckStarted, setHasForcedCheckStarted] =
React.useState(false);
const [isOwnedForcedCheckPending, setIsOwnedForcedCheckPending] =
React.useState(false);
const forceRefresh = React.useCallback(async () => {
// Own the launch state instead of inferring it from the query observer.
// A fast mocked/native response can start and settle inside one React
// batch, so consumers may never render the transient query fetching state.
setHasForcedCheckStarted(true);
setIsOwnedForcedCheckPending(true);
try {
return await refreshAcpRuntimes(queryClient);
} finally {
setIsOwnedForcedCheckPending(false);
}
}, [queryClient]);
React.useEffect(() => {
if (enabled && forceOnMount) void forceRefresh();
if (!enabled || !forceOnMount) return;
void forceRefresh();
}, [enabled, forceOnMount, forceRefresh]);
const isFetching = query.isFetching || forcedQuery.isFetching;
const isFetching =
isOwnedForcedCheckPending || query.isFetching || forcedQuery.isFetching;
return {
...query,
error: forcedQuery.error ?? query.error,
hasForcedCheckStarted,
isError: forcedQuery.isError || query.isError,
isFetching,
isLoading: isFetching && query.data === undefined,
Expand Down
Loading
Loading