- Implement test script for new SAG module endpoints BE-003 (Tag State Management) and BE-004 (Bulk Operations). - Create test cases for creating, updating, and bulk operations on cases and tags. - Add a test for module deactivation to ensure data integrity is maintained. - Include setup and teardown for tests to clear database state before and after each test.
335 lines
11 KiB
HTML
335 lines
11 KiB
HTML
{% extends "shared/frontend/base.html" %}
|
|
|
|
{% block title %}Opret Hardware - BMC Hub{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.form-container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.form-header {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.form-header h1 {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.form-header p {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.form-card {
|
|
background: var(--bg-card);
|
|
border-radius: 12px;
|
|
padding: 2rem;
|
|
border: 1px solid rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.form-section {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.form-section-title {
|
|
font-size: 1.2rem;
|
|
font-weight: 600;
|
|
margin-bottom: 1rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 2px solid var(--accent);
|
|
}
|
|
|
|
.form-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.form-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.form-group.full-width {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.form-group label {
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.form-group input,
|
|
.form-group select,
|
|
.form-group textarea {
|
|
padding: 0.75rem;
|
|
border: 1px solid rgba(0,0,0,0.2);
|
|
border-radius: 8px;
|
|
background: var(--bg-body);
|
|
color: var(--text-primary);
|
|
font-size: 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.form-group input:focus,
|
|
.form-group select:focus,
|
|
.form-group textarea:focus {
|
|
outline: none;
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 3px rgba(15, 76, 117, 0.1);
|
|
}
|
|
|
|
.form-group textarea {
|
|
min-height: 100px;
|
|
resize: vertical;
|
|
}
|
|
|
|
.form-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
justify-content: flex-end;
|
|
margin-top: 2rem;
|
|
padding-top: 2rem;
|
|
border-top: 1px solid rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.btn {
|
|
padding: 0.75rem 2rem;
|
|
border-radius: 8px;
|
|
font-weight: 500;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
border: none;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.btn-primary {
|
|
background-color: var(--accent);
|
|
color: white;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background-color: #0056b3;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(15, 76, 117, 0.3);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background-color: #6c757d;
|
|
color: white;
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
background-color: #5a6268;
|
|
}
|
|
|
|
.required {
|
|
color: #dc3545;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.form-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.form-actions {
|
|
flex-direction: column-reverse;
|
|
}
|
|
|
|
.btn {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="form-container">
|
|
<div class="form-header">
|
|
<h1>🖥️ Opret Nyt Hardware</h1>
|
|
<p>Tilføj et nyt hardware asset til systemet</p>
|
|
</div>
|
|
|
|
<div class="form-card">
|
|
<form id="hardwareForm" onsubmit="submitForm(event)">
|
|
<!-- Basic Information -->
|
|
<div class="form-section">
|
|
<h3 class="form-section-title">📋 Grundlæggende Information</h3>
|
|
<div class="form-grid">
|
|
<div class="form-group">
|
|
<label for="asset_type">Type <span class="required">*</span></label>
|
|
<select id="asset_type" name="asset_type" required>
|
|
<option value="">Vælg type...</option>
|
|
<option value="pc">🖥️ PC</option>
|
|
<option value="laptop">💻 Laptop</option>
|
|
<option value="printer">🖨️ Printer</option>
|
|
<option value="skærm">🖥️ Skærm</option>
|
|
<option value="telefon">📱 Telefon</option>
|
|
<option value="server">🗄️ Server</option>
|
|
<option value="netværk">🌐 Netværk</option>
|
|
<option value="andet">📦 Andet</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="brand">Mærke</label>
|
|
<input type="text" id="brand" name="brand" placeholder="fx Dell, HP, Lenovo...">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="model">Model</label>
|
|
<input type="text" id="model" name="model" placeholder="fx OptiPlex 7090">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="serial_number">Serienummer</label>
|
|
<input type="text" id="serial_number" name="serial_number" placeholder="Unik serienummer">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="internal_asset_id">Internt Asset ID</label>
|
|
<input type="text" id="internal_asset_id" name="internal_asset_id" placeholder="BMC-PC-001">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="customer_asset_id">Kunde Asset ID</label>
|
|
<input type="text" id="customer_asset_id" name="customer_asset_id" placeholder="Kundens ID">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ownership -->
|
|
<div class="form-section">
|
|
<h3 class="form-section-title">👥 Ejerskab</h3>
|
|
<div class="form-grid">
|
|
<div class="form-group">
|
|
<label for="current_owner_type">Ejer Type</label>
|
|
<select id="current_owner_type" name="current_owner_type" onchange="toggleCustomerSelect()">
|
|
<option value="bmc">BMC</option>
|
|
<option value="customer">Kunde</option>
|
|
<option value="third_party">Tredje Part</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group" id="customerSelectGroup" style="display: none;">
|
|
<label for="current_owner_customer_id">Kunde</label>
|
|
<select id="current_owner_customer_id" name="current_owner_customer_id">
|
|
<option value="">Vælg kunde...</option>
|
|
{% for customer in customers %}
|
|
<option value="{{ customer.id }}">{{ customer.navn }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="form-section">
|
|
<h3 class="form-section-title">📊 Status & Garanti</h3>
|
|
<div class="form-grid">
|
|
<div class="form-group">
|
|
<label for="status">Status</label>
|
|
<select id="status" name="status">
|
|
<option value="active">✅ Aktiv</option>
|
|
<option value="faulty_reported">⚠️ Fejl Rapporteret</option>
|
|
<option value="in_repair">🔧 Under Reparation</option>
|
|
<option value="replaced">🔄 Udskiftet</option>
|
|
<option value="retired">📦 Udtjent</option>
|
|
<option value="unsupported">❌ Ikke Supporteret</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="warranty_until">Garanti Udløber</label>
|
|
<input type="date" id="warranty_until" name="warranty_until">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="end_of_life">End of Life</label>
|
|
<input type="date" id="end_of_life" name="end_of_life">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes -->
|
|
<div class="form-section">
|
|
<h3 class="form-section-title">📝 Noter</h3>
|
|
<div class="form-group full-width">
|
|
<label for="notes">Beskrivelse/Noter</label>
|
|
<textarea id="notes" name="notes" placeholder="Tilføj eventuelle noter eller beskrivelse..."></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="form-actions">
|
|
<a href="/hardware" class="btn btn-secondary">Annuller</a>
|
|
<button type="submit" class="btn btn-primary">💾 Gem Hardware</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
function toggleCustomerSelect() {
|
|
const ownerType = document.getElementById('current_owner_type').value;
|
|
const customerGroup = document.getElementById('customerSelectGroup');
|
|
|
|
if (ownerType === 'customer') {
|
|
customerGroup.style.display = 'block';
|
|
} else {
|
|
customerGroup.style.display = 'none';
|
|
document.getElementById('current_owner_customer_id').value = '';
|
|
}
|
|
}
|
|
|
|
async function submitForm(event) {
|
|
event.preventDefault();
|
|
|
|
const formData = new FormData(event.target);
|
|
const data = {};
|
|
|
|
for (const [key, value] of formData.entries()) {
|
|
if (value) {
|
|
// Convert customer_id to integer
|
|
if (key === 'current_owner_customer_id') {
|
|
data[key] = parseInt(value);
|
|
} else {
|
|
data[key] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/v1/hardware', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
alert('Hardware oprettet!');
|
|
window.location.href = `/hardware/${result.id}`;
|
|
} else {
|
|
const error = await response.json();
|
|
alert('Fejl: ' + (error.detail || 'Kunne ikke oprette hardware'));
|
|
}
|
|
} catch (error) {
|
|
alert('Fejl ved oprettelse: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Initialize customer select visibility
|
|
toggleCustomerSelect();
|
|
</script>
|
|
{% endblock %}
|