Подробные комментарии ко всем JS-файлам фронтенда
This commit is contained in:
+76
-12
@@ -1,13 +1,28 @@
|
||||
"""
|
||||
CRUD для таблицы scenario_definitions.
|
||||
CRUD для таблицы scenario_definitions — определения сценариев.
|
||||
|
||||
Сценарии редактируются через UI (модальный редактор), хранятся в БД.
|
||||
Это позволяет менять сценарии БЕЗ редеплоя приложения.
|
||||
|
||||
ОПТИМИСТИЧНАЯ БЛОКИРОВКА (version):
|
||||
update_definition проверяет version — если другой пользователь уже изменил
|
||||
сценарий, возвращает conflict=true → UI показывает "Конфликт версий".
|
||||
|
||||
МЯГКОЕ УДАЛЕНИЕ:
|
||||
delete_definition ставит is_active=FALSE — не удаляет физически.
|
||||
Это позволяет восстановить случайно удалённый сценарий.
|
||||
|
||||
SEED-СЦЕНАРИИ:
|
||||
Сценарии с client_id="" и stand="" — seed (дефолтные, из YAML).
|
||||
Они доступны всем пользователям но не могут быть удалены через UI.
|
||||
|
||||
Функции:
|
||||
list_definitions(client_id, stand) — список активных
|
||||
get_definition(def_id, cid, stand) — один
|
||||
create_definition(cid, stand, name, steps, updated_by) → id
|
||||
update_definition(def_id, cid, stand, name, steps, version, updated_by) → ok|conflict
|
||||
delete_definition(def_id, cid, stand) — мягкое (is_active=false)
|
||||
lock_check(cid, stand) — есть ли RUNNING запуск → 409 если да
|
||||
list_definitions(client_id, stand) — список активных (+seed)
|
||||
get_definition(def_id, cid, stand) — один (по id)
|
||||
create_definition(...) → {id, version}
|
||||
update_definition(...) → {ok, version} | {conflict: true}
|
||||
delete_definition(...) → bool
|
||||
lock_check(cid, stand) — есть ли RUNNING → False
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -15,11 +30,20 @@ from db.pool import get_conn, put_conn
|
||||
|
||||
|
||||
def list_definitions(client_id, stand):
|
||||
"""Список ВСЕХ активных определений: пользовательские + seed.
|
||||
|
||||
Seed-сценарии (client_id="" AND stand="") видны всем.
|
||||
Пользовательские — только для текущего пользователя и стенда.
|
||||
|
||||
Returns:
|
||||
list[dict] с ключами: id, name, steps, version, is_active,
|
||||
created_at, updated_at, client_id, stand, is_seed (bool)."""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return []
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
# Два условия через OR: пользовательские + seed
|
||||
cur.execute("""
|
||||
SELECT id, name, steps, version, is_active, created_at, updated_at,
|
||||
client_id, stand
|
||||
@@ -33,8 +57,10 @@ def list_definitions(client_id, stand):
|
||||
result = []
|
||||
for r in rows:
|
||||
d = dict(zip(cols, r))
|
||||
# Конвертируем datetime → ISO-строка (JSON-совместимо)
|
||||
d["created_at"] = d["created_at"].isoformat() if d["created_at"] else None
|
||||
d["updated_at"] = d["updated_at"].isoformat() if d["updated_at"] else None
|
||||
# is_seed: client_id пустой → seed (из YAML)
|
||||
d["is_seed"] = (d.get("client_id") == "" and d.get("stand") == "")
|
||||
result.append(d)
|
||||
return result
|
||||
@@ -46,6 +72,12 @@ def list_definitions(client_id, stand):
|
||||
|
||||
|
||||
def get_definition(def_id, client_id, stand):
|
||||
"""Получить ОДНО определение по id.
|
||||
|
||||
Доступ: пользовательские (client_id+stand) ИЛИ seed (пустые).
|
||||
|
||||
Returns:
|
||||
dict или None если не найдено."""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return None
|
||||
@@ -72,6 +104,16 @@ def get_definition(def_id, client_id, stand):
|
||||
|
||||
|
||||
def create_definition(client_id, stand, name, steps, updated_by=""):
|
||||
"""Создать ИЛИ перезаписать определение (upsert).
|
||||
|
||||
ON CONFLICT (client_id, stand, LOWER(name)):
|
||||
Если сценарий с таким именем уже существует → UPDATE (перезапись steps, version+1).
|
||||
Если нет → INSERT.
|
||||
|
||||
Это позволяет «сохранить» без проверки существования.
|
||||
|
||||
Returns:
|
||||
{id: int, version: int} или None при ошибке."""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return None
|
||||
@@ -98,7 +140,15 @@ def create_definition(client_id, stand, name, steps, updated_by=""):
|
||||
|
||||
|
||||
def update_definition(def_id, client_id, stand, name, steps, version, updated_by=""):
|
||||
"""Возвращает dict {ok, version} или {conflict: True}."""
|
||||
"""Обновить определение с ОПТИМИСТИЧНОЙ БЛОКИРОВКОЙ.
|
||||
|
||||
WHERE version = %s — если версия изменилась (другой пользователь/вкладка),
|
||||
UPDATE затронет 0 строк → возвращаем {conflict: true}.
|
||||
|
||||
Returns:
|
||||
{ok: True, version: int} — успех
|
||||
{conflict: True} — версия устарела (409 Conflict)
|
||||
{error: str} — ошибка БД"""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return {"error": "no db"}
|
||||
@@ -116,6 +166,7 @@ def update_definition(def_id, client_id, stand, name, steps, version, updated_by
|
||||
cur.close()
|
||||
if row:
|
||||
return {"ok": True, "version": row[0]}
|
||||
# 0 строк — версия не совпала (кто-то уже изменил)
|
||||
return {"conflict": True}
|
||||
except Exception as e:
|
||||
print(f"[DEFS] update error: {e}", flush=True)
|
||||
@@ -126,7 +177,13 @@ def update_definition(def_id, client_id, stand, name, steps, version, updated_by
|
||||
|
||||
|
||||
def delete_definition(def_id, client_id, stand):
|
||||
"""Мягкое удаление."""
|
||||
"""Мягкое удаление: is_active = FALSE.
|
||||
|
||||
Только для пользовательских сценариев (client_id не пустой).
|
||||
Seed-сценарии не могут быть удалены через этот метод.
|
||||
|
||||
Returns:
|
||||
bool — True если удалён, False если не найден."""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return False
|
||||
@@ -150,10 +207,17 @@ def delete_definition(def_id, client_id, stand):
|
||||
|
||||
|
||||
def lock_check(client_id, stand):
|
||||
"""Проверить нет ли активного RUNNING запуска. True = можно запускать."""
|
||||
"""Проверить что нет активного RUNNING-запуска сценария.
|
||||
|
||||
Используется перед запуском нового сценария — предотвращает
|
||||
одновременный запуск двух сценариев одним пользователем.
|
||||
|
||||
Returns:
|
||||
True — можно запускать (нет RUNNING)
|
||||
False — нельзя (уже есть RUNNING) → 409 Conflict"""
|
||||
conn = get_conn()
|
||||
if not conn:
|
||||
return True # без БД — разрешаем
|
||||
return True # без БД — разрешаем (fallback)
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
@@ -163,7 +227,7 @@ def lock_check(client_id, stand):
|
||||
""", (client_id, stand))
|
||||
row = cur.fetchone()
|
||||
cur.close()
|
||||
return row is None
|
||||
return row is None # None = нет RUNNING = можно запускать
|
||||
except Exception as e:
|
||||
print(f"[DEFS] lock_check error: {e}", flush=True)
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user