Re-run setup and cleanup scripts (#1981)

## Summary

I've implemented the "re-run setup/cleanup script" functionality in the new UI command bar. The changes include:

### Files Modified

1. **`frontend/src/components/ui-new/actions/index.ts`**
   - Added `isAttemptRunning: boolean` to `ActionVisibilityContext` interface (line 109)
   - Added `RunSetupScript` and `RunCleanupScript` workspace actions (lines 737-777)
   - Both actions use the existing `attemptsApi.runSetupScript/runCleanupScript` methods
   - Actions are disabled when `isAttemptRunning` is true
   - Error handling for `no_script_configured` and `process_already_running` errors

2. **`frontend/src/components/ui-new/actions/useActionVisibility.ts`**
   - Import `useExecutionProcessesContext`
   - Added `isAttemptRunningVisible` to the hook call
   - Added `isAttemptRunning: isAttemptRunningVisible` to the returned context

3. **`frontend/src/components/ui-new/actions/pages.ts`**
   - Added a new "Scripts" group to the `workspaceActions` page containing both actions

### Testing

The dev server is running at:
- Frontend: http://localhost:3000/
- Backend: http://127.0.0.1:3001

To test:
1. Navigate to the new UI (`/workspaces`)
2. Select a workspace
3. Open the command bar (CMD+K)
4. Navigate to "Workspace Actions"
5. You should see a "Scripts" group with "Run Setup Script" and "Run Cleanup Script" options
This commit is contained in:
Louis Knight-Webb
2026-01-12 21:00:47 +00:00
committed by GitHub
parent 20b99300fe
commit 7bc52ac8c5
3 changed files with 58 additions and 0 deletions

View File

@@ -104,6 +104,9 @@ export interface ActionVisibilityContext {
hasMultipleRepos: boolean;
hasOpenPR: boolean;
hasUnpushedCommits: boolean;
// Execution state
isAttemptRunning: boolean;
}
// Base properties shared by all actions
@@ -729,6 +732,49 @@ export const Actions = {
invalidateWorkspaceQueries(ctx.queryClient, workspaceId);
},
},
// === Script Actions ===
RunSetupScript: {
id: 'run-setup-script',
label: 'Run Setup Script',
icon: TerminalIcon,
requiresTarget: true,
isVisible: (ctx) => ctx.hasWorkspace,
isEnabled: (ctx) => !ctx.isAttemptRunning,
execute: async (_ctx, workspaceId) => {
const result = await attemptsApi.runSetupScript(workspaceId);
if (!result.success) {
if (result.error?.type === 'no_script_configured') {
throw new Error('No setup script configured for this project');
}
if (result.error?.type === 'process_already_running') {
throw new Error('Cannot run script while another process is running');
}
throw new Error('Failed to run setup script');
}
},
},
RunCleanupScript: {
id: 'run-cleanup-script',
label: 'Run Cleanup Script',
icon: TerminalIcon,
requiresTarget: true,
isVisible: (ctx) => ctx.hasWorkspace,
isEnabled: (ctx) => !ctx.isAttemptRunning,
execute: async (_ctx, workspaceId) => {
const result = await attemptsApi.runCleanupScript(workspaceId);
if (!result.success) {
if (result.error?.type === 'no_script_configured') {
throw new Error('No cleanup script configured for this project');
}
if (result.error?.type === 'process_already_running') {
throw new Error('Cannot run script while another process is running');
}
throw new Error('Failed to run cleanup script');
}
},
},
} as const satisfies Record<string, ActionDefinition>;
// Helper to resolve dynamic label

View File

@@ -110,6 +110,14 @@ export const Pages: Record<StaticPageId, CommandBarPage> = {
{ type: 'action', action: Actions.DeleteWorkspace },
],
},
{
type: 'group',
label: 'Scripts',
items: [
{ type: 'action', action: Actions.RunSetupScript },
{ type: 'action', action: Actions.RunCleanupScript },
],
},
],
},

View File

@@ -6,6 +6,7 @@ import { useWorkspaceContext } from '@/contexts/WorkspaceContext';
import { useUserSystem } from '@/components/ConfigProvider';
import { useDevServer } from '@/hooks/useDevServer';
import { useBranchStatus } from '@/hooks/useBranchStatus';
import { useExecutionProcessesContext } from '@/contexts/ExecutionProcessesContext';
import type { Workspace, Merge } from 'shared/types';
import type {
ActionVisibilityContext,
@@ -31,6 +32,7 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
const { isStarting, isStopping, runningDevServers } =
useDevServer(workspaceId);
const { data: branchStatus } = useBranchStatus(workspaceId);
const { isAttemptRunningVisible } = useExecutionProcessesContext();
return useMemo(() => {
// Compute isAllDiffsExpanded
@@ -79,6 +81,7 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
hasMultipleRepos: repos.length > 1,
hasOpenPR,
hasUnpushedCommits,
isAttemptRunning: isAttemptRunningVisible,
};
}, [
layout.isChangesMode,
@@ -98,6 +101,7 @@ export function useActionVisibilityContext(): ActionVisibilityContext {
isStopping,
runningDevServers,
branchStatus,
isAttemptRunningVisible,
]);
}