v0.5.1: ссылки на стенды на главной + в Swagger описании
This commit is contained in:
@@ -80,7 +80,7 @@ SERVICES = _DF["SERVICES"]
|
|||||||
OPS_INDEX = _DF["OPS_INDEX"]
|
OPS_INDEX = _DF["OPS_INDEX"]
|
||||||
|
|
||||||
DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1"))
|
DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1"))
|
||||||
VERSION = "0.5.0"
|
VERSION = "0.5.1"
|
||||||
|
|
||||||
|
|
||||||
def get_services(stand_id):
|
def get_services(stand_id):
|
||||||
|
|||||||
@@ -60,10 +60,16 @@ def _build_spec():
|
|||||||
"Polygon полностью повторяет контракты реального API: сервисы, инстансы, "
|
"Polygon полностью повторяет контракты реального API: сервисы, инстансы, "
|
||||||
"операции, параметры, валидацию — но работает **без реальной инфраструктуры**, "
|
"операции, параметры, валидацию — но работает **без реальной инфраструктуры**, "
|
||||||
"в памяти, с мгновенным откликом.\n\n"
|
"в памяти, с мгновенным откликом.\n\n"
|
||||||
|
"### Стенды\n"
|
||||||
|
"**3 изолированных стенда** — переключайте в выпадающем списке серверов выше:\n"
|
||||||
|
"- **dev** — 37 сервисов (разработка)\n"
|
||||||
|
"- **test** — 37 сервисов (тестирование)\n"
|
||||||
|
"- **prod** — 35 сервисов (продуктив)\n"
|
||||||
|
"У каждого стенда **свои инстансы, свои операции, своё состояние**.\n\n"
|
||||||
"### Особенности\n"
|
"### Особенности\n"
|
||||||
"- Все операции синхронные (настраиваемая задержка через `/_mock/delay`)\n"
|
"- Все операции синхронные (настраиваемая задержка через `/_mock/delay`)\n"
|
||||||
"- Состояние в памяти (1 gunicorn-воркер)\n"
|
"- Состояние в памяти (1 gunicorn-воркер)\n"
|
||||||
"- Конфигурация сервисов из YAML (генерируется из STANDS)\n"
|
"- Конфигурация сервисов из YAML (генерируется из terraform)\n"
|
||||||
"- Управляемый сброс через `/_mock/reset`\n"
|
"- Управляемый сброс через `/_mock/reset`\n"
|
||||||
"- Симуляция ошибок через `/_mock/fail-next`\n\n"
|
"- Симуляция ошибок через `/_mock/fail-next`\n\n"
|
||||||
"### Авторизация\n"
|
"### Авторизация\n"
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ def index():
|
|||||||
svc_count = len(_cfg.SERVICES)
|
svc_count = len(_cfg.SERVICES)
|
||||||
inst_count = len(state.instances)
|
inst_count = len(state.instances)
|
||||||
|
|
||||||
|
# Список стендов
|
||||||
|
stands_list = []
|
||||||
|
for sid in _cfg.list_stands():
|
||||||
|
svc = _cfg.get_services(sid)
|
||||||
|
stands_list.append({
|
||||||
|
"id": sid,
|
||||||
|
"count": len(svc),
|
||||||
|
})
|
||||||
|
current_stand = g.stand_id
|
||||||
|
|
||||||
# Список сервисов для таблицы: name, id, кол-во операций
|
# Список сервисов для таблицы: name, id, кол-во операций
|
||||||
svc_list = []
|
svc_list = []
|
||||||
for sid, svc in sorted(_cfg.SERVICES.items(), key=lambda x: x[1].get("name", x[0])):
|
for sid, svc in sorted(_cfg.SERVICES.items(), key=lambda x: x[1].get("name", x[0])):
|
||||||
@@ -69,6 +79,8 @@ def index():
|
|||||||
inst_count=inst_count,
|
inst_count=inst_count,
|
||||||
delay=_cfg.DELAY,
|
delay=_cfg.DELAY,
|
||||||
svc_list=svc_list,
|
svc_list=svc_list,
|
||||||
|
stands_list=stands_list,
|
||||||
|
current_stand=current_stand,
|
||||||
endpoint=_POLYGON_ENDPOINT,
|
endpoint=_POLYGON_ENDPOINT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,66 @@ main {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Stands cards ── */
|
||||||
|
.card-stands .card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stands-grid {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-card {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 16px 12px;
|
||||||
|
background: var(--brand-grey-light);
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--text);
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-card:hover {
|
||||||
|
border-color: var(--brand-primary);
|
||||||
|
background: #eff6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-active {
|
||||||
|
border-color: var(--brand-primary);
|
||||||
|
background: #eff6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--brand-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-count {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-arrow {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--brand-primary);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stand-card:hover .stand-arrow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Dots ── */
|
/* ── Dots ── */
|
||||||
.dot {
|
.dot {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -30,6 +30,25 @@
|
|||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
|
<!-- ── Стенды ── -->
|
||||||
|
{% if stands_list|length > 1 %}
|
||||||
|
<section class="card card-stands">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>🖥 Стенды</h2>
|
||||||
|
<span class="muted">Вы находитесь на стенде <strong>{{ current_stand }}</strong></span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body stands-grid">
|
||||||
|
{% for s in stands_list %}
|
||||||
|
<a href="/{{ s.id }}/" class="stand-card {% if s.id == current_stand %}stand-active{% endif %}">
|
||||||
|
<span class="stand-name">{{ s.id }}</span>
|
||||||
|
<span class="stand-count">{{ s.count }} сервисов</span>
|
||||||
|
<span class="stand-arrow">→</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- ── Что такое Polygon ── -->
|
<!-- ── Что такое Polygon ── -->
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|||||||
Reference in New Issue
Block a user