Migrate frontend to Svelte 5 runes semantics

This commit is contained in:
2026-03-11 11:29:24 +03:00
parent e50fc4c476
commit abfe06cea3
61 changed files with 989 additions and 922 deletions

View File

@@ -6,12 +6,12 @@
@RELATION: CALLS -> gitService.getBranches
@RELATION: CALLS -> gitService.checkoutBranch
@RELATION: CALLS -> gitService.createBranch
@RELATION: DISPATCHES -> change
@RELATION: BINDS_TO -> onchange
-->
<script>
// [SECTION: IMPORTS]
import { onMount, createEventDispatcher } from 'svelte';
import { onMount } from 'svelte';
import { gitService } from '../../services/gitService';
import { addToast as toast } from '../../lib/toasts.js';
import { t } from '../../lib/i18n';
@@ -23,6 +23,7 @@
dashboardId,
envId = null,
currentBranch = $bindable('main'),
onchange = () => {},
} = $props();
// [/SECTION]
@@ -33,9 +34,6 @@
let showCreate = $state(false);
let newBranchName = $state('');
// [/SECTION]
const dispatch = createEventDispatcher();
// [DEF:onMount:Function]
/**
* @purpose Load branches when component is mounted.
@@ -83,14 +81,14 @@
/**
* @purpose Переключает текущую ветку.
* @param {string} branchName - Имя ветки.
* @post currentBranch обновлен, событие отправлено.
* @post currentBranch обновлен, родительский callback вызван.
*/
async function handleCheckout(branchName) {
console.log(`[BranchSelector][Action] Checking out branch ${branchName}`);
try {
await gitService.checkoutBranch(dashboardId, branchName, envId);
currentBranch = branchName;
dispatch('change', { branch: branchName });
onchange({ branch: branchName });
toast($t.git?.switched_to?.replace('{branch}', branchName), 'success');
console.log(`[BranchSelector][Coherence:OK] Checked out ${branchName}`);
} catch (e) {

View File

@@ -12,7 +12,6 @@
<script>
// [SECTION: IMPORTS]
import { createEventDispatcher, onMount } from "svelte";
import { gitService } from "../../services/gitService";
import { addToast as toast } from "../../lib/toasts.js";
import { api } from "../../lib/api";
@@ -33,8 +32,6 @@
let generatingMessage = $state(false);
// [/SECTION]
const dispatch = createEventDispatcher();
// [DEF:handleGenerateMessage:Function]
/**
* @purpose Generates a commit message using LLM.
@@ -107,7 +104,7 @@
/**
* @purpose Создает коммит с указанным сообщением.
* @pre message не должно быть пустым.
* @post Коммит создан, событие отправлено, модальное окно закрыто.
* @post Коммит создан и модальное окно закрыто.
*/
async function handleCommit() {
if (!message) return;
@@ -118,7 +115,6 @@
try {
await gitService.commit(dashboardId, message, [], envId);
toast($t.git?.commit_success, "success");
dispatch("commit");
show = false;
message = "";
console.log(`[CommitModal][Coherence:OK] Committed`);

View File

@@ -3,14 +3,13 @@
@SEMANTICS: git, conflict, resolution, merge
@PURPOSE: UI for resolving merge conflicts (Keep Mine / Keep Theirs).
@LAYER: Component
@RELATION: DISPATCHES -> resolve
@RELATION: BINDS_TO -> onresolve
@INVARIANT: User must resolve all conflicts before saving.
-->
<script>
// [SECTION: IMPORTS]
import { createEventDispatcher } from "svelte";
import { addToast as toast } from "../../lib/toasts.js";
// [/SECTION]
@@ -18,12 +17,12 @@
let {
conflicts = [],
show = $bindable(false),
onresolve = () => {},
} = $props();
// [/SECTION]
// [SECTION: STATE]
const dispatch = createEventDispatcher();
/** @type {Object.<string, 'mine' | 'theirs' | 'manual'>} */
let resolutions = $state({});
// [/SECTION]
@@ -50,7 +49,7 @@
/**
* @purpose Validate and submit resolutions.
* @pre All conflicts must have a resolution.
* @post 'resolve' event dispatched if valid.
* @post Parent callback receives resolutions if valid.
* @side_effect Dispatches event and closes modal.
*/
function handleSave() {
@@ -69,7 +68,7 @@
// 2. Implementation
console.log(`[ConflictResolver][Coherence:OK] All conflicts resolved`);
dispatch("resolve", resolutions);
onresolve(resolutions);
show = false;
}
// [/DEF:handleSave:Function]

View File

@@ -11,7 +11,6 @@
<script>
// [SECTION: IMPORTS]
import { createEventDispatcher } from "svelte";
import { gitService } from "../../services/gitService";
import { api } from "../../lib/api.js";
import { addToast as toast } from "../../lib/toasts.js";
@@ -30,7 +29,6 @@
let deploying = $state(false);
// [/SECTION]
const dispatch = createEventDispatcher();
const normalizedPreferredStage = $derived(String(preferredTargetStage || "").toUpperCase());
const deploymentCandidates = $derived.by(() => {
const all = environments.filter((env) => env?.id !== envId);
@@ -109,7 +107,7 @@
/**
* @purpose Trigger deployment to selected environment.
* @pre selectedEnv must be set.
* @post deploy event dispatched on success.
* @post Deploy request finishes and modal closes on success.
* @side_effect Triggers API call, closes modal, shows toast.
*/
async function handleDeploy() {
@@ -130,7 +128,6 @@
result.message || $t.git?.deploy_success,
"success",
);
dispatch("deploy");
show = false;
console.log(`[DeploymentModal][Coherence:OK] Deployment triggered`);
} catch (e) {
@@ -172,10 +169,11 @@
</p>
{/if}
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2"
<label for="deployment-target-env" class="block text-sm font-medium text-gray-700 mb-2"
>{$t.migration?.target_env}</label
>
<select
id="deployment-target-env"
bind:value={selectedEnv}
class="w-full border rounded p-2 focus:ring-2 focus:ring-blue-500 outline-none bg-white"
>

View File

@@ -796,10 +796,18 @@
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
onclick={handleBackdropClick}
onkeydown={(event) => {
if (event.key === 'Escape') closeModal();
}}
role="button"
tabindex="0"
aria-label={$t.common?.close || 'Close'}
>
<div
class="relative max-h-[90vh] w-full max-w-6xl overflow-y-auto rounded-lg bg-white p-6 shadow-2xl"
onclick={(event) => event.stopPropagation()}
role="dialog"
aria-modal="true"
aria-label={`${$t.git?.management || 'Управление Git'}: ${dashboardTitle}`}
>
<button
type="button"
@@ -1190,7 +1198,7 @@
<ConflictResolver
conflicts={mergeConflicts}
bind:show={showConflictResolver}
on:resolve={handleResolveConflicts}
onresolve={handleResolveConflicts}
/>
<DeploymentModal