Fix git/storage workflows: repos-only page, default dev branch, robust pull/push, and storage path resolution

This commit is contained in:
2026-03-04 19:18:58 +03:00
parent 4fec2e02ad
commit 7ff0dfa8c6
10 changed files with 658 additions and 63 deletions

View File

@@ -21,6 +21,7 @@
import RepositoryDashboardGrid from '../../../components/RepositoryDashboardGrid.svelte';
import { addToast as toast } from '$lib/toasts.js';
import { api } from '$lib/api.js';
import { gitService } from '../../../services/gitService.js';
import type { DashboardMetadata } from '$lib/types/dashboard';
import { t } from '$lib/i18n';
import { Button, Card, PageHeader, Select } from '$lib/ui';
@@ -65,7 +66,24 @@
if (!envId) return;
fetchingDashboards = true;
try {
dashboards = await api.requestApi(`/environments/${envId}/dashboards`);
const pageSize = 100;
let page = 1;
let aggregatedDashboards: DashboardMetadata[] = [];
let totalPages = 1;
while (page <= totalPages) {
const response = await api.requestApi(
`/dashboards?env_id=${encodeURIComponent(envId)}&page=${page}&page_size=${pageSize}`,
);
const pageDashboards = Array.isArray(response?.dashboards)
? response.dashboards
: [];
aggregatedDashboards = aggregatedDashboards.concat(pageDashboards);
totalPages = Number(response?.total_pages || 1);
page += 1;
}
dashboards = await filterDashboardsWithRepositories(aggregatedDashboards);
} catch (e) {
toast(e.message, 'error');
dashboards = [];
@@ -75,6 +93,46 @@
}
// [/DEF:fetchDashboards:Function]
// [DEF:filterDashboardsWithRepositories:Function]
/**
* @PURPOSE: Keep only dashboards that already have initialized Git repositories.
* @PRE: dashboards list is loaded for selected environment.
* @POST: Returns dashboards with status != NO_REPO.
*/
async function filterDashboardsWithRepositories(
allDashboards: DashboardMetadata[],
): Promise<DashboardMetadata[]> {
if (allDashboards.length === 0) return [];
const chunkSize = 50;
const repositoryDashboardIds = new Set<number>();
const allIds = allDashboards.map((dashboard) => dashboard.id);
for (let offset = 0; offset < allIds.length; offset += chunkSize) {
const idsChunk = allIds.slice(offset, offset + chunkSize);
try {
const batchResponse = await gitService.getStatusesBatch(idsChunk);
const statuses = batchResponse?.statuses || {};
idsChunk.forEach((dashboardId) => {
const status = statuses[dashboardId] || statuses[String(dashboardId)];
const syncStatus = String(status?.sync_status || status?.sync_state || "").toUpperCase();
if (syncStatus && syncStatus !== "NO_REPO") {
repositoryDashboardIds.add(dashboardId);
}
});
} catch (error) {
console.error(
`[StorageReposPage][Coherence:Failed] Failed to resolve repository statuses chunk: ${error?.message || error}`,
);
}
}
return allDashboards.filter((dashboard) =>
repositoryDashboardIds.has(dashboard.id),
);
}
// [/DEF:filterDashboardsWithRepositories:Function]
onMount(fetchEnvironments);
$: environments = $environmentContextStore?.environments || [];
@@ -107,13 +165,13 @@
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
</div>
{:else}
<Card title={$t.git?.select_dashboard }>
<Card title={$t.nav?.repositories || "Репозитории"}>
{#if fetchingDashboards}
<p class="text-gray-500">{$t.common?.loading }</p>
{:else if dashboards.length > 0}
<RepositoryDashboardGrid {dashboards} statusMode="repository" />
<RepositoryDashboardGrid {dashboards} statusMode="repository" envId={selectedEnvId || null} repositoriesOnly={true} />
{:else}
<p class="text-gray-500 italic">{$t.dashboard?.no_dashboards }</p>
<p class="text-gray-500 italic">{$t.git?.no_repositories_selected || "Репозитории не найдены"}</p>
{/if}
</Card>
{/if}