This commit is contained in:
2026-05-27 23:24:12 +03:00
parent d2c60c87e2
commit 477e30a9f2
36 changed files with 1348 additions and 306 deletions

View File

@@ -32,6 +32,7 @@
let loading = $state(false);
let showCreate = $state(false);
let newBranchName = $state('');
let branchError = $state(null);
// #endregion state
// #region loadBranches [C:2] [TYPE Function]
@@ -68,7 +69,9 @@
// @PRE branchName is non-empty; envId required when ref is slug.
// @POST currentBranch updated; onchange callback fired.
// @SIDE_EFFECT POSTs to /git/repositories/{ref}/checkout.
// @UX_STATE Error -> Inline error message below the dropdown; persistent toast above modal with full details.
async function handleCheckout(branchName) {
branchError = null;
console.log(`[EXT:frontend:BranchSelector][Action] Checking out branch ${branchName}`);
try {
await gitService.checkoutBranch(dashboardId, branchName, envId);
@@ -78,7 +81,15 @@
console.log(`[EXT:frontend:BranchSelector][Coherence:OK] Checked out ${branchName}`);
} catch (e) {
console.error(`[EXT:frontend:BranchSelector][Coherence:Failed] ${e.message}`);
toast(e.message, 'error');
const detail = typeof e?.detail === 'object' ? e.detail : {};
const nextSteps = detail?.next_steps || [];
const shortMsg = detail?.message || detail?.message_en || 'Ошибка переключения ветки';
branchError = {
message: shortMsg,
next_steps: nextSteps,
};
// Persistent toast above modal with the full technical error
toast(shortMsg, 'warning', 0);
}
}
// #endregion handleCheckout
@@ -90,6 +101,7 @@
// @SIDE_EFFECT POSTs to /git/repositories/{ref}/branches.
async function handleCreate() {
if (!newBranchName) return;
branchError = null;
console.log(`[EXT:frontend:BranchSelector][Action] Creating branch ${newBranchName} from ${currentBranch}`);
try {
await gitService.createBranch(dashboardId, newBranchName, currentBranch, envId);
@@ -100,6 +112,7 @@
console.log(`[EXT:frontend:BranchSelector][Coherence:OK] Branch created`);
} catch (e) {
console.error(`[EXT:frontend:BranchSelector][Coherence:Failed] ${e.message}`);
branchError = { message: e.message || 'Ошибка создания ветки', next_steps: [] };
toast(e.message, 'error');
}
}
@@ -133,6 +146,27 @@
</Button>
</div>
{#if branchError}
<div class="max-h-32 overflow-y-auto rounded-lg border border-red-300 bg-red-50 p-3 text-sm text-red-800" role="alert">
<div class="flex items-start gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="mt-0.5 h-4 w-4 flex-shrink-0 text-red-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 9l-6 6m0-6l6 6"/></svg>
<div class="flex-1 min-w-0">
<p class="truncate">{branchError.message}</p>
{#if branchError.next_steps?.length}
<ul class="mt-1 list-disc pl-4 text-xs text-red-700">
{#each branchError.next_steps as step}
<li>{step}</li>
{/each}
</ul>
{/if}
</div>
<button type="button" onclick={() => branchError = null} class="flex-shrink-0 rounded p-0.5 hover:bg-red-100" aria-label="Закрыть">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>
</button>
</div>
</div>
{/if}
{#if showCreate}
<div class="flex items-end gap-2 bg-gray-50 p-3 rounded-lg border border-dashed border-gray-200">
<div class="flex-grow">