Работает создание коммитов и перенос в новый enviroment

This commit is contained in:
2026-01-23 13:57:44 +03:00
parent e9d3f3c827
commit 07ec2d9797
37 changed files with 3227 additions and 252 deletions

View File

@@ -0,0 +1,170 @@
<!-- [DEF:BranchSelector:Component] -->
<!--
@SEMANTICS: git, branch, selection, checkout
@PURPOSE: UI для выбора и создания веток Git.
@LAYER: Component
@RELATION: CALLS -> gitService.getBranches
@RELATION: CALLS -> gitService.checkoutBranch
@RELATION: CALLS -> gitService.createBranch
@RELATION: DISPATCHES -> change
-->
<script>
// [SECTION: IMPORTS]
import { onMount, createEventDispatcher } from 'svelte';
import { gitService } from '../../services/gitService';
import { addToast as toast } from '../../lib/toasts.js';
// [/SECTION]
// [SECTION: PROPS]
export let dashboardId;
export let currentBranch = 'main';
// [/SECTION]
// [SECTION: STATE]
let branches = [];
let loading = false;
let showCreate = false;
let newBranchName = '';
// [/SECTION]
const dispatch = createEventDispatcher();
// [DEF:onMount:Function]
onMount(async () => {
await loadBranches();
});
// [/DEF:onMount:Function]
// [DEF:loadBranches:Function]
/**
* @purpose Загружает список веток для дашборда.
* @post branches обновлен.
*/
async function loadBranches() {
console.log(`[BranchSelector][Action] Loading branches for dashboard ${dashboardId}`);
loading = true;
try {
branches = await gitService.getBranches(dashboardId);
console.log(`[BranchSelector][Coherence:OK] Loaded ${branches.length} branches`);
} catch (e) {
console.error(`[BranchSelector][Coherence:Failed] ${e.message}`);
toast('Failed to load branches', 'error');
} finally {
loading = false;
}
}
// [/DEF:loadBranches:Function]
// [DEF:handleSelect:Function]
function handleSelect(event) {
handleCheckout(event.target.value);
}
// [/DEF:handleSelect:Function]
// [DEF:handleCheckout:Function]
/**
* @purpose Переключает текущую ветку.
* @param {string} branchName - Имя ветки.
* @post currentBranch обновлен, событие отправлено.
*/
async function handleCheckout(branchName) {
console.log(`[BranchSelector][Action] Checking out branch ${branchName}`);
try {
await gitService.checkoutBranch(dashboardId, branchName);
currentBranch = branchName;
dispatch('change', { branch: branchName });
toast(`Switched to ${branchName}`, 'success');
console.log(`[BranchSelector][Coherence:OK] Checked out ${branchName}`);
} catch (e) {
console.error(`[BranchSelector][Coherence:Failed] ${e.message}`);
toast(e.message, 'error');
}
}
// [/DEF:handleCheckout:Function]
// [DEF:handleCreate:Function]
/**
* @purpose Создает новую ветку.
* @post Новая ветка создана и загружена.
*/
async function handleCreate() {
if (!newBranchName) return;
console.log(`[BranchSelector][Action] Creating branch ${newBranchName} from ${currentBranch}`);
try {
await gitService.createBranch(dashboardId, newBranchName, currentBranch);
toast(`Created branch ${newBranchName}`, 'success');
showCreate = false;
newBranchName = '';
await loadBranches();
console.log(`[BranchSelector][Coherence:OK] Branch created`);
} catch (e) {
console.error(`[BranchSelector][Coherence:Failed] ${e.message}`);
toast(e.message, 'error');
}
}
// [/DEF:handleCreate:Function]
</script>
<!-- [SECTION: TEMPLATE] -->
<div class="space-y-2">
<div class="flex items-center space-x-2">
<div class="relative">
<select
value={currentBranch}
on:change={handleSelect}
disabled={loading}
class="bg-white border rounded px-3 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
>
{#each branches as branch}
<option value={branch.name}>{branch.name}</option>
{/each}
</select>
{#if loading}
<span class="absolute -right-6 top-1">
<svg class="animate-spin h-4 w-4 text-blue-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</span>
{/if}
</div>
<button
on:click={() => showCreate = !showCreate}
disabled={loading}
class="text-blue-600 hover:text-blue-800 text-sm font-medium disabled:opacity-50"
>
+ New Branch
</button>
</div>
{#if showCreate}
<div class="flex items-center space-x-1 bg-gray-50 p-2 rounded border border-dashed">
<input
type="text"
bind:value={newBranchName}
placeholder="branch-name"
disabled={loading}
class="border rounded px-2 py-1 text-sm w-full max-w-[150px]"
/>
<button
on:click={handleCreate}
disabled={loading || !newBranchName}
class="bg-green-600 text-white px-3 py-1 rounded text-xs font-medium hover:bg-green-700 disabled:opacity-50"
>
{loading ? '...' : 'Create'}
</button>
<button
on:click={() => showCreate = false}
disabled={loading}
class="text-gray-500 hover:text-gray-700 text-xs px-2 py-1 disabled:opacity-50"
>
Cancel
</button>
</div>
{/if}
</div>
<!-- [/SECTION] -->
<!-- [/DEF:BranchSelector:Component] -->