diff --git a/app/(main)/releases/page.tsx b/app/(main)/releases/page.tsx index 0be3001e..532ddf57 100644 --- a/app/(main)/releases/page.tsx +++ b/app/(main)/releases/page.tsx @@ -6,7 +6,6 @@ import { formatAppVersionLabel, getAppVersion, getReleaseUrl } from "@/lib/app-v import { formatCommitSubject, getReleaseCommitPreview, - RELEASE_COMMIT_PREVIEW_LIMIT, } from "@/lib/release-commits" import { readReleaseManifest } from "@/lib/release-manifest" import { cn } from "@/lib/utils" @@ -16,23 +15,23 @@ export const dynamic = "force-dynamic" function formatPublishedAt(value: string | null, isProdBuild: boolean): string { if (value) { - return new Intl.DateTimeFormat("ru-RU", { + return "Дата манифеста: " + new Intl.DateTimeFormat("ru-RU", { dateStyle: "long", timeStyle: "short", }).format(new Date(value)) } - return isProdBuild ? "Прод-сборка" : "Локальная сборка" + return isProdBuild ? "Дата манифеста не указана" : "Локальная сборка" } export default function ReleasesPage() { const manifest = readReleaseManifest() const version = getAppVersion() const isProdBuild = !version.endsWith("-dev") - const releaseUrl = getReleaseUrl() || manifest.releaseUrl || null - const commits = getReleaseCommitPreview(manifest.commits) + const releaseUrl = getReleaseUrl() || manifest?.releaseUrl || null + const commits = getReleaseCommitPreview(manifest?.commits ?? []) return ( -
+
- - Открыть в Gitea + + Открыть релиз ) : null } /> -
+
- {formatAppVersionLabel(version)} - {formatPublishedAt(manifest.publishedAt, isProdBuild)} + {formatAppVersionLabel(version)} + {isProdBuild ? formatPublishedAt(manifest?.version === version ? manifest.publishedAt : null, true) : "Локальная сборка"}

Версия формируется автоматически от базы v1.0.0 по Conventional Commits.

+ {!manifest ?

Метаданные релиза недоступны или повреждены. Дата, ссылка и список коммитов не подтверждены.

: manifest.version !== version && isProdBuild ?

Манифест относится к {formatAppVersionLabel(manifest.version)}; версия запущенной сборки отличается.

: null} + 0 - ? `Последние ${RELEASE_COMMIT_PREVIEW_LIMIT} коммитов в сборке ${formatAppVersionLabel(manifest.version)}.` - : "Для локальной разработки список коммитов пуст. В прод-сборке он заполняется CI." + ? `Коммиты манифеста ${formatAppVersionLabel(manifest!.version)}: ${commits.length}.` + : manifest ? "В манифесте нет коммитов. При публикации список формируется CI." : "Список коммитов не подтверждён." } contentClassName="px-5 pb-5" > {commits.length === 0 ? ( -

Коммитов для отображения пока нет.

+

{manifest ? "Коммитов для отображения пока нет." : "Нет подтверждённых метаданных."}

) : (
    {commits.map((commit) => ( -
  • +
  • {commit.type} {commit.shortSha} {commit.author}
    -

    {formatCommitSubject(commit.subject)}

    +

    {formatCommitSubject(commit.subject)}

  • ))}
diff --git a/components/release-notes-modal.tsx b/components/release-notes-modal.tsx index 336b3109..b8187146 100644 --- a/components/release-notes-modal.tsx +++ b/components/release-notes-modal.tsx @@ -16,9 +16,8 @@ import { formatAppVersionLabel, getAppVersion } from "@/lib/app-version" import { formatCommitSubject, getReleaseCommitPreview, - RELEASE_COMMIT_PREVIEW_LIMIT, } from "@/lib/release-commits" -import type { ReleaseManifest } from "@/lib/release-manifest" +import {parseReleaseManifest,shouldShowReleaseNotes,type ReleaseManifest} from "@/lib/release-metadata" import { hasSeenReleaseModal, markReleaseModalSeen } from "@/lib/release-modal-storage" export function ReleaseNotesModal() { @@ -27,26 +26,30 @@ export function ReleaseNotesModal() { React.useEffect(() => { let cancelled = false + const controller=new AbortController() + const timeout=setTimeout(()=>controller.abort(),8000) async function loadManifest() { try { - const response = await fetch("/release-manifest.json", { cache: "no-store" }) + const response = await fetch("/release-manifest.json", { cache: "no-store", signal:controller.signal }) if (!response.ok) return - const data = (await response.json()) as ReleaseManifest - if (cancelled || !data.commits?.length || hasSeenReleaseModal(data.tag)) return + const data = parseReleaseManifest(await response.json()) + if (cancelled || controller.signal.aborted || !data || !shouldShowReleaseNotes(data,getAppVersion()) || hasSeenReleaseModal(data.tag)) return setManifest(data) setOpen(true) } catch { // Локальная сборка или недоступный manifest — модалку не показываем. - } + } finally {clearTimeout(timeout)} } void loadManifest() return () => { cancelled = true + clearTimeout(timeout) + controller.abort() } }, []) @@ -68,7 +71,7 @@ export function ReleaseNotesModal() { Что нового в {versionLabel} - Последние {RELEASE_COMMIT_PREVIEW_LIMIT} коммитов текущей сборки MikrotikManager. + Коммиты текущей сборки MikrotikManager: {commits.length}. @@ -78,7 +81,7 @@ export function ReleaseNotesModal() { {commits.map((commit) => (
  • @@ -99,6 +102,7 @@ export function ReleaseNotesModal() {