feat(integrations): add merge-method selection and provider-specific payloads

Introduce dedicated merge handling for integration review merges:

- Add src-tauri/src/integrations/merge.rs: implements merge_options (read provider repo settings), merge_payload (build provider-specific merge body) and a Tauri command get_integration_review_merge_options. Includes unit tests for behavior.
- Wire merge module into integrations.rs and pass an optional merge_method into provider-specific review action functions (GitHub, GitLab, Gitea, Azure DevOps). run_integration_review_action now accepts an optional merge_method, validates it early, and includes provider-specific merge payloads when performing a merge.
- Export the new command in src-tauri/src/main.rs so the frontend can request merge options.

Frontend changes to support selecting a merge method before merging:

- ConfirmDialog.svelte: add SelectMenu support and a select field to confirm requests.
- ReviewCenter.svelte: fetch integration merge options, show a merge-method selector in the merge confirmation, and pass the chosen method to the review action.
- Update types and git bindings to surface IntegrationMergeOptions / IntegrationMergeMethod and the getIntegrationReviewMergeOptions call (git.ts / types.ts changes staged).

Effect: users can pick a merge method appropriate to the provider/project; the integration layer generates the correct API payload per provider. Tests added for merge logic.
This commit is contained in:
2026-09-18 15:12:25 +02:00
parent ed484f5477
commit 6a40159f9f
7 changed files with 202 additions and 29 deletions
+11 -2
View File
@@ -5,6 +5,7 @@
* untranslated, event-blocking browser dialog.
*/
import { AlertTriangle, Check, LoaderCircle, Trash2, X } from "@lucide/svelte";
import SelectMenu from "./SelectMenu.svelte";
import { t } from "../i18n.svelte";
export interface ConfirmRequest {
@@ -25,6 +26,7 @@
input?: { label: string; placeholder?: string; value?: string; optional?: boolean };
/** Destructive actions get the red confirm button and warning icon. */
danger?: boolean;
select?: { label: string; value: string; options: { value: string; label: string }[] };
}
interface Props {
@@ -47,13 +49,13 @@
let value = $state("");
let inputElement = $state<HTMLInputElement | null>(null);
let missingInput = $derived(Boolean(request.input) && request.input?.optional !== true && value.trim().length === 0);
let blocked = $derived((Boolean(request.checkbox?.required) && !checked) || missingInput);
let blocked = $derived((Boolean(request.checkbox?.required) && !checked) || missingInput || (Boolean(request.select) && !request.select?.options.some(option => option.value === value)));
$effect(() => {
// Start from the defaults again whenever a different confirmation is shown.
request.title;
checked = request.checkbox?.defaultChecked ?? false;
value = request.input?.value ?? "";
value = request.select?.value ?? request.input?.value ?? "";
});
$effect(() => {
@@ -144,6 +146,13 @@
</label>
{/if}
{#if request.select}
<div class="confirm-input">
<span>{request.select.label}</span>
<SelectMenu {value} options={request.select.options} ariaLabel={request.select.label} disabled={isBusy} onChange={(selected) => value = selected} />
</div>
{/if}
{#if request.checkbox}
<label class="confirm-check">
<input type="checkbox" bind:checked disabled={isBusy} />