{# Установка и удаление Helm-аддонов в выбранном кластере.
   Автор: Сергей Антропов — https://devops.org.ru #}
{% extends "base.html" %}

{% block page_title %}Аддоны кластера{% endblock %}

{% block body_extra_class %} cluster-addons-page-loading{% endblock %}

{% block body_attrs %}data-dashboard-mode="addons"{% endblock %}

{% block footer %}
<div class="footer-inner">
  <p class="footer-copyright">
    © {{ app_title }} ·
    <a href="https://devops.org.ru" target="_blank" rel="noopener">devops.org.ru</a>
  </p>
</div>
{% endblock %}

{% block content %}
{# Полноэкранный спиннер до списка кластеров и статуса; версии чартов подгружаются после (helm repo update может быть долгим). #}
<div
  id="addons-page-loading-overlay"
  class="page-loading-overlay"
  role="status"
  aria-live="polite"
  aria-busy="true"
  aria-label="Загрузка страницы аддонов"
>
  <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>
  </div>
</div>

<section class="card hero-panel cluster-create-hero" aria-labelledby="addons-hero-title">
  <h1 class="page-title" id="addons-hero-title">Дополнения кластера (Helm)</h1>
  <p class="muted page-lead">
    Выберите кластер с сохранённым kubeconfig. Установка и удаление выполняются через <code>helm</code> в контейнере веб-приложения;
    операции могут занимать несколько минут — ход и вывод команд отображаются в журнале ниже (как при развёртывании кластера). История операций сохраняется в каталоге кластера.
  </p>
</section>

<section class="card create-cluster-card cluster-addons-toolbar-card">
  <h2 class="create-cluster-card__title">Кластер</h2>
  <div class="cluster-addons-cluster-row">
    <label for="addons-cluster-select" class="cluster-addons-cluster-label">Выберите кластер для просмотра статуса аддонов.</label>
    <select id="addons-cluster-select" class="cluster-addons-cluster-select" aria-label="Выберите кластер для просмотра статуса аддонов">
      <option value="">— загрузка списка —</option>
    </select>
    <button type="button" class="btn-secondary" id="addons-refresh-status">Обновить статус</button>
  </div>
  <div id="addons-status-bar" class="cluster-addons-status-bar" role="status" aria-live="polite"></div>
  <p id="addons-bootstrap-msg" class="cluster-addons-bootstrap-msg muted hidden" role="status" aria-live="polite"></p>
</section>

<div
  id="addons-cards-wrap"
  class="cluster-addons-cards-wrap hidden"
  aria-hidden="true"
>
<div class="cluster-addons-grid">
  <section class="card cluster-addon-card" data-addon="ingress-nginx">
    <header class="cluster-addon-card__header">
      <h2 class="cluster-addon-card__title">ingress-nginx</h2>
      <span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
    </header>
    <p class="muted cluster-addon-card__desc">Контроллер Ingress.</p>
    <div class="create-form-field">
      <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>
    <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">
        <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>
  </section>

  <section class="card cluster-addon-card" data-addon="kube-prometheus-stack">
    <header class="cluster-addon-card__header">
      <h2 class="cluster-addon-card__title">kube-prometheus-stack</h2>
      <span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
    </header>
    <p class="muted cluster-addon-card__desc">Prometheus Operator, Alertmanager, Grafana.</p>
    <div class="create-form-field">
      <label for="addons-grafana-user">Логин администратора Grafana</label>
      <input id="addons-grafana-user" type="text" value="admin" maxlength="256" autocomplete="username" />
    </div>
    <div class="create-form-field">
      <label for="addons-grafana-pass">Пароль администратора Grafana</label>
      <input id="addons-grafana-pass" type="password" minlength="8" maxlength="256" autocomplete="new-password" placeholder="не менее 8 символов" />
    </div>
    <div class="create-form-field">
      <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>
    <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">
        <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>
  </section>

  <section class="card cluster-addon-card" data-addon="metrics-server">
    <header class="cluster-addon-card__header">
      <h2 class="cluster-addon-card__title">metrics-server</h2>
      <span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
    </header>
    <p class="muted cluster-addon-card__desc">Метрики узлов и подов для <code>kubectl top</code>; для kind включён <code>--kubelet-insecure-tls</code>.</p>
    <div class="create-form-field">
      <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>
    <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">
        <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>
  </section>

  <section class="card cluster-addon-card cluster-addon-card--wide" data-addon="istio-kiali">
    <header class="cluster-addon-card__header">
      <h2 class="cluster-addon-card__title">Istio + Kiali</h2>
      <span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
    </header>
    <p class="muted cluster-addon-card__desc">
      Чарты <code>istio/base</code>, <code>istio/istiod</code> и <code>kiali-server</code> в <code>istio-system</code>. Kiali по умолчанию —
      <strong>anonymous</strong> (без экрана входа; уместно для kind и <code>kubectl port-forward</code>). Для
      <strong>token</strong> / <strong>openid</strong> задайте <code>auth.strategy</code> в YAML values kiali-server.
    </p>
    <div class="create-form-grid cluster-addon-istio-grid">
      <div class="create-form-field">
        <label for="addons-istio-version-select">Версия чартов Istio (base + istiod)</label>
        <select id="addons-istio-version-select" class="cluster-addons-version-select">
          <option value="">Последняя (из репозитория)</option>
        </select>
      </div>
      <div class="create-form-field">
        <label for="addons-kiali-version-select">Версия чарта Kiali</label>
        <select id="addons-kiali-version-select" class="cluster-addons-version-select">
          <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>
    <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">
        <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. Секрет логина больше не создаётся; при необходимости настройте <code>auth</code> в блоке kiali-server.
        </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>
  </section>
</div>
</div>

{# Ход 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"
  >
    <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 %}

{% block scripts %}
<script src="/static/js/cluster_addons.js" defer></script>
{% endblock %}
