52 lines
2.1 KiB
JavaScript
52 lines
2.1 KiB
JavaScript
import React from 'react';
|
|
|
|
const bootCopy = {
|
|
'control-unreachable': {
|
|
title: 'Harbor недоступен',
|
|
message: 'Control plane не ответил. Проверьте, что контейнер запущен, и повторите запрос.',
|
|
},
|
|
'incompatible-api': {
|
|
title: 'Версия Harbor несовместима',
|
|
message: 'Интерфейс получил state неизвестной версии. Обновите frontend и control plane вместе.',
|
|
},
|
|
fatal: {
|
|
title: 'Harbor не удалось запустить',
|
|
message: 'Произошла непредвиденная ошибка. Технические детали помогут найти причину.',
|
|
},
|
|
};
|
|
|
|
export function BootStatePage({ transport, onRetry }) {
|
|
if (transport.bootStatus === 'loading') return <div className="app-loading">Harbor</div>;
|
|
|
|
const copy = bootCopy[transport.bootStatus] || bootCopy.fatal;
|
|
return (
|
|
<main className="app-boot">
|
|
<span>Harbor</span>
|
|
<h1>{copy.title}</h1>
|
|
<p>{copy.message}</p>
|
|
<button type="button" onClick={onRetry}>Повторить</button>
|
|
<details>
|
|
<summary>Технические детали</summary>
|
|
<code>{transport.error?.message}</code>
|
|
<pre>{`curl -i ${window.location.origin}/api/state\ndocker compose logs --tail=100`}</pre>
|
|
</details>
|
|
</main>
|
|
);
|
|
}
|
|
|
|
export function StaleBanner({ transport, onRetry }) {
|
|
if (!transport.stale) return null;
|
|
const lastSync = transport.lastSuccessfulSyncAt
|
|
? new Date(transport.lastSuccessfulSyncAt).toLocaleTimeString('ru-RU')
|
|
: 'неизвестно';
|
|
const incompatible = transport.error?.kind === 'incompatible-api';
|
|
|
|
return (
|
|
<aside className="client-stale-banner" role="status">
|
|
<strong>{incompatible ? 'API несовместим' : 'Показано последнее известное состояние'}</strong>
|
|
<span>Последняя синхронизация: {lastSync}</span>
|
|
<button type="button" onClick={onRetry}>Повторить</button>
|
|
</aside>
|
|
);
|
|
}
|