feat(git): clarify dashboard release flow
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
import CreateBranchDialog from './CreateBranchDialog.svelte';
|
||||
import MergeDialog from './MergeDialog.svelte';
|
||||
import GitEnvironmentTimeline from './GitEnvironmentTimeline.svelte';
|
||||
import GitFeatureWorkflow from './GitFeatureWorkflow.svelte';
|
||||
import BranchSelector from './BranchSelector.svelte';
|
||||
|
||||
let { dashboardId, envId = null, dashboardTitle = '', show = $bindable(false) } = $props();
|
||||
@@ -124,10 +125,10 @@
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<div class="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-surface-overlay pt-6 backdrop-blur-sm" onclick={handleBackdropClick} onkeydown={(e) => { if (e.key === 'Escape') handleModalClose(); if (e.key === 'Tab') trapFocus(e); }} role="dialog" aria-modal="true" tabindex="-1" aria-label={`${$t.git?.management || 'Управление Git'}: ${dashboardTitle}`}>
|
||||
<div bind:this={modalEl} class="relative w-[95vw] max-w-[1600px] overflow-hidden rounded-xl bg-surface-card shadow-2xl" role="document" aria-label={`${$t.git?.management || 'Управление Git'}: ${dashboardTitle}`}>
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-surface-overlay p-4 backdrop-blur-sm sm:p-6" onclick={handleBackdropClick} onkeydown={(e) => { if (e.key === 'Escape') handleModalClose(); if (e.key === 'Tab') trapFocus(e); }} role="dialog" aria-modal="true" tabindex="-1" aria-label={`${$t.git?.management || 'Управление Git'}: ${dashboardTitle}`}>
|
||||
<div bind:this={modalEl} class="relative flex h-[calc(100dvh-2rem)] w-[95vw] max-w-[1600px] flex-col overflow-hidden rounded-xl bg-surface-card shadow-2xl sm:h-[calc(100dvh-3rem)]" role="document" aria-label={`${$t.git?.management || 'Управление Git'}: ${dashboardTitle}`}>
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between border-b border-border bg-surface-page px-6 py-4">
|
||||
<div class="flex shrink-0 items-center justify-between border-b border-border bg-surface-page px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-primary text-white shadow-sm">
|
||||
<Icon name="code" size={20} strokeWidth={2} />
|
||||
@@ -202,27 +203,15 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Body: height fills space, scroll is inside GitWorkspacePanel diff panel -->
|
||||
<div class="flex flex-col p-6" style="height: calc(92vh - 80px);">
|
||||
<!-- Body owns the modal scroll so every action, including commit message, remains reachable. -->
|
||||
<div class="min-h-0 flex-1 overflow-y-auto p-6">
|
||||
|
||||
{#if model.checkingStatus}
|
||||
<div class="flex justify-center py-12"><div class="h-8 w-8 animate-spin rounded-full border-b-2 border-primary-ring"></div></div>
|
||||
{:else if !model.initialized}
|
||||
<GitInitPanel configs={model.configs} bind:selectedConfigId={model.selectedConfigId} bind:remoteUrl={model.remoteUrl} creatingRemoteRepo={model.creatingRemoteRepo} loading={model.loading} onCreateRemoteRepo={() => model.handleCreateRemoteRepo()} onInit={() => model.handleInit()} />
|
||||
{:else}
|
||||
<div class="flex min-h-0 flex-1 flex-col gap-4">
|
||||
{#if model.hasOriginConfigMismatch}
|
||||
<div class="rounded-lg border border-warning bg-warning-light p-3 text-sm text-warning">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div>
|
||||
<div class="font-semibold">{$t.git?.git_server_mismatch_title || 'Git server mismatch detected'}</div>
|
||||
<div class="mt-1">{($t.git?.git_server_mismatch_desc || 'Configured: {configured}, origin: {origin}.').replace('{configured}', model.configHost).replace('{origin}', model.originHost)}</div>
|
||||
<div class="mt-1.5 text-xs text-warning/80">{$t.git?.git_server_mismatch_hint || 'Push/Pull будут отправлять на настроенный сервер, а не на origin. Обновите конфигурацию в Настройках → Git, если это не intended.'}</div>
|
||||
</div>
|
||||
<a href={ROUTES.settings.git()} class="shrink-0 rounded-md border border-warning bg-surface-card px-3 py-1.5 text-xs font-medium text-warning transition-colors hover:bg-warning-light">{$t.git?.git_server_mismatch_fix || 'Настроить'}</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex min-w-0 flex-col gap-4">
|
||||
{#if model.commitCompleted}
|
||||
<div class="rounded-lg border border-success bg-success-light p-3 text-sm text-success">
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -239,11 +228,15 @@
|
||||
{/if}
|
||||
<GitDeploymentPipeline
|
||||
deploymentStatus={model.deploymentStatus}
|
||||
currentVersionDate={model.workspaceStatus?.last_commit_date || null}
|
||||
currentVersionHash={model.workspaceStatus?.last_commit_hash || null}
|
||||
hasWorkspaceChanges={model.hasWorkspaceChanges}
|
||||
changedFilesCount={model.changedFilesCount}
|
||||
validatingPreprod={model.validatingPreprod}
|
||||
onSync={() => model.handleSync()}
|
||||
onDeployPreprod={() => model.openDeployModal('PREPROD')}
|
||||
onValidatePreprod={() => model.validatePreprodDeployment()}
|
||||
onDeployProd={() => model.openDeployModal('PROD')}
|
||||
onDeployProd={(commitHash) => model.openDeployModal('PROD', commitHash)}
|
||||
onCompare={async () => {
|
||||
const prod = model.environmentHistories.prod?.[0];
|
||||
const dev = model.environmentHistories.dev?.[0];
|
||||
@@ -259,19 +252,53 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Branch selector moved here per UX review: separate from version map to avoid confusion -->
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<div class="text-xs font-medium text-text-muted uppercase tracking-wide">{$t.git?.working_branch || 'Working branch (current changes):'}</div>
|
||||
<div class="flex-1 max-w-[280px]">
|
||||
<BranchSelector
|
||||
{dashboardId}
|
||||
envId={model.resolvedEnvId}
|
||||
bind:currentBranch={model.currentBranch}
|
||||
onchange={(event) => model.handleBranchChanged(event)}
|
||||
onmerge={handleOpenMergeDialog}
|
||||
/>
|
||||
{#if model.hasWorkspaceChanges}
|
||||
<section class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-warning/30 bg-warning-light px-4 py-3" aria-label={$t.git?.workspace_pending_title || 'Несохранённые изменения'}>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-text">{$t.git?.workspace_pending_title || 'Есть несохранённые изменения'}</h3>
|
||||
<p class="mt-0.5 text-xs text-text-muted">{($t.git?.workspace_pending_hint || '{count} файлов изменены. Они не войдут в текущую публикацию, пока вы не сохраните новую версию.').replace('{count}', String(model.changedFilesCount))}</p>
|
||||
</div>
|
||||
<Button variant="secondary" size="sm" onclick={() => { model.activeTab = 'workspace'; }}>
|
||||
<Icon name="edit" size={14} class="mr-1" />{$t.git?.workspace_pending_action || 'Сохранить новую версию'}
|
||||
</Button>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<GitFeatureWorkflow
|
||||
branches={model.branches}
|
||||
currentBranch={model.currentBranch}
|
||||
{dashboardId}
|
||||
envId={model.resolvedEnvId}
|
||||
openFeature={(branch) => model.openFeatureDraft(branch)}
|
||||
onCreate={() => { model.showCreateBranchDialog = true; }}
|
||||
onTransferred={async () => {
|
||||
await model.refreshBranches();
|
||||
await model.loadWorkspace();
|
||||
void model.loadEnvironmentHistories();
|
||||
}}
|
||||
/>
|
||||
|
||||
<details class="rounded-md border border-border bg-surface-page px-3 py-2 text-xs text-text-muted">
|
||||
<summary class="cursor-pointer font-medium text-text">{$t.git?.technical_details || 'Технические детали'}</summary>
|
||||
{#if model.hasOriginConfigMismatch}
|
||||
<div class="mt-3 flex items-start justify-between gap-3 rounded-md border border-warning/40 bg-warning-light px-3 py-2 text-xs text-warning">
|
||||
<p>Привязка репозитория использует другой Git-сервер: origin — {model.originHost}, выбранный сервер — {model.configHost}. Push заблокирован до перепривязки, чтобы не отправить изменения не в тот репозиторий.</p>
|
||||
<a href={ROUTES.settings.git()} class="shrink-0 font-medium underline">{$t.git?.git_server_mismatch_fix || 'Настроить'}</a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="mt-3 flex max-w-2xl flex-wrap items-center gap-3">
|
||||
<span class="shrink-0">{$t.git?.working_branch || 'Рабочая ветка'}:</span>
|
||||
<div class="min-w-[18rem] flex-1">
|
||||
<BranchSelector
|
||||
{dashboardId}
|
||||
envId={model.resolvedEnvId}
|
||||
bind:currentBranch={model.currentBranch}
|
||||
onchange={(event) => model.handleBranchChanged(event)}
|
||||
onmerge={handleOpenMergeDialog}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- BI dashboard version timeline: focused on status map. Operations below in tabs. -->
|
||||
<GitEnvironmentTimeline
|
||||
@@ -279,10 +306,7 @@
|
||||
environmentHistories={model.environmentHistories}
|
||||
historiesLoading={model.environmentHistoriesLoading}
|
||||
deploymentStatus={model.deploymentStatus}
|
||||
{dashboardId}
|
||||
envId={model.resolvedEnvId}
|
||||
bind:currentBranch={model.currentBranch}
|
||||
onBranchChange={(event) => model.handleBranchChanged(event)}
|
||||
onMerge={handleOpenMergeDialog}
|
||||
selectedA={model.selectedVersionA}
|
||||
selectedB={model.selectedVersionB}
|
||||
@@ -296,6 +320,7 @@
|
||||
addToast($t.git?.viz_diff_ready || 'Dashboard changes loaded for comparison', 'success');
|
||||
}
|
||||
}}
|
||||
onDeployVersion={(hash) => model.openDeployModal('PREPROD', hash)}
|
||||
/>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-1 border-b border-border pb-0" role="tablist" aria-label={$t.git?.management || 'Управление Git'}>
|
||||
@@ -333,7 +358,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<ConflictResolver conflicts={model.mergeConflicts} bind:show={model.showConflictResolver} onresolve={(e) => model.handleResolveConflicts(e)} />
|
||||
<DeploymentModal {dashboardId} envId={model.resolvedEnvId} preferredTargetStage={model.preferredDeployTargetStage} bind:show={model.showDeployModal} />
|
||||
<DeploymentModal {dashboardId} envId={model.resolvedEnvId} preferredTargetStage={model.preferredDeployTargetStage} commitHash={model.deployCommitHash} sourceBranch={model.currentBranch || null} bind:show={model.showDeployModal} />
|
||||
|
||||
{#if model.showDeployConfirm}
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-surface-overlay" onclick={() => { model.showDeployConfirm = false; }} onkeydown={(e) => { if (e.key === 'Escape') model.showDeployConfirm = false; }}>
|
||||
@@ -412,7 +437,11 @@
|
||||
{envId}
|
||||
sourceBranch={model.mergeSourceBranch}
|
||||
targetBranch={model.mergeTargetBranch || 'dev'}
|
||||
onmerged={() => model.refreshBranches()}
|
||||
onmerged={async () => {
|
||||
await model.refreshBranches();
|
||||
await model.loadWorkspace();
|
||||
void model.loadEnvironmentHistories();
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- Create Remote Repo Dialog (replaces native prompt()) -->
|
||||
|
||||
Reference in New Issue
Block a user