p3p pairs
This commit is contained in:
@@ -117,7 +117,7 @@ export default function App() {
|
||||
detailsPosition="right"
|
||||
details={['COE', 'P2P', 'P3P'].map((type) => {
|
||||
const typeStats = d.byType?.[type] ?? { completed: 0, total: 0 }
|
||||
return `${type}: ${typeStats.completed}/${typeStats.total}`
|
||||
return `${type}: ${typeStats.completed}/${typeStats.total} tests`
|
||||
})}
|
||||
/>
|
||||
<CompletionBar value={d.completionRate} />
|
||||
|
||||
@@ -196,7 +196,11 @@ export default function TestTable({ tests = [], allTests = [], isLoading }) {
|
||||
const pairs = parsePairArray(test.coe_pair)
|
||||
return pairs.length > 0 ? String(pairs.length) : null
|
||||
})()} colorClass="bg-cyan-900/50 text-cyan-300" />
|
||||
<TagPill label="File ID" value={test.test_id} />
|
||||
<TagPill label="P3P Pairs" value={(() => {
|
||||
const pairs = parsePairArray(test.p3p_pair)
|
||||
return pairs.length > 0 ? String(pairs.length) : null
|
||||
})()} colorClass="bg-orange-900/50 text-orange-300" />
|
||||
<TagPill label="Test ID" value={test.test_id} />
|
||||
<TagPill label="Type" value={test.interference} colorClass={TYPE_COLORS[test.interference]} />
|
||||
<TagPill label="Device" value={test.device} />
|
||||
<TagPill label="Rotation" value={test.rotation} />
|
||||
@@ -258,6 +262,94 @@ export default function TestTable({ tests = [], allTests = [], isLoading }) {
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={itemKey} className="border border-slate-700/70 rounded-md overflow-hidden">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => togglePairedExpand(test.id, pairKey)}
|
||||
className="w-full px-2.5 py-2 bg-slate-900/70 hover:bg-slate-800 transition-colors flex items-center justify-between gap-2 text-left"
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="text-xs text-slate-500 select-none">{open ? '▾' : '▸'}</span>
|
||||
<span className="text-xs text-slate-200 truncate">{pairTest.filename ?? pairKey}</span>
|
||||
</div>
|
||||
<StatusBadge completed={pairTest.completed} />
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
<div className="px-3 py-3 border-t border-slate-700/60 bg-slate-900/40">
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<TagPill label="File ID" value={pairTest.test_id} />
|
||||
<TagPill label="Type" value={pairTest.interference} colorClass={TYPE_COLORS[pairTest.interference]} />
|
||||
<TagPill label="Device" value={pairTest.device} />
|
||||
<TagPill label="Rotation" value={pairTest.rotation} />
|
||||
<TagPill label="Test Point" value={pairTest.test_point} />
|
||||
<TagPill label="RSSI" value={pairTest.rssi} />
|
||||
<TagPill label="Station" value={pairTest.station} />
|
||||
<TagPill label="Band" value={pairTest.band} />
|
||||
<TagPill label="Channel" value={pairTest.channel} />
|
||||
<TagPill label="Bandwidth" value={pairTest.bandwidth} />
|
||||
<TagPill label="Throttle" value={pairTest.throttled} />
|
||||
<TagPill label="Direction" value={pairTest.direction} />
|
||||
<TagPill label="Elapsed Time" value={fmtDuration(pairTest.duration_seconds)} />
|
||||
</div>
|
||||
{(() => {
|
||||
const rows = parseTputRows(pairTest.tput_results)
|
||||
if (!pairTest.completed || rows.length === 0) return null
|
||||
return (
|
||||
<div className="mt-3 pt-3 border-t border-slate-700/50">
|
||||
<table className="text-xs w-auto border-collapse">
|
||||
<thead>
|
||||
<tr className="text-slate-500 uppercase tracking-wide">
|
||||
<th className="pr-6 pb-1 text-left font-medium">Station</th>
|
||||
<th className="pr-6 pb-1 text-right font-medium">Throughput</th>
|
||||
<th className="pr-6 pb-1 text-right font-medium">DL RSSI</th>
|
||||
<th className="pb-1 text-right font-medium">UL RSSI</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map(r => (
|
||||
<tr key={`${pairTest.id}-${r.station}`} className="text-slate-300">
|
||||
<td className="pr-6 py-0.5 text-cyan-400 font-medium">STA{r.station}</td>
|
||||
<td className="pr-6 py-0.5 text-right">{r.tput} Mbps</td>
|
||||
<td className="pr-6 py-0.5 text-right">{r.dlRssi} dBm</td>
|
||||
<td className="py-0.5 text-right">{r.ulRssi} dBm</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
{(() => {
|
||||
const pairs = parsePairArray(test.p3p_pair)
|
||||
if (pairs.length === 0) return null
|
||||
return (
|
||||
<div className="mt-3 pt-3 border-t border-slate-700/50">
|
||||
<p className="text-[10px] uppercase tracking-wide text-slate-500 mb-2">Paired P3P Tests</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
{pairs.map(pairKey => {
|
||||
const pairTest = testsByLookupKey.get(pairKey)
|
||||
const itemKey = `${test.id}-${pairKey}`
|
||||
const open = pairedExpanded.has(`${test.id}::${pairKey}`)
|
||||
|
||||
if (!pairTest) {
|
||||
return (
|
||||
<div key={itemKey} className="text-xs font-medium px-2.5 py-2 rounded bg-slate-800 text-slate-400">
|
||||
{pairKey}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={itemKey} className="border border-slate-700/70 rounded-md overflow-hidden">
|
||||
<button
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -66,6 +66,7 @@ def _init_db():
|
||||
"tput_results TEXT",
|
||||
"throttled TEXT",
|
||||
"coe_pair TEXT",
|
||||
"p3p_pair TEXT",
|
||||
]:
|
||||
try:
|
||||
_conn.execute(f"ALTER TABLE tests ADD COLUMN {col_def}")
|
||||
@@ -152,6 +153,19 @@ def set_coe_pair(test_row_id, coe_pair):
|
||||
)
|
||||
|
||||
|
||||
def set_p3p_pair(test_row_id, p3p_pair):
|
||||
json_value = json.dumps(p3p_pair or [])
|
||||
with _tx():
|
||||
_conn.execute(
|
||||
"""
|
||||
UPDATE tests
|
||||
SET p3p_pair = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(json_value, test_row_id),
|
||||
)
|
||||
|
||||
|
||||
def get_station_for_test(test_id, device):
|
||||
with _lock:
|
||||
row = _conn.execute(
|
||||
|
||||
+62
-1
@@ -2,7 +2,14 @@ import os
|
||||
import re
|
||||
import smbclient
|
||||
|
||||
from db_py import clear_tests, get_all_tests, mark_completed, set_coe_pair, upsert_test
|
||||
from db_py import (
|
||||
clear_tests,
|
||||
get_all_tests,
|
||||
mark_completed,
|
||||
set_coe_pair,
|
||||
set_p3p_pair,
|
||||
upsert_test,
|
||||
)
|
||||
from parser import (
|
||||
parse_elapsed_time,
|
||||
parse_result_filename,
|
||||
@@ -111,6 +118,7 @@ def scan_results_only(results_dir, results_dir_ref=None):
|
||||
if results_dir_ref:
|
||||
scan_results(results_dir_ref)
|
||||
update_p2p_coe_pairs()
|
||||
update_p3p_throttle_pairs()
|
||||
|
||||
|
||||
def full_scan(target_dir, results_dir, results_dir_ref=None):
|
||||
@@ -132,6 +140,7 @@ def full_scan(target_dir, results_dir, results_dir_ref=None):
|
||||
if results_dir_ref:
|
||||
scan_results(results_dir_ref)
|
||||
update_p2p_coe_pairs()
|
||||
update_p3p_throttle_pairs()
|
||||
|
||||
|
||||
def update_p2p_coe_pairs():
|
||||
@@ -174,6 +183,58 @@ def update_p2p_coe_pairs():
|
||||
|
||||
print(f"[scanner] coe_pair updated for {updated} P2P test(s)")
|
||||
|
||||
def update_p3p_throttle_pairs():
|
||||
tests = get_all_tests()
|
||||
|
||||
p3p_lookup = {}
|
||||
for test in tests:
|
||||
if test.get("interference") != "P3P":
|
||||
continue
|
||||
|
||||
device = test.get("device")
|
||||
test_id = test.get("test_id")
|
||||
if not device or not test_id:
|
||||
continue
|
||||
|
||||
p3p_lookup.setdefault(f"{str(device).upper()}_{str(test_id).upper()}", []).append(test)
|
||||
|
||||
def _pair_test_id(test_id, throttled):
|
||||
if not test_id or not throttled:
|
||||
return None
|
||||
|
||||
upper_id = str(test_id).upper()
|
||||
upper_throttled = str(throttled).upper()
|
||||
|
||||
if upper_throttled == "TH":
|
||||
return re.sub("TH", "UT", upper_id, count=1)
|
||||
if upper_throttled == "UT":
|
||||
return re.sub("UT", "TH", upper_id, count=1)
|
||||
return None
|
||||
|
||||
updated = 0
|
||||
for test in tests:
|
||||
if test.get("interference") != "P3P":
|
||||
continue
|
||||
|
||||
device = test.get("device")
|
||||
test_id = test.get("test_id")
|
||||
pair_test_id = _pair_test_id(test_id, test.get("throttled"))
|
||||
|
||||
pairs = []
|
||||
if device and pair_test_id:
|
||||
lookup_key = f"{str(device).upper()}_{str(pair_test_id).upper()}"
|
||||
matches = p3p_lookup.get(lookup_key, [])
|
||||
for match in matches:
|
||||
match_device = match.get("device")
|
||||
match_test_id = match.get("test_id")
|
||||
if match_device and match_test_id:
|
||||
pairs.append(f"{match_device}_{match_test_id}")
|
||||
|
||||
set_p3p_pair(test.get("id"), sorted(set(pairs)))
|
||||
updated += 1
|
||||
|
||||
print(f"[scanner] p3p_pair updated for {updated} P3P test(s)")
|
||||
|
||||
|
||||
def scan_targets(target_dir):
|
||||
target_dir = _normalize_input_path(target_dir)
|
||||
|
||||
Reference in New Issue
Block a user