169 lines
6.9 KiB
HTML
169 lines
6.9 KiB
HTML
{% extends 'base.html' %}
|
||
{% block title %}New Document – IT Asset Management{% endblock %}
|
||
{% block breadcrumb %}
|
||
<li class="breadcrumb-item"><a href="{{ url_for('dashboard.index') }}">Home</a></li>
|
||
<li class="breadcrumb-item"><a href="{{ url_for('paperwork.index') }}">Paperwork</a></li>
|
||
<li class="breadcrumb-item active">New Document</li>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="page-header mb-4">
|
||
<h1><i class="bi bi-file-earmark-plus me-2"></i>Create Document</h1>
|
||
</div>
|
||
|
||
<div class="card border-0 shadow-sm" style="max-width:740px;">
|
||
<div class="card-body">
|
||
<form method="POST" action="{{ url_for('paperwork.create') }}">
|
||
<div class="row g-3 mb-3">
|
||
<div class="col-md-6">
|
||
<label class="form-label">Document Type <span class="text-danger">*</span></label>
|
||
<select name="document_type" class="form-select" id="docType">
|
||
{% for val, label in doc_types %}
|
||
<option value="{{ val }}">{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<label class="form-label">Title</label>
|
||
<input type="text" name="title" class="form-control"
|
||
placeholder="Leave blank to auto-generate">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Word Template selector -->
|
||
{% if all_templates %}
|
||
<div class="mb-3">
|
||
<label class="form-label">
|
||
Word Template
|
||
<span class="text-muted small">(optional — generates an editable .docx)</span>
|
||
</label>
|
||
<select name="template_id" id="templateSelect" class="form-select">
|
||
<option value="">— No template (PDF only) —</option>
|
||
{% for tpl in all_templates %}
|
||
<option value="{{ tpl.id }}">{{ tpl.name }}{% if tpl.category %} [{{ tpl.category }}]{% endif %}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<!-- Variable preview loaded via AJAX -->
|
||
<div id="tplVarsBox" class="mt-2" style="display:none">
|
||
<div class="small text-muted mb-1">Variables auto-filled from this template:</div>
|
||
<div id="tplVarsList" class="d-flex flex-wrap gap-1"></div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- User search -->
|
||
<div class="mb-3">
|
||
<label class="form-label">User <span class="text-danger">*</span></label>
|
||
<input type="hidden" name="user_id" id="userId" value="{{ preselect_user_id or '' }}">
|
||
<input type="text" id="userSearch" class="form-control"
|
||
placeholder="Type name or Windows ID…" autocomplete="off">
|
||
<div id="userDropdown" class="list-group position-absolute shadow" style="z-index:1000;display:none;min-width:350px;"></div>
|
||
<div id="userDisplay" class="form-text text-success fw-semibold"></div>
|
||
</div>
|
||
|
||
<!-- Asset search (optional) -->
|
||
<div class="mb-3">
|
||
<label class="form-label">Asset <span class="text-muted small">(optional)</span></label>
|
||
<input type="hidden" name="asset_id" id="assetId" value="{{ preselect_asset_id or '' }}">
|
||
<input type="text" id="assetSearch" class="form-control"
|
||
placeholder="Serial number or service tag…" autocomplete="off">
|
||
<div id="assetDropdown" class="list-group position-absolute shadow" style="z-index:1000;display:none;min-width:350px;"></div>
|
||
<div id="assetDisplay" class="form-text text-success fw-semibold"></div>
|
||
</div>
|
||
|
||
{% if preselect_assignment_id %}
|
||
<input type="hidden" name="assignment_id" value="{{ preselect_assignment_id }}">
|
||
{% endif %}
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Notes</label>
|
||
<textarea name="notes" class="form-control" rows="2"></textarea>
|
||
</div>
|
||
|
||
<div class="d-flex gap-2">
|
||
<button type="submit" class="btn btn-primary">
|
||
<i class="bi bi-file-earmark-check me-1"></i>Generate Document
|
||
</button>
|
||
<a href="{{ url_for('paperwork.index') }}" class="btn btn-outline-secondary">Cancel</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
{% if all_templates %}
|
||
<div class="mt-3">
|
||
<a href="{{ url_for('doc_templates.index') }}" class="btn btn-sm btn-outline-primary">
|
||
<i class="bi bi-file-earmark-word me-1"></i>Manage Templates
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
{% endblock %}
|
||
|
||
{% block extra_js %}
|
||
<script>
|
||
function liveSearch(inputId, dropdownId, hiddenId, displayId, endpoint) {
|
||
const input = document.getElementById(inputId);
|
||
const dropdown = document.getElementById(dropdownId);
|
||
const hidden = document.getElementById(hiddenId);
|
||
const display = document.getElementById(displayId);
|
||
let timer;
|
||
input.addEventListener('input', () => {
|
||
clearTimeout(timer);
|
||
timer = setTimeout(() => {
|
||
const q = input.value.trim();
|
||
if (q.length < 2) { dropdown.style.display = 'none'; return; }
|
||
fetch(`${endpoint}?q=${encodeURIComponent(q)}`)
|
||
.then(r => r.json())
|
||
.then(items => {
|
||
dropdown.innerHTML = '';
|
||
if (!items.length) { dropdown.style.display = 'none'; return; }
|
||
items.forEach(item => {
|
||
const a = document.createElement('a');
|
||
a.className = 'list-group-item list-group-item-action py-2';
|
||
a.textContent = item.text;
|
||
a.addEventListener('click', () => {
|
||
hidden.value = item.id;
|
||
input.value = item.text;
|
||
display.textContent = '✓ Selected';
|
||
dropdown.style.display = 'none';
|
||
});
|
||
dropdown.appendChild(a);
|
||
});
|
||
dropdown.style.display = 'block';
|
||
});
|
||
}, 250);
|
||
});
|
||
document.addEventListener('click', e => { if (!input.contains(e.target)) dropdown.style.display = 'none'; });
|
||
}
|
||
|
||
liveSearch('userSearch', 'userDropdown', 'userId', 'userDisplay', '{{ url_for("users.search") }}');
|
||
liveSearch('assetSearch', 'assetDropdown', 'assetId', 'assetDisplay', '{{ url_for("assets.search") }}');
|
||
|
||
// Template variable preview
|
||
const tplSelect = document.getElementById('templateSelect');
|
||
if (tplSelect) {
|
||
const PII_VARS = new Set(['user_name', 'user_email', 'user_phone']);
|
||
tplSelect.addEventListener('change', () => {
|
||
const id = tplSelect.value;
|
||
const box = document.getElementById('tplVarsBox');
|
||
const list = document.getElementById('tplVarsList');
|
||
if (!id) { box.style.display = 'none'; return; }
|
||
fetch(`/doc-templates/${id}/variables.json`)
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
list.innerHTML = '';
|
||
(data.variables || []).forEach(v => {
|
||
const badge = document.createElement('span');
|
||
badge.className = 'badge ' + (PII_VARS.has(v) ? 'bg-danger' : 'bg-secondary');
|
||
badge.title = PII_VARS.has(v) ? 'PII — will be masked on user departure' : '';
|
||
badge.textContent = '{{ ' + v + ' }}';
|
||
list.appendChild(badge);
|
||
});
|
||
box.style.display = 'block';
|
||
})
|
||
.catch(() => { box.style.display = 'none'; });
|
||
});
|
||
}
|
||
</script>
|
||
{% endblock %}
|