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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions apps/web/src/app/(onboarding)/setup/StepComputeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ export function StepComputeProvider({
onBack?: () => void;
disabled?: boolean;
}) {
// All providers are offered. Hosted providers whose worker image is not yet
// available are still selectable: their config step collects a shared worker
// image (and can auto-derive or provision the provider artifact from it), so
// the operator is no longer dead-ended by missing infrastructure.
const availableProviders = computeSetup.providers;
// Hosted providers whose worker image is not yet available remain selectable:
// their config step can collect or provision the missing infrastructure.
// Explicit deployment exclusions are stronger and must not be offered.
const excludedProviders = new Set(computeSetup.excludedProviders ?? []);
const availableProviders = computeSetup.providers.filter(
(provider) => !excludedProviders.has(provider.provider),
);

return (
<div className="relative w-full max-w-2xl space-y-6 py-2 md:py-0">
Expand Down
77 changes: 77 additions & 0 deletions apps/web/src/app/(onboarding)/setup/hooks.client.test.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions apps/web/src/app/(onboarding)/setup/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ export function useSetupFlow(
status.setupNewState.authProvider ??
status.authSetup.runtimeConfiguredProvider ??
status.authSetup.selectedProvider;
const selectedComputeProvider = status.computeSetup.selectedProvider;
const hasStaleComputeProvider =
status.setupNewState.computeProvider !== null &&
selectedComputeProvider !== status.setupNewState.computeProvider;

switch (candidate) {
case 'welcome':
Expand Down Expand Up @@ -389,17 +393,15 @@ export function useSetupFlow(
return activeQualificationBlock === null;
case 'compute-provider':
return (
status.computeSetup.setupSatisfied ||
status.setupNewState.computeProvider != null
!hasStaleComputeProvider &&
(status.computeSetup.setupSatisfied ||
selectedComputeProvider !== null)
);
case 'compute-config': {
if (status.computeSetup.setupSatisfied) {
if (hasStaleComputeProvider || status.computeSetup.setupSatisfied) {
return true;
}

const selectedComputeProvider =
status.setupNewState.computeProvider ?? null;

if (!selectedComputeProvider) {
return true;
}
Expand Down
47 changes: 47 additions & 0 deletions apps/web/src/trpc/commands/setup-new/index.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 42 additions & 10 deletions apps/web/src/trpc/commands/setup-new/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import {
SETUP_COMPUTE_PROVISIONING_STATE_FIELDS,
SHARED_WORKER_IMAGE_ENV_VAR,
type SetupAuthProviderId,
type SetupComputeStatus,
type SetupModelProviderId,
type SetupProvisionableComputeProvider,
type SourceControlProvider,
Expand Down Expand Up @@ -539,6 +540,19 @@ type SetupOnboardingComputeGate = {
error: string | null;
};

function findAvailableSetupComputeProvider(
computeSetup: SetupComputeStatus,
provider: ComputeProvider,
) {
if (computeSetup.excludedProviders?.includes(provider)) {
return undefined;
}

return computeSetup.providers.find(
(candidate) => candidate.provider === provider,
);
}

async function getSetupOnboardingComputeGate(
setupNewState: PersistedSetupNewState,
executor: DatabaseOrTransaction,
Expand Down Expand Up @@ -1537,8 +1551,9 @@ export async function saveSetupNewComputeProviderChoiceCommand(
persistedComputeConfig: persistedRuntimeComputeConfig,
selectedProvider: input.provider,
});
const providerStatus = computeSetup.providers.find(
(candidate) => candidate.provider === input.provider,
const providerStatus = findAvailableSetupComputeProvider(
computeSetup,
input.provider,
);

if (!providerStatus) {
Expand Down Expand Up @@ -1602,12 +1617,6 @@ export async function saveSetupNewComputeConfigCommand(
templateRef: string;
} | null = null;

if (isSetupProvisionableComputeProvider(input.provider)) {
await acquireComputeProvisioningLock(input.provider, tx);
}

await purgeSavedDeploymentWorkerImage(tx);

const [
currentState,
persistedRuntimeComputeConfig,
Expand Down Expand Up @@ -1635,14 +1644,21 @@ export async function saveSetupNewComputeConfigCommand(
persistedComputeConfig: persistedRuntimeComputeConfig,
selectedProvider: input.provider,
});
const providerStatus = computeSetup.providers.find(
(candidate) => candidate.provider === input.provider,
const providerStatus = findAvailableSetupComputeProvider(
computeSetup,
input.provider,
);

if (!providerStatus) {
throw new Error('Selected sandbox provider is unavailable.');
}

if (isSetupProvisionableComputeProvider(input.provider)) {
await acquireComputeProvisioningLock(input.provider, tx);
}

await purgeSavedDeploymentWorkerImage(tx);

// Derive MODAL_BASE_IMAGE_REF when not env-provided or already saved.
// Form submissions are ignored (deployment-managed like E2B/Daytona
// artifacts).
Expand Down Expand Up @@ -2266,6 +2282,22 @@ export async function startSetupNewOnboardingTaskCommand(
};
}

if (currentState.computeProvider) {
const persistedRuntimeComputeConfig =
await getPersistedRuntimeComputeConfig(tx);
const computeSetup = buildSetupComputeStatus({
runtimeEnv: process.env,
persistedComputeConfig: persistedRuntimeComputeConfig,
selectedProvider: currentState.computeProvider,
});

if (computeSetup.selectedProvider !== currentState.computeProvider) {
throw new Error(
'Selected sandbox provider is no longer available. Choose another provider before starting setup.',
);
}
}

const { normalizedRepositoryIds, selectedRepositories } =
await resolveSelectedRepositories(currentState.selectedRepositoryIds);
await assertHasCommittedRepositorySelection(normalizedRepositoryIds);
Expand Down
Loading