UI: карточка установленных аддонов на странице кластера; API аддонов и правки стилей

- Отдельная section.card после сводки ресурсов узлов, выравнивание бейджа Helm с заголовком
- Расширение эндпоинтов аддонов, схемы, helm_addons, cluster_addons.js/html
- Обновление api_routes.md
This commit is contained in:
Sergey Antropoff
2026-04-04 14:13:01 +03:00
parent eb063aec20
commit d55e69c756
9 changed files with 1238 additions and 229 deletions
+174 -126
View File
@@ -18,7 +18,7 @@
{% endblock %}
{% block content %}
{# Полноэкранный спиннер до загрузки списка кластеров, статуса и версий чартов; скрывается в cluster_addons.js #}
{# Полноэкранный спиннер до списка кластеров и статуса; версии чартов подгружаются после (helm repo update может быть долгим). #}
<div
id="addons-page-loading-overlay"
class="page-loading-overlay"
@@ -30,7 +30,7 @@
<div class="page-loading-backdrop" aria-hidden="true"></div>
<div class="page-loading-center">
<span class="spinner page-loading-spinner" aria-hidden="true"></span>
<span class="page-loading-label">Загрузка списка кластеров и версий чартов</span>
<span class="page-loading-label">Загрузка списка кластеров…</span>
</div>
</div>
@@ -68,26 +68,31 @@
</header>
<p class="muted cluster-addon-card__desc">Контроллер Ingress.</p>
<div class="create-form-field">
<label for="addons-ing-version-select">Версия чарта</label>
<select id="addons-ing-version-select" class="cluster-addons-version-select" aria-label="Версия чарта ingress-nginx">
<option value="">Последняя (из репозитория)</option>
</select>
<span class="cluster-addon-card__field-label" id="addons-ing-version-label">Версия чарта</span>
<div class="cluster-addon-version-row" role="group" aria-labelledby="addons-ing-version-label">
<select id="addons-ing-version-select" class="cluster-addons-version-select" aria-label="Версия чарта ingress-nginx">
<option value="">Последняя (из репозитория)</option>
</select>
<button type="button" class="btn-secondary btn-addon-load-values" data-addon="ingress-nginx">Загрузить values</button>
</div>
</div>
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Содержимое из <code>helm show values</code> плюс сервис для kind; подставляется при смене версии чарта. После <code>-f</code> Helm применяет <code>--set</code> для NodePort.
</p>
<label for="addons-values-yaml-ingress-nginx" class="sr-only">Полные YAML values для ingress-nginx</label>
<textarea
id="addons-values-yaml-ingress-nginx"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта ingress-nginx"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<div id="addons-values-panel-ingress-nginx" class="cluster-addon-card__values-panel hidden" hidden aria-hidden="true">
<details class="cluster-addon-card__values-details" open>
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Содержимое из <code>helm show values</code> плюс сервис для kind. После <code>-f</code> Helm применяет <code>--set</code> для NodePort. Нажмите «Загрузить values» для выбранной версии.
</p>
<label for="addons-values-yaml-ingress-nginx" class="sr-only">Полные YAML values для ingress-nginx</label>
<textarea
id="addons-values-yaml-ingress-nginx"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта ingress-nginx"
></textarea>
</details>
</div>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--inline">
<button type="button" class="btn-addon-install" data-endpoint="ingress-nginx">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="ingress-nginx" hidden>Удалить</button>
</div>
@@ -108,26 +113,35 @@
<input id="addons-grafana-pass" type="password" minlength="8" maxlength="256" autocomplete="new-password" placeholder="не менее 8 символов" />
</div>
<div class="create-form-field">
<label for="addons-prom-version-select">Версия чарта</label>
<select id="addons-prom-version-select" class="cluster-addons-version-select">
<option value="">Последняя (из репозитория)</option>
</select>
<span class="cluster-addon-card__field-label" id="addons-prom-version-label">Версия чарта</span>
<div class="cluster-addon-version-row" role="group" aria-labelledby="addons-prom-version-label">
<select
id="addons-prom-version-select"
class="cluster-addons-version-select"
aria-labelledby="addons-prom-version-label"
>
<option value="">Последняя (из репозитория)</option>
</select>
<button type="button" class="btn-secondary btn-addon-load-values" data-addon="kube-prometheus-stack">Загрузить values</button>
</div>
</div>
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Вывод <code>helm show values</code> с подставленными логином и паролем Grafana из полей выше; обновляется при смене версии или учётных данных. Пустое поле при установке — сервер соберёт values сам.
</p>
<label for="addons-values-yaml-kube-prometheus-stack" class="sr-only">Полные YAML values для kube-prometheus-stack</label>
<textarea
id="addons-values-yaml-kube-prometheus-stack"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта kube-prometheus-stack"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<div id="addons-values-panel-kube-prometheus-stack" class="cluster-addon-card__values-panel hidden" hidden aria-hidden="true">
<details class="cluster-addon-card__values-details" open>
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Вывод <code>helm show values</code> с подстановкой логина и пароля Grafana из полей выше на момент нажатия «Загрузить values». Пустой textarea при установке — сервер соберёт values сам.
</p>
<label for="addons-values-yaml-kube-prometheus-stack" class="sr-only">Полные YAML values для kube-prometheus-stack</label>
<textarea
id="addons-values-yaml-kube-prometheus-stack"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта kube-prometheus-stack"
></textarea>
</details>
</div>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--inline">
<button type="button" class="btn-addon-install" data-endpoint="kube-prometheus-stack">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="kube-prometheus-stack" hidden>Удалить</button>
</div>
@@ -140,26 +154,35 @@
</header>
<p class="muted cluster-addon-card__desc">Метрики узлов и подов для <code>kubectl top</code>; для kind включён <code>--kubelet-insecure-tls</code>.</p>
<div class="create-form-field">
<label for="addons-ms-version-select">Версия чарта</label>
<select id="addons-ms-version-select" class="cluster-addons-version-select">
<option value="">Последняя (из репозитория)</option>
</select>
<span class="cluster-addon-card__field-label" id="addons-ms-version-label">Версия чарта</span>
<div class="cluster-addon-version-row" role="group" aria-labelledby="addons-ms-version-label">
<select
id="addons-ms-version-select"
class="cluster-addons-version-select"
aria-labelledby="addons-ms-version-label"
>
<option value="">Последняя (из репозитория)</option>
</select>
<button type="button" class="btn-secondary btn-addon-load-values" data-addon="metrics-server">Загрузить values</button>
</div>
</div>
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
<code>helm show values</code> плюс аргументы для kind (<code>--kubelet-insecure-tls</code> и т.д.). Пустое поле — автосборка на сервере.
</p>
<label for="addons-values-yaml-metrics-server" class="sr-only">Полные YAML values для metrics-server</label>
<textarea
id="addons-values-yaml-metrics-server"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта metrics-server"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<div id="addons-values-panel-metrics-server" class="cluster-addon-card__values-panel hidden" hidden aria-hidden="true">
<details class="cluster-addon-card__values-details" open>
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
<code>helm show values</code> плюс аргументы для kind (<code>--kubelet-insecure-tls</code> и т.д.). Пустое поле при установке — автосборка на сервере.
</p>
<label for="addons-values-yaml-metrics-server" class="sr-only">Полные YAML values для metrics-server</label>
<textarea
id="addons-values-yaml-metrics-server"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта metrics-server"
></textarea>
</details>
</div>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--inline">
<button type="button" class="btn-addon-install" data-endpoint="metrics-server">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="metrics-server" hidden>Удалить</button>
</div>
@@ -195,41 +218,49 @@
<option value="">Последняя (из репозитория)</option>
</select>
</div>
<div class="create-form-field cluster-addon-istio-load-field">
<span class="cluster-addon-card__field-label" id="addons-istio-values-label">Предпросмотр YAML</span>
<div class="cluster-addon-version-row" role="group" aria-labelledby="addons-istio-values-label">
<button type="button" class="btn-secondary btn-addon-load-values" data-addon="istio-kiali">Загрузить values</button>
</div>
</div>
</div>
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чартов Istio и Kiali (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Три блока из <code>helm show values</code> для выбранных версий. Логин и пароль Kiali вносятся в секрет Kubernetes отдельно; для kiali-server дополнительно задаётся <code>auth.strategy=login</code> через <code>--set</code>.
</p>
<p class="cluster-addon-card__values-subhead">kiali-server</p>
<label for="addons-values-yaml-istio-kiali" class="sr-only">YAML values kiali-server</label>
<textarea
id="addons-values-yaml-istio-kiali"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта kiali-server"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/base</p>
<label for="addons-values-yaml-istio-base" class="sr-only">YAML values istio-base</label>
<textarea
id="addons-values-yaml-istio-base"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/base"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/istiod</p>
<label for="addons-values-yaml-istio-istiod" class="sr-only">YAML values istiod</label>
<textarea
id="addons-values-yaml-istio-istiod"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/istiod"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<div id="addons-values-panel-istio-kiali" class="cluster-addon-card__values-panel hidden" hidden aria-hidden="true">
<details class="cluster-addon-card__values-details" open>
<summary class="cluster-addon-card__values-summary">Values чартов Istio и Kiali (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Три блока из <code>helm show values</code> для выбранных версий Istio и Kiali. Логин и пароль Kiali задаются в секрете при установке; здесь — только шаблон values чартов.
</p>
<p class="cluster-addon-card__values-subhead">kiali-server</p>
<label for="addons-values-yaml-istio-kiali" class="sr-only">YAML values kiali-server</label>
<textarea
id="addons-values-yaml-istio-kiali"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта kiali-server"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/base</p>
<label for="addons-values-yaml-istio-base" class="sr-only">YAML values istio-base</label>
<textarea
id="addons-values-yaml-istio-base"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/base"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/istiod</p>
<label for="addons-values-yaml-istio-istiod" class="sr-only">YAML values istiod</label>
<textarea
id="addons-values-yaml-istio-istiod"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/istiod"
></textarea>
</details>
</div>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--inline">
<button type="button" class="btn-addon-install" data-endpoint="istio-kiali">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="istio-kiali" hidden>Удалить</button>
</div>
@@ -237,40 +268,57 @@
</div>
</div>
{# Журнал операции Helm: те же блоки, что на странице создания кластера (прогресс + job-log-panel). Без полноэкранного спиннера. #}
<section
id="addons-helm-progress-wrap"
class="card create-progress-wrap cluster-addons-helm-progress hidden"
aria-hidden="true"
aria-labelledby="addons-helm-progress-title"
>
<h2 class="create-cluster-card__title" id="addons-helm-progress-title">Ход операции Helm</h2>
<p class="create-progress-hint muted" id="addons-helm-progress-hint">
Выполняется команда в контейнере веб-приложения; полный вывод появится по завершении.
</p>
<div
class="progress-track"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
aria-labelledby="addons-helm-progress-label"
id="addons-helm-progress-track"
{# Ход Helm: секция в dock; при установке/удалении переносится внутрь карточки аддона (cluster_addons.js). #}
<div id="addons-helm-progress-dock" class="cluster-addons-helm-dock" aria-hidden="true">
<section
id="addons-helm-progress-wrap"
class="card create-progress-wrap cluster-addons-helm-progress hidden"
aria-hidden="true"
aria-labelledby="addons-helm-progress-title"
>
<div class="progress-bar" id="addons-helm-progress-bar" style="width: 0%"></div>
</div>
<p class="progress-label" id="addons-helm-progress-label"></p>
<div class="job-log-panel-wrap">
<label for="addons-helm-log-panel" class="job-log-label muted">Журнал установки / удаления</label>
<pre
id="addons-helm-log-panel"
class="mono job-log-panel"
role="log"
aria-live="polite"
aria-relevant="additions"
></pre>
</div>
</section>
<h2 class="create-cluster-card__title" id="addons-helm-progress-title">Ход операции Helm</h2>
<p class="create-progress-hint muted" id="addons-helm-progress-hint">
Выполняется команда в контейнере веб-приложения; полный вывод появится по завершении.
</p>
<div
class="progress-track"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
aria-labelledby="addons-helm-progress-label"
id="addons-helm-progress-track"
>
<div class="progress-bar" id="addons-helm-progress-bar" style="width: 0%"></div>
</div>
<p class="progress-label" id="addons-helm-progress-label"></p>
<div class="job-log-panel-wrap">
<label for="addons-helm-log-panel" class="job-log-label muted">Журнал установки / удаления</label>
<pre
id="addons-helm-log-panel"
class="mono job-log-panel"
role="log"
aria-live="polite"
aria-relevant="additions"
></pre>
</div>
</section>
</div>
{# Если внешний cluster_addons.js не выполнился (404, ошибка синтаксиса), оверлей снимается через 50 с. #}
<script>
(function () {
var ms = 50000;
setTimeout(function () {
var el = document.getElementById("addons-page-loading-overlay");
if (!el || el.classList.contains("hidden")) return;
el.classList.add("hidden");
el.setAttribute("aria-busy", "false");
el.setAttribute("aria-hidden", "true");
document.body.classList.remove("cluster-addons-page-loading");
}, ms);
})();
</script>
{% include "partials/dashboard_modals.html" %}
{% endblock %}