fix: ScriptFixerDialog no longer overwrites unrelated scripts (Vibe Kanban) (#2078)
* All tasks are complete. Here's a summary of the changes made:
## Summary
Fixed the issue where `ScriptFixerDialog.tsx` was replacing cleanup and setup scripts with `null` when editing a dev server script.
### Changes Made:
1. **Added `serde_with` dependency** (`Cargo.toml` and `crates/db/Cargo.toml`)
- Added `serde_with = "3"` to enable the double option pattern
2. **Updated `UpdateRepo` struct** (`crates/db/src/models/repo.rs`)
- Changed all fields from `Option<T>` to `Option<Option<T>>` with the `double_option` serde helper
- Added `#[ts(optional, type = "...")]` annotations for proper TypeScript type generation
3. **Updated `Repo::update` method** (`crates/db/src/models/repo.rs`)
- Now properly handles three states:
- `None` = field absent → preserve existing value
- `Some(None)` = explicitly null → set to NULL
- `Some(Some(v))` = has value → update to value
4. **Updated `ScriptFixerDialog.tsx`** (`frontend/src/components/dialogs/scripts/ScriptFixerDialog.tsx`)
- Changed `handleSave` and `handleSaveAndTest` to only send the field being edited
- Removed `repos` from the dependency arrays since it's no longer used in the save functions
5. **Regenerated TypeScript types**
- `UpdateRepo` now has all fields as optional: `field?: type | null`
### Result:
The API now supports true partial updates. Clients can send only the fields they want to update, and existing values are preserved for omitted fields. Sending `null` explicitly will clear a field to NULL.
* Done. All Rust code has been formatted.
This commit is contained in:
committed by
GitHub
parent
75beab35d9
commit
ede1511a50
@@ -166,27 +166,16 @@ const ScriptFixerDialogImpl = NiceModal.create<ScriptFixerDialogProps>(
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// Build update data with all required fields
|
||||
const selectedRepo = repos.find((r) => r.id === selectedRepoId);
|
||||
const updateData: UpdateRepo = {
|
||||
display_name: selectedRepo?.display_name ?? null,
|
||||
setup_script:
|
||||
scriptType === 'setup'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.setup_script ?? null),
|
||||
cleanup_script:
|
||||
scriptType === 'cleanup'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.cleanup_script ?? null),
|
||||
copy_files: selectedRepo?.copy_files ?? null,
|
||||
parallel_setup_script: selectedRepo?.parallel_setup_script ?? null,
|
||||
dev_server_script:
|
||||
scriptType === 'dev_server'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.dev_server_script ?? null),
|
||||
};
|
||||
// Only send the field being edited - other fields will be preserved by the backend
|
||||
const scriptValue = script.trim() || null;
|
||||
const updateData: Partial<UpdateRepo> =
|
||||
scriptType === 'setup'
|
||||
? { setup_script: scriptValue }
|
||||
: scriptType === 'cleanup'
|
||||
? { cleanup_script: scriptValue }
|
||||
: { dev_server_script: scriptValue };
|
||||
|
||||
await repoApi.update(selectedRepoId, updateData);
|
||||
await repoApi.update(selectedRepoId, updateData as UpdateRepo);
|
||||
|
||||
// Invalidate repos cache
|
||||
queryClient.invalidateQueries({ queryKey: ['repos'] });
|
||||
@@ -201,7 +190,7 @@ const ScriptFixerDialogImpl = NiceModal.create<ScriptFixerDialogProps>(
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, [selectedRepoId, script, scriptType, queryClient, modal, t, repos]);
|
||||
}, [selectedRepoId, script, scriptType, queryClient, modal, t]);
|
||||
|
||||
const handleSaveAndTest = useCallback(async () => {
|
||||
if (!selectedRepoId) return;
|
||||
@@ -210,27 +199,16 @@ const ScriptFixerDialogImpl = NiceModal.create<ScriptFixerDialogProps>(
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// First save the script
|
||||
const selectedRepo = repos.find((r) => r.id === selectedRepoId);
|
||||
const updateData: UpdateRepo = {
|
||||
display_name: selectedRepo?.display_name ?? null,
|
||||
setup_script:
|
||||
scriptType === 'setup'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.setup_script ?? null),
|
||||
cleanup_script:
|
||||
scriptType === 'cleanup'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.cleanup_script ?? null),
|
||||
copy_files: selectedRepo?.copy_files ?? null,
|
||||
parallel_setup_script: selectedRepo?.parallel_setup_script ?? null,
|
||||
dev_server_script:
|
||||
scriptType === 'dev_server'
|
||||
? script.trim() || null
|
||||
: (selectedRepo?.dev_server_script ?? null),
|
||||
};
|
||||
// Only send the field being edited - other fields will be preserved by the backend
|
||||
const scriptValue = script.trim() || null;
|
||||
const updateData: Partial<UpdateRepo> =
|
||||
scriptType === 'setup'
|
||||
? { setup_script: scriptValue }
|
||||
: scriptType === 'cleanup'
|
||||
? { cleanup_script: scriptValue }
|
||||
: { dev_server_script: scriptValue };
|
||||
|
||||
await repoApi.update(selectedRepoId, updateData);
|
||||
await repoApi.update(selectedRepoId, updateData as UpdateRepo);
|
||||
|
||||
// Invalidate repos cache
|
||||
queryClient.invalidateQueries({ queryKey: ['repos'] });
|
||||
@@ -256,15 +234,7 @@ const ScriptFixerDialogImpl = NiceModal.create<ScriptFixerDialogProps>(
|
||||
} finally {
|
||||
setIsTesting(false);
|
||||
}
|
||||
}, [
|
||||
selectedRepoId,
|
||||
script,
|
||||
scriptType,
|
||||
workspaceId,
|
||||
queryClient,
|
||||
t,
|
||||
repos,
|
||||
]);
|
||||
}, [selectedRepoId, script, scriptType, workspaceId, queryClient, t]);
|
||||
|
||||
const dialogTitle =
|
||||
scriptType === 'setup'
|
||||
|
||||
Reference in New Issue
Block a user