Веб-интерфейс: страница /clusters, навигация и крошки для кластеров

- Выделена страница списка кластеров, панель упрощена; nav_active и крошки
  ведут в раздел Кластеры; theme.js синхронизирует активную пилюлю по URL.
- Доработки дашборда, аддонов, журнала, стилей и API-документации.
- Поддержка Podman: docker-compose.podman.yml, скрипты сокета; Makefile и env.
This commit is contained in:
Sergey Antropoff
2026-04-04 13:42:21 +03:00
parent 17f6233fd7
commit eb063aec20
38 changed files with 3990 additions and 734 deletions
+296 -47
View File
@@ -440,6 +440,16 @@ html[data-theme="light"] .nav-link.nav-pill.nav-pill--active:not(.nav-pill--ext)
font-size: 1.05rem;
}
/* Отдельная карточка на панели: донаты + список кластеров (GET /stats) */
.home-resources-summary-inner {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.home-resources-summary-card .donuts-card-title {
margin-bottom: 0.5rem;
}
/* Пояснение: узлы kind и метрики идут через Docker или Podman (CONTAINER_CLI) */
.stats-engine-hint {
margin: 0;
@@ -460,10 +470,10 @@ html[data-theme="light"] .nav-link.nav-pill.nav-pill--active:not(.nav-pill--ext)
padding: 0.85rem 0.65rem;
}
/* Среда: Docker API · Kind · Kubectl · Каталогов — один ряд, 4 колонки */
/* Среда: Docker API · Kind · Kubectl (3 в ряд); число каталогов — в сетке метрик под ними */
.stats-env-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(3, 1fr);
gap: 0.65rem;
flex-shrink: 0;
}
@@ -513,10 +523,10 @@ html[data-theme="light"] .stats-env-card--metric {
background: rgba(59, 130, 246, 0.07);
}
/* Метрики: по 4 карточки в ряд (4 метрики — один ряд) */
/* Метрики панели: по 3 карточки в ряд */
.stats-metrics-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(3, 1fr);
gap: 0.65rem;
flex: 1 1 auto;
align-content: start;
@@ -524,7 +534,7 @@ html[data-theme="light"] .stats-env-card--metric {
@media (max-width: 520px) {
.stats-metrics-grid {
grid-template-columns: repeat(2, 1fr);
grid-template-columns: 1fr;
}
}
@@ -909,6 +919,46 @@ html[data-theme="light"] .cluster-node-res-card__bar-track {
background: rgba(239, 68, 68, 0.12);
}
/* Страница «Кластеры»: заголовок слева, кнопка «Создать кластер» справа */
.clusters-page-hero-row {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
gap: 1rem 1.5rem;
}
.clusters-page-hero-text {
flex: 1 1 14rem;
min-width: 0;
}
.clusters-page-hero-lead {
margin: 0;
}
.clusters-page-hero-actions {
flex: 0 0 auto;
display: flex;
align-items: center;
padding-top: 0.15rem;
}
.clusters-page-create-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.6rem 1.35rem;
font-size: 0.95rem;
font-weight: 650;
border-radius: 10px;
text-decoration: none;
border: 1px solid transparent;
background: var(--accent);
color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);
white-space: nowrap;
}
.clusters-page-create-btn:hover {
filter: brightness(1.08);
}
/* Прогресс создания кластера */
.create-progress-wrap {
margin-top: 1rem;
@@ -2170,6 +2220,31 @@ html[data-theme="light"] .cluster-kube-hint.cluster-kube-hint--info {
margin: 0 0 0.55rem;
font-size: 1.02rem;
}
/* Заголовок карточки K8s + выпадающий фильтр namespace справа */
.cluster-k8s-card-header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 0.5rem 1rem;
margin-bottom: 0.55rem;
}
.cluster-k8s-card-header .cluster-detail-section-title {
margin: 0;
flex: 1 1 auto;
min-width: 0;
}
.cluster-k8s-ns-filter-wrap {
flex: 0 0 auto;
}
.cluster-k8s-ns-select {
width: auto;
min-width: 10rem;
max-width: min(18rem, 100%);
margin: 0;
padding: 0.35rem 0.5rem;
font-size: 0.88rem;
}
/* Сетка карточек узлов на странице кластера: не более 3 карточек в ряд */
.cluster-page-node-cards--wide.cluster-nodes-resources__cards-row {
@@ -2769,69 +2844,199 @@ html[data-theme="light"] .cluster-edit-yaml-preview-head {
flex: 1 1 14rem;
max-width: 28rem;
}
.cluster-addons-hint {
margin: 0.35rem 0 0;
font-size: 0.82rem;
}
.cluster-addons-status-bar {
margin-top: 0.65rem;
font-size: 0.85rem;
margin-top: 0.85rem;
}
.cluster-addons-status-bar--message .cluster-addons-status-msg {
margin: 0;
font-size: 0.88rem;
line-height: 1.45;
}
.cluster-addons-status-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
gap: 0.65rem;
}
.cluster-addons-status-card {
border-radius: 10px;
border: 1px solid var(--border);
padding: 0.65rem 0.75rem;
background: rgba(0, 0, 0, 0.14);
display: flex;
flex-direction: column;
gap: 0.35rem;
min-height: 3.5rem;
justify-content: center;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
html[data-theme="light"] .cluster-addons-status-card {
background: rgba(15, 23, 42, 0.04);
}
.cluster-addons-status-card--on {
border-color: rgba(34, 197, 94, 0.45);
box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.12);
}
.cluster-addons-status-card--off {
border-color: var(--border);
opacity: 0.92;
}
.cluster-addons-status-card__label {
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
line-height: 1.25;
word-break: break-word;
}
.cluster-addons-status-card__value {
font-size: 1.05rem;
font-weight: 700;
letter-spacing: 0.02em;
}
.cluster-addons-status-card--on .cluster-addons-status-card__value {
color: rgb(34, 197, 94);
}
.cluster-addons-status-card--off .cluster-addons-status-card__value {
color: var(--muted);
}
.cluster-addons-grid {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 1rem;
margin: 1rem 0;
}
@media (min-width: 52rem) {
.cluster-addons-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* Шапка карточки аддона: заголовок + бейдж «установлен» справа */
.cluster-addon-card__header {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 0.65rem;
margin-bottom: 0.35rem;
}
.cluster-addon-card__title {
margin: 0 0 0.35rem;
.cluster-addon-card__header .cluster-addon-card__title {
margin: 0;
flex: 1 1 auto;
min-width: 0;
font-size: 1.05rem;
line-height: 1.3;
}
.cluster-addon-card__badge {
flex: 0 0 auto;
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
padding: 0.28rem 0.5rem;
border-radius: 6px;
border: 1px solid var(--border);
line-height: 1.2;
white-space: nowrap;
}
.cluster-addon-card__badge--on {
border-color: rgba(34, 197, 94, 0.5);
color: rgb(34, 197, 94);
background: rgba(34, 197, 94, 0.1);
}
.cluster-addon-card__badge--off {
color: var(--muted);
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-addon-card__badge--off {
background: rgba(15, 23, 42, 0.06);
}
.cluster-addon-card__values-details {
margin: 0.75rem 0 0;
border-radius: 8px;
border: 1px solid var(--border);
padding: 0.5rem 0.65rem;
background: rgba(0, 0, 0, 0.08);
}
html[data-theme="light"] .cluster-addon-card__values-details {
background: rgba(15, 23, 42, 0.03);
}
.cluster-addon-card__values-summary {
cursor: pointer;
font-weight: 600;
font-size: 0.88rem;
list-style-position: outside;
padding: 0.15rem 0;
}
.cluster-addon-card__values-hint {
margin: 0.5rem 0 0.45rem;
font-size: 0.78rem;
line-height: 1.45;
}
.cluster-addon-card__values-subhead {
margin: 0.65rem 0 0.35rem;
font-size: 0.8rem;
font-weight: 700;
color: var(--text);
}
.cluster-addon-card__values-details .cluster-addon-card__values-subhead:first-of-type {
margin-top: 0.35rem;
}
.cluster-addon-card__values-textarea {
display: block;
width: 100%;
box-sizing: border-box;
margin: 0;
min-height: 6rem;
padding: 0.5rem 0.6rem;
font-size: 0.78rem;
line-height: 1.4;
border-radius: 6px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.18);
color: inherit;
resize: vertical;
}
html[data-theme="light"] .cluster-addon-card__values-textarea {
background: rgba(255, 255, 255, 0.85);
}
.cluster-addon-card__desc {
margin: 0 0 0.75rem;
font-size: 0.85rem;
line-height: 1.45;
}
.cluster-addon-card__actions {
.cluster-addon-card__actions--equal {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
margin-top: 0.85rem;
gap: 0.5rem;
align-items: stretch;
}
.cluster-addon-card__actions--equal .btn-addon-install,
.cluster-addon-card__actions--equal .btn-addon-remove {
flex: 1 1 0;
min-width: 0;
min-height: 2.65rem;
margin-top: 0;
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
}
.cluster-addon-card--wide {
grid-column: 1 / -1;
grid-column: 1;
}
.cluster-addon-istio-grid {
margin-top: 0.25rem;
}
.cluster-addons-log-card {
/* Карточка хода Helm на странице аддонов (разметка как у create-progress-wrap + job-log-panel) */
.cluster-addons-helm-progress {
margin-bottom: 1.5rem;
}
.cluster-addons-log-pre {
.cluster-addons-helm-progress .job-log-panel {
max-height: min(55vh, 420px);
}
.cluster-addons-bootstrap-msg {
margin: 0.5rem 0 0;
max-height: min(50vh, 22rem);
overflow: auto;
padding: 0.65rem 0.75rem;
font-size: 0.78rem;
line-height: 1.4;
white-space: pre-wrap;
word-break: break-word;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(0, 0, 0, 0.12);
}
html[data-theme="light"] .cluster-addons-log-pre {
background: rgba(15, 23, 42, 0.04);
}
.cluster-addons-busy-overlay {
z-index: 9995;
}
body.cluster-addons-busy {
overflow: hidden;
font-size: 0.88rem;
line-height: 1.45;
}
/* Версии чартов на странице аддонов */
@@ -2930,8 +3135,58 @@ html[data-theme="light"] .journal-details-cell {
border: 1px solid var(--border);
}
.journal-page-size-hint {
/* Три сегмента на странице журнала — шире блок переключателя */
.journal-toolbar-card .cluster-edit-segmented {
max-width: 100%;
flex-wrap: wrap;
}
@media (min-width: 960px) {
.journal-toolbar-card .cluster-edit-segmented {
flex-wrap: nowrap;
max-width: 56rem;
}
}
.journal-view-fieldset {
margin-bottom: 0.25rem;
}
.journal-cluster-picker {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.journal-cluster-picker.hidden {
display: none;
}
.journal-cluster-picker-label {
display: block;
font-size: 0.88rem;
font-weight: 600;
margin-bottom: 0.35rem;
}
.journal-cluster-select {
width: 100%;
max-width: 24rem;
padding: 0.45rem 0.65rem;
font-size: 0.9rem;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
}
.journal-cluster-picker-hint {
margin: 0.45rem 0 0;
font-size: 0.84rem;
max-width: 40rem;
}
.journal-toolbar-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem 1rem;
margin-top: 0.65rem;
}
.journal-cell-kind {
word-break: break-word;
max-width: 12rem;
}
/* Пагинация журнала */
@@ -3000,12 +3255,6 @@ html[data-theme="light"] .journal-details-cell {
font-size: 0.9rem;
user-select: none;
}
.journal-pagination-summary {
width: 100%;
text-align: center;
margin: 0.85rem 0 0;
font-size: 0.84rem;
}
@media (max-width: 640px) {
.journal-pagination-inner {
flex-direction: column;