commit for publication

This commit is contained in:
2026-09-17 14:41:22 +01:00
committed by Jack Clifton
commit 0bf030f3c7
26 changed files with 2506 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
{% extends "base.html" %}
{% block body %}
{% if current_user.user_role >= UserRoles.ADMIN %}
<div>
<form action="/account/new" method="POST">
<div>
<label>Username:</label>
<input name="username" type="text" placeholder="Username" />
</div>
<div>
<label>Email:</label>
<input name="email" type="text" placeholder="Email" />
</div>
<div>
<label>Password:</label>
<input name="password" type="password" placeholder="Temporary Password" />
</div>
<div>
<label>User Type:</label>
<select name="user-type">
{% for role in UserRoles %}
<option value="{{ role }}">
{{ role.text }}
</option>
{% endfor %}
</select>
</div>
<div>
<button type="submit" style="margin-top: 20px;">Create</button>
</div>
</form>
</div>
{% endif %}
{% endblock %}
+77
View File
@@ -0,0 +1,77 @@
{% extends "base.html" %}
{% block body %}
<div>
<h2>My Account</h2>
<table class="vertical-table" style="margin-bottom: 40px;">
<tr>
<th>First Name:</th>
<td>{{ current_user.username }}</input></td>
</tr>
<tr>
<th>Email:</th>
<td>{{ current_user.email }}</input></td>
</tr>
<tr>
<th>User Type:</th>
<td>{{ current_user.user_role.text }}</td>
</tr>
</table>
</div>
{% if current_user.user_role >= UserRoles.ADMIN %}
<div>
<div style="margin-bottom: 20px; text-decoration: none; cursor: pointer;">
<a href="/account/new">Create User</a>
</div>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>User Type</th>
<th>Save</th>
</tr>
{% for user in users %}
<tr>
<form id="form-{{ user.id }}" method="POST" action="/account/update">
<div style="display: none;">
<input name="user-id" value="{{ user.id }}" />
</div>
<td>{{ user.id }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
{% if current_user.user_role >= UserRoles.ADMIN %}
<td>
<select name="user-type" oninput="document.getElementById('save-btn-{{ user.id }}').removeAttribute('disabled');">
{% for role in UserRoles %}
<option value="{{ role.text }}" {% if role == user.user_role %} selected {% endif %}>
{{ role.text }}
</option>
{% endfor %}
</select>
</td>
<td><button id="save-btn-{{ user.id }}" type="submit" disabled>Save</button></td>
{% else %}
<td>{{ user.usertype.type }}</td>
{% endif %}
</form>
</tr>
{% endfor %}
</table>
</div>
{% endif %}
{% endblock %}
+102
View File
@@ -0,0 +1,102 @@
{% extends "base.html" %}
{% block title %}Test Bench Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container" style="display: flex; gap: 0px; align-items: flex-start; margin-left: 100px;">
<div>
<h2>Active Tests - {{ report_id }}</h2>
<div style="margin-bottom: 10px;">
<a href="/active-tests"><- Go Back</a>
</div>
<table style="width: 100%; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background-color: var(--bg-surface);">
<thead>
<tr style="background-color: var(--bg-active); border-bottom: 1px solid var(--border);">
<th style="padding: 12px; text-align: left;">ID</th>
<th style="padding: 12px; text-align: left;">Author</th>
<th style="padding: 12px; text-align: left;">Project</th>
<th style="padding: 12px; text-align: left;">Version</th>
<th style="padding: 12px; text-align: left;">Board</th>
<th style="padding: 12px; text-align: left;">OS</th>
<th style="padding: 12px; text-align: left;">Date</th>
<th style="padding: 12px; text-align: left;">Start Time</th>
<th style="padding: 12px; text-align: left;">End Time</th>
<th style="padding: 12px; text-align: left;">Passed</th>
<th style="padding: 12px; text-align: left;">Failed</th>
<th style="padding: 12px; text-align: center; width: 1%; white-space: nowrap;">Delete</th>
</tr>
</thead>
<tbody>
{% for board in test_products %}
<tr style="border-bottom: 1px solid var(--border);">
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.test_product_id }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.report.author.username }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.report.project_version.project.project_name }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.report.project_version.version_string }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.testboard.board.family.board_family_prefix }}{{ board.testboard.board.board_name }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.testboard.os.os_name }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.timestamp_start.strftime("%d %b %Y") }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.timestamp_start.strftime("%H:%M:%S") }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.timestamp_end.strftime("%H:%M:%S") }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
0
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
0
</td>
<td>
<form action="/active-tests/delete-product-test/{{ board.test_product_id }}" method="POST">
<button type="submit">X</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="10" style="padding: 20px; text-align: center; color: var(--text-muted);">No tests are in progress.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}
+79
View File
@@ -0,0 +1,79 @@
{% extends "base.html" %}
{% block title %}Test Bench Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container" style="display: flex; gap: 0px; align-items: flex-start; margin-left: 100px;">
<div>
<h2>Active Tests</h2>
<table style="width: 100%; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background-color: var(--bg-surface);">
<thead>
<tr style="background-color: var(--bg-active); border-bottom: 1px solid var(--border);">
<th style="padding: 12px; text-align: left;">ID</th>
<th style="padding: 12px; text-align: left;">Author</th>
<th style="padding: 12px; text-align: left;">Project</th>
<th style="padding: 12px; text-align: left;">Version</th>
<th style="padding: 12px; text-align: left;">Date</th>
<th style="padding: 12px; text-align: left;">Start Time</th>
<th style="padding: 12px; text-align: left;">Status</th>
<th style="padding: 12px; text-align: center; width: 1%; white-space: nowrap;">Delete</th>
</tr>
</thead>
<tbody>
{% for report in active_reports %}
<tr style="border-bottom: 1px solid var(--border);" class="clickable" data-href="/active-tests/{{ report.test_report_id }}">
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.test_report_id }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.author.username }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.project_version.project.project_name }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.project_version.version_string }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.timestamp_start.strftime("%d %b %Y") }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ report.timestamp_start.strftime("%H:%M:%S") }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
In Progress
</td>
<td>
<form action="/active-tests/delete/{{ report.test_report_id }}" method="POST">
<button type="submit">X</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="7" style="padding: 20px; text-align: center; color: var(--text-muted);">No tests are in progress.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='utils/clickable.js') }}"></script>
{% endblock %}
+94
View File
@@ -0,0 +1,94 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Autotest{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='layout.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='colour-default.css') }}">
</head>
<body>
<header class="header-container">
<h1>Autotest</h1>
{% if current_user.is_authenticated %}
<a href="/account" class="user-account-btn" style="text-align: right;">
{{ current_user.f_name }} {{ current_user.s_name[0] if current_user.s_name else "" }}
</a>
{% endif %}
<nav>
<a href="/">Home</a>
<a href="/operating-system-setup">Operating Systems</a>
<a href="/projects">Projects</a>
<a href="/product-setup">Products</a>
<a href="/test-bench-setup">Test Bench</a>
<a href="/schedule-new-test">Schedule Test</a>
<a href="/active-tests">Active Tests</a>
<a href="/test-reports">Reports</a>
<a href="/account">Account</a>
{% if current_user.is_authenticated %}
<a href="/signout">Sign out</a>
{% else %}
<a href="/signin">Sign in</a>
{% endif %}
</nav>
</header>
<main>
{% block body %}{% endblock %}
</main>
<footer>
</footer>
<div id="flash-popup-container" style="position: fixed; top: 120px; left: 50%; transform: translateX(-50%); z-index: 1000; display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 400px; padding: 0 20px; box-sizing: border-box;">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="flash-popup {{ category }}" style="min-width: 280px; max-width: 400px; background-color: #e63946; color: white; padding: 14px 18px; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-family: sans-serif; display: flex; justify-content: space-between; align-items: center; gap: 12px; animation: popupFadeIn 0.3s ease;">
<span style="font-size: 14px; font-weight: 500; line-height: 1.4;">{{ message }}</span>
<button onclick="this.parentElement.remove()" style="background: none; border: none; color: white; cursor: pointer; font-size: 20px; font-weight: bold; padding: 0; line-height: 1; opacity: 0.8;">&times;</button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
<style>
@keyframes popupFadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const popups = document.querySelectorAll('.flash-popup');
popups.forEach(function(popup) {
// Automatically fade and remove the popup after 5 seconds
setTimeout(function() {
popup.style.transition = "opacity 0.5s ease, transform 0.5s ease";
popup.style.opacity = "0";
popup.style.transform = "translateY(-10px)";
setTimeout(function() {
popup.remove();
}, 500);
}, 5000);
});
});
</script>
{% block scripts %}{% endblock %}
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block body %}
<h1>
testing home page
</h1>
{% endblock %}
+51
View File
@@ -0,0 +1,51 @@
{% extends "base.html" %}
{% block title %}Operating System Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container" style="display: flex; gap: 0px; align-items: flex-start; margin-left: 100px;">
<div class="forms-column" style="flex: 1; min-width: 300px;">
<section class="setup-section" style="margin-bottom: 40px;">
<h2>Add Operating System</h2>
<form action="/operating-system-setup/add-os" method="POST" class="account-input">
<input type="text" name="os_name" placeholder="Operating System" required>
<button type="submit">Add OS</button>
</form>
</section>
</div>
<div class="table-column" style="flex: 2;">
<h2>Operating Systems</h2>
<table style="width: 100%; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background-color: var(--bg-surface);">
<thead>
<tr style="background-color: var(--bg-active); border-bottom: 1px solid var(--border);">
<th style="padding: 12px; text-align: left;">Operating System</th>
<th style="padding: 12px; text-align: center; width: 1%; white-space: nowrap;">Delete</th>
</tr>
</thead>
<tbody>
{% for os in operating_systems %}
<tr style="border-bottom: 1px solid var(--border);">
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ os.os_name }}
</td>
<td>
<form action="/operating-system-setup/delete-os/{{ os.os_id }}" method="POST">
<button type="submit">X</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="1" style="padding: 20px; text-align: center; color: var(--text-muted);">No products registered yet. Add one on the left.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+70
View File
@@ -0,0 +1,70 @@
{% extends "base.html" %}
{% block title %}Product Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container" style="display: flex; gap: 0px; align-items: flex-start; margin-left: 100px;">
<div class="forms-column" style="flex: 1; min-width: 300px;">
<section class="setup-section" style="margin-bottom: 40px;">
<h2>Add Board Family</h2>
<form action="/product-setup/add-family" method="POST" class="account-input">
<input type="text" name="family_name" placeholder="e.g. DPX-S" required>
<button type="submit">Add Family</button>
</form>
</section>
<section class="setup-section">
<h2>Add New Board</h2>
<form action="/product-setup/add-board" method="POST" class="account-input">
<label style="display:block; margin-bottom:5px; font-weight:600;">Board Family:</label>
<select name="board_family_id" style="display: block; margin-bottom: 10px; min-width: 250px; background-color: var(--bg-surface); color: var(--text-main); border: 1px solid var(--border); padding: 5px; border-radius: 6px;" required>
<option value="" disabled selected>Select a Family</option>
{% for family in families %}
<option value="{{ family.board_family_id }}">{{ family.board_family_prefix }}</option>
{% endfor %}
</select>
<input type="text" name="board_name" placeholder="Board Name">
<button type="submit">Add Product</button>
</form>
</section>
</div>
<div class="table-column" style="flex: 2;">
<h2>Products</h2>
<table style="width: 100%; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background-color: var(--bg-surface);">
<thead>
<tr style="background-color: var(--bg-active); border-bottom: 1px solid var(--border);">
<th style="padding: 12px; text-align: left;">Product Families</th>
<th style="padding: 12px; text-align: left;">Boards</th>
</tr>
</thead>
<tbody>
{% for boards in products_table %}
{% for board in boards %}
<tr style="border-bottom: 1px solid var(--border);">
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{% if loop.first %}{{ board.family.board_family_prefix }}{% endif %}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ board.family.board_family_prefix }}{{ board.board_name}}
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="1" style="padding: 20px; text-align: center; color: var(--text-muted);">No products registered yet. Add one on the left.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
+90
View File
@@ -0,0 +1,90 @@
{% extends "base.html" %}
{% block body %}
<div style="margin-bottom: 40px;">
<h2>Create New Project</h2>
<form action="/projects/add-project" method="POST" class="account-input">
<input type="text" name="project_name" placeholder="Project Name" required>
<button type="submit">Create Project</button>
</form>
</div>
<div>
<h2>Create New Version</h2>
<form action="/projects/add-version" method="POST" class="account-input">
<label style="display:block; margin-bottom:5px; font-weight:600;">Project Name:</label>
<select name="project_id" style="display: block; margin-bottom: 15px; min-width: 250px; background-color: var(--bg-surface); color: var(--text-main); border: 1px solid var(--border); padding: 8px; border-radius: 6px;" required>
<option value="" disabled selected>Select project...</option>
{% for project in projects %}
<option value="{{ project.project_id }}">{{ project.project_name }}</option>
{% endfor %}
</select>
<label style="display:block; margin-bottom:5px; font-weight:600;">Semantic Versioning Configuration:</label>
<div>
<input type="number" name="major" placeholder="Major" min="0" style="min-width: 70px; width: 70px;" required>
<input type="number" name="minor" placeholder="Minor" min="0" style="min-width: 70px; width: 70px;" required>
<input type="number" name="micro" placeholder="Micro" min="0" style="min-width: 70px; width: 70px;" required>
</div>
<button type="submit">Create Version</button>
</form>
</div>
<div class="display-panel">
<h2>Project Registry</h2>
{% for project in projects %}
<div class="project-card" style="background-color: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin-bottom: 25px;">
<h3 style="margin-top: 0; color: var(--accent); border-bottom: 1px solid var(--border); padding-bottom: 10px;">
{{ project.project_name }}
</h3>
<table style="width: 100%;">
<thead>
<tr style="color: var(--text-muted); font-size: 0.85rem;">
<th style="padding: 8px;">Version</th>
<th style="padding: 8px;">Status</th>
<th style="padding: 8px; text-align: right;">Visibility</th>
</tr>
</thead>
<tbody>
<!-- Loop through the project's versions sorted by semantic order using its relation helper -->
{% for version in project.versions | sort(attribute='project_version_major', reverse=True) %}
<tr style="border-top: 1px solid var(--border); opacity: {% if version.is_hidden %}0.5{% else %}1{% endif %};">
<td style="padding: 10px 8px; font-weight: 500;">
v{{ version.project_version_major }}.{{ version.project_version_minor }}.{{ version.project_version_micro }}
</td>
<td style="padding: 10px 8px; font-weight: 500;">
{% if version.is_hidden %}
<span style="font-size: 0.75rem; background-color: #ef4444; color: white; padding: 2px 6px; border-radius: 4px; margin-left: 10px;">HIDDEN</span>
{% else %}
<span style="font-size: 0.75rem; background-color: #22c55e; color: white; padding: 2px 6px; border-radius: 4px; margin-left: 10px;">ACTIVE</span>
{% endif %}
</td>
<td style="padding: 10px 8px; text-align: right;">
<!-- Uses your custom Segmented Control layout block for status transitions -->
<form action="/projects/toggle-version-hidden/{{ version.project_version_id }}" method="POST">
<div class="segmented-control">
<input type="checkbox" name="visibility_status" id="vis_{{ version.project_version_id }}_active" {% if version.is_hidden %}checked{% endif %} onchange="this.form.submit()">
<label for="vis_{{ version.project_version_id }}_active">{% if version.is_hidden %}Show{% else %}Hide{% endif %}</label>
</div>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="2" style="padding: 15px 8px; color: var(--text-muted); font-style: italic;">No semantic versions published for this asset profile.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p style="color: var(--text-muted); background-color: var(--bg-surface); padding: 20px; border-radius: 6px; border: 1px solid var(--border); text-align: center;">
No tracked projects found in database engine. Use creation module to register systems.
</p>
{% endfor %}
{% endblock %}
+146
View File
@@ -0,0 +1,146 @@
{% extends "base.html" %}
{% block title %}Test Bench Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container">
<form action="/schedule-new-test" method="POST">
<!-- project -->
<div>
<select id="proj" name="proj" onchange="oninput_proj();">
<option selected disabled>Project</option>
{% for proj in projects %}
<option value="{{ proj }}">{{ proj }}</option>
{% endfor %}
</select>
</div>
<!-- version -->
<div>
<select id="ver" name="ver" onchange="oninput_ver();">
<option selected disabled>Version</option>
</select>
</div>
<!-- build -->
<div>
<select id="build" name="build">
<option selected disabeld>Build</option>
</select>
</div>
<!-- products / test boards -->
<div>
<table>
<tr>
<th></th>
<th>Board Name</th>
<th>Operating System</th>
<th>MAC Address</th>
</tr>
{% for board in test_boards %}
<tr>
<td><input name="test-boards" type="checkbox" value="{{ board.testboard_id }}"></td>
<td>{{ board.board.family.board_family_prefix }}{{ board.board.board_name }}</td>
<td>{{ board.os.os_name }}</td>
<td>{{ board.mac_addr }}</td>
</tr>
{% else %}
<tr>
<td colspan="4" style="padding: 20px; text-align: center; color: var(--text-muted);">No board have been added to the test bench.</td>
</tr>
{% endfor %}
</table>
</div>
<!-- submit btn -->
<button type="submit">Schedule Test Run</button>
</form>
</div>
{% endblock %}
{% block scripts %}
<style>
form div select {
min-width: 100px;
}
</style>
<script>
const projects_json = {{ projects|tojson }};
const obj_selected = document.getElementById("proj");
const obj_ver = document.getElementById("ver");
const obj_build = document.getElementById("build");
function oninput_proj() {
const selected_proj = obj_selected.value;
const versions_list = projects_json[selected_proj];
obj_ver.innerHTML = "";
versions_list.forEach(function(version) {
const option = document.createElement("option");
option.value = version;
option.textContent = version;
obj_ver.appendChild(option);
})
}
function oninput_ver() {
// not implemented due to backend relying on internal coporate systems
// this is outside the scope of this assignment
// this will query the internal build archive to load a list of available builds
obj_build.innerHTML = "";
const versions_list = [
"example_x.y_z_1",
"example_x.y_z_2",
"example_x.y_z_3",
"example_x.y_z_4",
"example_x.y_z_5",
"example_x.y_z_6",
"example_x.y_z_7",
"example_x.y_z_8",
"example_x.y_z_9",
];
let i = 1;
versions_list.forEach(function(version) {
const option = document.createElement("option");
option.value = i; // example value
option.textContent = version;
obj_build.appendChild(option);
i++;
})
}
</script>
{% endblock %}
+14
View File
@@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block body %}
<div style="margin-bottom: 40px;">
<h2>Sign in</h2>
<form action="/signin" method="POST" class="account-input">
<input type="text" name="username" placeholder="Username or Email" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Sign in</button>
</form>
</div>
{% endblock %}
+115
View File
@@ -0,0 +1,115 @@
{% extends "base.html" %}
{% block title %}Test Bench Setup - Autotest{% endblock %}
{% block body %}
<div class="setup-container" style="display: flex; gap: 0px; align-items: flex-start; margin-left: 100px;">
<div class="forms-column" style="flex: 1; min-width: 300px;">
<section class="setup-section">
<h2>Add Board</h2>
<form id="addBoardForm" action="/test-bench-setup/add-board" method="POST" class="account-input">
<label style="display:block; margin-bottom:5px; font-weight:600;">Board Family:</label>
<select name="board_id" style="display: block; margin-bottom: 10px; min-width: 250px; background-color: var(--bg-surface); color: var(--text-main); border: 1px solid var(--border); padding: 5px; border-radius: 6px;" required>
<option value="" disabled selected>Select a Board</option>
{% for board in boards %}
<option value="{{ board.board_id }}">{{ board.family.board_family_prefix }}{{ board.board_name }}</option>
{% endfor %}
</select>
<input type="text" id="mac_addr" name="mac_addr" placeholder="MAC Address" required>
<div id="mac_err" class="error-text"></div>
<button type="submit">Add Test Board</button>
</form>
</section>
</div>
<div class="table-column" style="flex: 2;">
<h2>Test Units</h2>
<table style="width: 100%; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background-color: var(--bg-surface);">
<thead>
<tr style="background-color: var(--bg-active); border-bottom: 1px solid var(--border);">
<th style="padding: 12px; text-align: left;">Board</th>
<th style="padding: 12px; text-align: left;">MAC Address</th>
<th style="padding: 12px; text-align: left;">OS</th>
<th style="padding: 12px; text-align: center; width: 1%; white-space: nowrap;">Delete</th>
</tr>
</thead>
<tbody>
{% for test_unit in test_boards %}
<tr style="border-bottom: 1px solid var(--border);">
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ test_unit.board.family.board_family_prefix }}{{ test_unit.board.board_name }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
{{ test_unit.mac_addr }}
</td>
<td style="padding: 12px; text-align: left; font-weight: 600; color: var(--text-muted);">
<form action="/test-bench-setup/update-os/{{ test_unit.testboard_id }}" method="POST">
<select name="os_id" onchange="this.form.submit()">
<option value="0">No OS installed</option>
{% for os in operating_systems %}
<option value="{{ os.os_id}}" {% if os.os_id == test_unit.os.os_id %} selected {% endif %}>
{{ os.os_name }}
</option>
{% endfor %}
</select>
</form>
</td>
<td>
<form action="/test-bench-setup/delete-test-board/{{ test_unit.testboard_id }}" method="POST">
<button type="submit">X</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="1" style="padding: 20px; text-align: center; color: var(--text-muted);">No products registered yet. Add one on the left.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='utils/validation.js') }}"></script>
<script>
addBoardForm.addEventListener('submit', function(event) {
const mac_input = mac_addr.value;
const is_valid = validation.mac_addr(mac_input);
if (is_valid === false) {
event.preventDefault();
const err_msg = "Error: MAC address input is not valid";
console.error(err_msg);
mac_err.textContent = err_msg
}
});
</script>
{% endblock %}