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
1 change: 1 addition & 0 deletions apps/web/reactCompiledFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ export const REACT_COMPILED_FILES = [
"apps/web/src/components/ui/toggle-group.tsx",
"apps/web/src/components/ThreadNotificationCoordinator.tsx",
"apps/web/src/state/queries.ts",
"apps/web/src/state/sourceControlActions.ts",
] as const;
253 changes: 122 additions & 131 deletions apps/web/src/state/sourceControlActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
import * as Cause from "effect/Cause";
import * as Option from "effect/Option";
import { AsyncResult } from "effect/reactivity";
import { useCallback } from "react";

import { appAtomRegistry } from "../rpc/atomRegistry";
import { gitEnvironment } from "./git";
Expand Down Expand Up @@ -87,48 +86,45 @@ function useAction<
const state = useAtomValue(vcsActionManager.stateAtom(input.scope));
const ownsState = state.operation === operation;

const resetError = useCallback(() => {
const resetError = () => {
vcsActionManager.resetError(appAtomRegistry, input.scope, operation);
}, [input.scope, operation]);
};

const run = useCallback(
async (...args: TArgs) => {
if (
input.scope.environmentId === null ||
!readEnvironmentScope(input.scope.environmentId, AuthSourceControlWriteScope)
) {
return AsyncResult.failure<never, EnvironmentAuthorizationError>(
Cause.fail(
new EnvironmentAuthorizationError({
requiredScope: AuthSourceControlWriteScope,
message: "This connection cannot change source control.",
}),
),
);
const run = async (...args: TArgs) => {
if (
input.scope.environmentId === null ||
!readEnvironmentScope(input.scope.environmentId, AuthSourceControlWriteScope)
) {
return AsyncResult.failure<never, EnvironmentAuthorizationError>(
Cause.fail(
new EnvironmentAuthorizationError({
requiredScope: AuthSourceControlWriteScope,
message: "This connection cannot change source control.",
}),
),
);
}
const execute = async (): Promise<
AtomCommandResult<AtomCommandSuccess<R>, AtomCommandFailure<R>>
> => {
const result = await input.action(...args);
if (AsyncResult.isSuccess(result)) {
input.onSuccess?.();
}
const execute = async (): Promise<
AtomCommandResult<AtomCommandSuccess<R>, AtomCommandFailure<R>>
> => {
const result = await input.action(...args);
if (AsyncResult.isSuccess(result)) {
input.onSuccess?.();
}
return result as AtomCommandResult<AtomCommandSuccess<R>, AtomCommandFailure<R>>;
};
return input.managedExternally === true
? execute()
: vcsActionManager.track(
appAtomRegistry,
input.scope,
{
operation,
label: input.label,
},
execute,
);
},
[input.action, input.label, input.managedExternally, input.onSuccess, input.scope, operation],
);
return result as AtomCommandResult<AtomCommandSuccess<R>, AtomCommandFailure<R>>;
};
return input.managedExternally === true
? execute()
: vcsActionManager.track(
appAtomRegistry,
input.scope,
{
operation,
label: input.label,
},
execute,
);
};

return {
isAllowed,
Expand Down Expand Up @@ -163,7 +159,7 @@ export function useSourceControlActionRunning(

export function useVcsInitAction(scope: SourceControlActionScope) {
const init = useAtomCommand(vcsEnvironment.init, { reportFailure: false });
const action = useCallback(async () => {
const action = async () => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Expand All @@ -180,7 +176,7 @@ export function useVcsInitAction(scope: SourceControlActionScope) {
environmentId: target.environmentId,
input: { cwd: target.cwd },
});
}, [init, scope]);
};
return useAction({ kind: "init", label: "Initializing repository", scope, action });
}

Expand All @@ -194,7 +190,7 @@ export function useVcsPullAction(scope: SourceControlActionScope) {
})
: null,
);
const action = useCallback(async () => {
const action = async () => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Expand All @@ -211,7 +207,7 @@ export function useVcsPullAction(scope: SourceControlActionScope) {
environmentId: target.environmentId,
input: { cwd: target.cwd },
});
}, [pull, scope]);
};
return useAction({
kind: "pull",
label: "Pulling latest changes...",
Expand All @@ -234,23 +230,20 @@ export function useGitStackedAction(scope: SourceControlActionScope) {
: null,
);

const action = useCallback(
async (input: RunVcsStackedActionInput) => {
if (resolveScope(scope) === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "run_change_request",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
return runStackedAction(input);
},
[runStackedAction, scope],
);
const action = async (input: RunVcsStackedActionInput) => {
if (resolveScope(scope) === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "run_change_request",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
return runStackedAction(input);
};

return useAction({
kind: "runStackedAction",
Expand All @@ -274,36 +267,33 @@ export function useSourceControlPublishRepositoryAction(scope: SourceControlActi
})
: null,
);
const action = useCallback(
async (input: {
provider: SourceControlProviderKind;
repository: string;
visibility: SourceControlRepositoryVisibility;
remoteName: string;
protocol: SourceControlCloneProtocol;
}) => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "publish_repository",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
return publishRepository({
environmentId: target.environmentId,
input: {
cwd: target.cwd,
...input,
},
});
},
[publishRepository, scope],
);
const action = async (input: {
provider: SourceControlProviderKind;
repository: string;
visibility: SourceControlRepositoryVisibility;
remoteName: string;
protocol: SourceControlCloneProtocol;
}) => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "publish_repository",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
return publishRepository({
environmentId: target.environmentId,
input: {
cwd: target.cwd,
...input,
},
});
};
return useAction({
kind: "publishRepository",
label: "Publishing repository",
Expand All @@ -317,46 +307,47 @@ export function usePreparePullRequestThreadAction(scope: SourceControlActionScop
const preparePullRequestThread = useAtomCommand(gitEnvironment.preparePullRequestThread, {
reportFailure: false,
});
const action = useCallback(
async (input: { reference: string; mode: "local" | "worktree"; threadId?: ThreadId }) => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "prepare_pull_request_thread",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
if (
input.mode === "worktree" &&
input.threadId !== undefined &&
!readEnvironmentScope(target.environmentId, AuthOrchestrationOperateScope)
) {
return AsyncResult.failure<never, EnvironmentAuthorizationError>(
Cause.fail(
new EnvironmentAuthorizationError({
requiredScope: AuthOrchestrationOperateScope,
message: "This connection cannot change threads.",
}),
),
);
}
return preparePullRequestThread({
environmentId: target.environmentId,
input: {
cwd: target.cwd,
reference: input.reference,
mode: input.mode,
...(input.threadId ? { threadId: input.threadId } : {}),
},
});
},
[preparePullRequestThread, scope],
);
const action = async (input: {
reference: string;
mode: "local" | "worktree";
threadId?: ThreadId;
}) => {
const target = resolveScope(scope);
if (target === null) {
return AsyncResult.failure<never, VcsActionUnavailableError>(
Cause.fail(
new VcsActionUnavailableError({
operation: "prepare_pull_request_thread",
environmentId: scope.environmentId,
cwd: scope.cwd,
}),
),
);
}
if (
input.mode === "worktree" &&
input.threadId !== undefined &&
!readEnvironmentScope(target.environmentId, AuthOrchestrationOperateScope)
) {
return AsyncResult.failure<never, EnvironmentAuthorizationError>(
Cause.fail(
new EnvironmentAuthorizationError({
requiredScope: AuthOrchestrationOperateScope,
message: "This connection cannot change threads.",
}),
),
);
}
return preparePullRequestThread({
environmentId: target.environmentId,
input: {
cwd: target.cwd,
reference: input.reference,
mode: input.mode,
...(input.threadId ? { threadId: input.threadId } : {}),
},
});
};
return useAction({
kind: "preparePullRequestThread",
label: "Preparing pull request thread",
Expand Down
Loading