v1.0.66: backend status resolver for operations
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Архитектура app-autotest — полный документ
|
# Архитектура app-autotest — полный документ
|
||||||
|
|
||||||
v1.0.65, 27.07.2026
|
v1.0.66, 27.07.2026
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# История разработки app-autotest
|
# История разработки app-autotest
|
||||||
|
|
||||||
|
# v1.0.66 (27.07.2026) — backend status resolver for operations
|
||||||
|
|
||||||
|
### Что изменилось
|
||||||
|
- В `site/routes/main.py` добавлен канонический резолвер статуса инстанса для `/api/operations/<svc_id>`.
|
||||||
|
- Backend теперь отдаёт `status` для инстансов, а UI читает именно его вместо угадывания по `explainedStatus`.
|
||||||
|
- В `site/templates/index.html` убрано раннее отображение «Готово» во время выполнения операции.
|
||||||
|
|
||||||
|
### Что это чинит
|
||||||
|
- Путаницу между `creating`, `running` и фактическим статусом в UI.
|
||||||
|
- Ситуацию, когда фронтенд сам интерпретировал статусы и показывал не то состояние.
|
||||||
|
|
||||||
## v1.0.65 (27.07.2026) — cloud list pagination fix
|
## v1.0.65 (27.07.2026) — cloud list pagination fix
|
||||||
|
|
||||||
### Что изменилось
|
### Что изменилось
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ from routes.main import bp as main_bp
|
|||||||
from routes.api import bp as api_bp
|
from routes.api import bp as api_bp
|
||||||
from routes.api_test import bp as api_test_bp
|
from routes.api_test import bp as api_test_bp
|
||||||
|
|
||||||
VERSION = "1.0.65"
|
VERSION = "1.0.66"
|
||||||
|
|
||||||
app = Flask(__name__, template_folder="templates", static_folder="static")
|
app = Flask(__name__, template_folder="templates", static_folder="static")
|
||||||
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc")
|
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc")
|
||||||
|
|||||||
+29
-5
@@ -10,6 +10,21 @@ bp = Blueprint("main", __name__)
|
|||||||
AUTOTEST_PREFIX = "autotest-"
|
AUTOTEST_PREFIX = "autotest-"
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_instance_status(instance, tracked=None):
|
||||||
|
"""Вернуть канонический статус инстанса для API и UI."""
|
||||||
|
tracked = tracked or {}
|
||||||
|
cloud_status = str(instance.get("explainedStatus") or "").strip()
|
||||||
|
display_name = str(instance.get("displayName") or "")
|
||||||
|
|
||||||
|
if cloud_status:
|
||||||
|
return cloud_status
|
||||||
|
|
||||||
|
if tracked and display_name.startswith(AUTOTEST_PREFIX):
|
||||||
|
return "creating"
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
def _mask(s):
|
def _mask(s):
|
||||||
if not s or len(s) < 8:
|
if not s or len(s) < 8:
|
||||||
return ""
|
return ""
|
||||||
@@ -143,10 +158,18 @@ def api_operations(svc_id):
|
|||||||
tracked_uids = set(tracked_by_uid.keys())
|
tracked_uids = set(tracked_by_uid.keys())
|
||||||
instances = get_instances(client)
|
instances = get_instances(client)
|
||||||
nubes_uids = {i["instanceUid"] for i in instances}
|
nubes_uids = {i["instanceUid"] for i in instances}
|
||||||
svc_instances = [i for i in instances
|
svc_instances = []
|
||||||
if i.get("instanceUid") in tracked_uids
|
for i in instances:
|
||||||
and str(i.get("displayName", "")).startswith(AUTOTEST_PREFIX)
|
uid = i.get("instanceUid")
|
||||||
and i.get("explainedStatus") not in ("deleted",)]
|
if uid not in tracked_uids:
|
||||||
|
continue
|
||||||
|
if not str(i.get("displayName", "")).startswith(AUTOTEST_PREFIX):
|
||||||
|
continue
|
||||||
|
if i.get("explainedStatus") in ("deleted",):
|
||||||
|
continue
|
||||||
|
item = dict(i)
|
||||||
|
item["status"] = _resolve_instance_status(item, tracked_by_uid.get(uid))
|
||||||
|
svc_instances.append(item)
|
||||||
# Если Nubes уже не отдаёт tracked-инстанс после reload, добавляем его из трекера.
|
# Если Nubes уже не отдаёт tracked-инстанс после reload, добавляем его из трекера.
|
||||||
for uid, t in tracked_by_uid.items():
|
for uid, t in tracked_by_uid.items():
|
||||||
if uid not in nubes_uids:
|
if uid not in nubes_uids:
|
||||||
@@ -155,7 +178,8 @@ def api_operations(svc_id):
|
|||||||
"displayName": t["displayName"],
|
"displayName": t["displayName"],
|
||||||
"serviceId": svc_id,
|
"serviceId": svc_id,
|
||||||
"svc": detail.get("svc", ""),
|
"svc": detail.get("svc", ""),
|
||||||
"explainedStatus": "creating",
|
"explainedStatus": "",
|
||||||
|
"status": "creating",
|
||||||
})
|
})
|
||||||
return jsonify({"svc": detail.get("svc", ""), "operations": ops, "instances": svc_instances})
|
return jsonify({"svc": detail.get("svc", ""), "operations": ops, "instances": svc_instances})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -114,10 +114,11 @@ async function selectService(svcId){
|
|||||||
|
|
||||||
let html='';
|
let html='';
|
||||||
svcInstances.forEach(i=>{
|
svcInstances.forEach(i=>{
|
||||||
const sc=i.explainedStatus==='running'?'badge-success':'';
|
const status=i.status||i.explainedStatus||'?';
|
||||||
|
const sc=status==='running'?'badge-success':'';
|
||||||
html+=`<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
html+=`<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
||||||
<span style="flex:1;">${i.displayName}</span>
|
<span style="flex:1;">${i.displayName}</span>
|
||||||
<span class="badge ${sc}" style="font-size:9px;">${i.explainedStatus||'?'}</span>
|
<span class="badge ${sc}" style="font-size:9px;">${status}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
html+=`<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
html+=`<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
||||||
});
|
});
|
||||||
@@ -235,7 +236,7 @@ function setFinishedState(statusText, statusClass, statusError, statusDuration){
|
|||||||
function setRunningState(opName, displayName){
|
function setRunningState(opName, displayName){
|
||||||
const btn=document.getElementById('btn-test');
|
const btn=document.getElementById('btn-test');
|
||||||
const title=displayName || opName;
|
const title=displayName || opName;
|
||||||
btn.textContent='Готово';
|
btn.textContent=opName+'...';
|
||||||
document.getElementById('test-status').textContent=' ⏳ '+title+' выполняется...';
|
document.getElementById('test-status').textContent=' ⏳ '+title+' выполняется...';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,10 +308,11 @@ async function refreshInstances(){
|
|||||||
svcInstances=newInsts;
|
svcInstances=newInsts;
|
||||||
let html='';
|
let html='';
|
||||||
svcInstances.forEach(i=>{
|
svcInstances.forEach(i=>{
|
||||||
const sc=i.explainedStatus==='running'?'badge-success':'';
|
const status=i.status||i.explainedStatus||'?';
|
||||||
|
const sc=status==='running'?'badge-success':'';
|
||||||
html+=`<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
html+=`<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
||||||
<span style="flex:1;">${i.displayName}</span>
|
<span style="flex:1;">${i.displayName}</span>
|
||||||
<span class="badge ${sc}" style="font-size:9px;">${i.explainedStatus||'?'}</span>
|
<span class="badge ${sc}" style="font-size:9px;">${status}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
html+=`<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
html+=`<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user