zebra-day 1.0.2__py3-none-any.whl → 2.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zebra_day/__init__.py +7 -2
- zebra_day/_version.py +1 -0
- zebra_day/cli/__init__.py +80 -30
- zebra_day/cli/cognito.py +15 -9
- zebra_day/cli/gui.py +101 -13
- zebra_day/cli/printer.py +34 -27
- zebra_day/cli/template.py +19 -15
- zebra_day/cmd_mgr.py +3 -6
- zebra_day/docs/gx420d-gx430d-ug-en.pdf +0 -0
- zebra_day/docs/hardware_config_guide.md +149 -0
- zebra_day/docs/programatic_guide.md +181 -0
- zebra_day/docs/qln420_zebra_manual.pdf +0 -0
- zebra_day/docs/uid_screed_light.md +38 -0
- zebra_day/docs/zd620-zd420-ug-en.pdf +0 -0
- zebra_day/docs/zebra_day_ui_guide.md +194 -0
- zebra_day/etc/printer_config.json +5 -11
- zebra_day/etc/printer_config.template.json +5 -11
- zebra_day/etc/tmp_printers120.json +10 -0
- zebra_day/etc/tmp_printers139.json +10 -0
- zebra_day/etc/tmp_printers145.json +10 -0
- zebra_day/etc/tmp_printers147.json +10 -0
- zebra_day/etc/tmp_printers207.json +10 -0
- zebra_day/etc/tmp_printers34.json +10 -0
- zebra_day/etc/tmp_printers389.json +10 -0
- zebra_day/etc/tmp_printers398.json +10 -0
- zebra_day/etc/tmp_printers437.json +10 -0
- zebra_day/etc/tmp_printers439.json +10 -0
- zebra_day/etc/tmp_printers440.json +10 -0
- zebra_day/etc/tmp_printers469.json +10 -0
- zebra_day/etc/tmp_printers485.json +10 -0
- zebra_day/etc/tmp_printers508.json +10 -0
- zebra_day/etc/tmp_printers531.json +10 -0
- zebra_day/etc/tmp_printers540.json +10 -0
- zebra_day/etc/tmp_printers542.json +10 -0
- zebra_day/etc/tmp_printers543.json +10 -0
- zebra_day/etc/tmp_printers552.json +10 -0
- zebra_day/etc/tmp_printers715.json +10 -0
- zebra_day/etc/tmp_printers835.json +10 -0
- zebra_day/etc/tmp_printers842.json +10 -0
- zebra_day/etc/tmp_printers931.json +10 -0
- zebra_day/etc/tmp_printers969.json +10 -0
- zebra_day/etc/tmp_printers972.json +10 -0
- zebra_day/exceptions.py +1 -1
- zebra_day/files/blank_preview.png +0 -0
- zebra_day/files/corners_20cmX30cm_preview.png +0 -0
- zebra_day/files/corners_smallTube_preview.png +0 -0
- zebra_day/files/generic_2inX1in_preview.png +0 -0
- zebra_day/files/test_png_12020.png +0 -0
- zebra_day/files/test_png_12352.png +0 -0
- zebra_day/files/test_png_15472.png +0 -0
- zebra_day/files/test_png_24493.png +0 -0
- zebra_day/files/test_png_2897.png +0 -0
- zebra_day/files/test_png_30069.png +0 -0
- zebra_day/files/test_png_31690.png +0 -0
- zebra_day/files/test_png_33804.png +0 -0
- zebra_day/files/test_png_34737.png +0 -0
- zebra_day/files/test_png_4161.png +0 -0
- zebra_day/files/test_png_44748.png +0 -0
- zebra_day/files/test_png_4635.png +0 -0
- zebra_day/files/test_png_47791.png +0 -0
- zebra_day/files/test_png_47799.png +0 -0
- zebra_day/files/test_png_55588.png +0 -0
- zebra_day/files/test_png_56349.png +0 -0
- zebra_day/files/test_png_58809.png +0 -0
- zebra_day/files/test_png_5936.png +0 -0
- zebra_day/files/test_png_64110.png +0 -0
- zebra_day/files/test_png_64891.png +0 -0
- zebra_day/files/test_png_67242.png +0 -0
- zebra_day/files/test_png_69002.png +0 -0
- zebra_day/files/test_png_70065.png +0 -0
- zebra_day/files/test_png_72366.png +0 -0
- zebra_day/files/test_png_77793.png +0 -0
- zebra_day/files/test_png_89893.png +0 -0
- zebra_day/files/test_png_9572.png +0 -0
- zebra_day/files/tube_20mmX30mmA_preview.png +0 -0
- zebra_day/imgs/.hold +0 -0
- zebra_day/imgs/bar_ltpurp.png +0 -0
- zebra_day/imgs/bar_purp.png +0 -0
- zebra_day/imgs/bar_purp3.png +0 -0
- zebra_day/imgs/bar_red.png +0 -0
- zebra_day/imgs/legacy/UBC_gantt_chart.png +0 -0
- zebra_day/imgs/legacy/gx420d_network_config.png +0 -0
- zebra_day/imgs/legacy/gx420d_printer_config.png +0 -0
- zebra_day/imgs/legacy/ngrok.png +0 -0
- zebra_day/imgs/legacy/printer_details.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label2.png +0 -0
- zebra_day/imgs/legacy/zd620_network_config.png +0 -0
- zebra_day/imgs/legacy/zd620_printer_config.png +0 -0
- zebra_day/imgs/legacy/zday_quick_gui.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_dog.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_flower.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_main.png +0 -0
- zebra_day/imgs/legacy/zebra_day_available_zpl_templates.png +0 -0
- zebra_day/imgs/legacy/zebra_day_bkup_pconfig.png +0 -0
- zebra_day/imgs/legacy/zebra_day_home.png +0 -0
- zebra_day/imgs/legacy/zebra_day_manual_print.png +0 -0
- zebra_day/imgs/legacy/zebra_day_printer_fleet_json.png +0 -0
- zebra_day/imgs/legacy/zebra_day_quick_ex.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLa.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLb.png +0 -0
- zebra_day/imgs/ui_api_docs.png +0 -0
- zebra_day/imgs/ui_config.png +0 -0
- zebra_day/imgs/ui_dashboard.png +0 -0
- zebra_day/imgs/ui_print_request.png +0 -0
- zebra_day/imgs/ui_printers.png +0 -0
- zebra_day/imgs/ui_templates.png +0 -0
- zebra_day/logging_config.py +4 -9
- zebra_day/mkcert.py +157 -0
- zebra_day/paths.py +1 -2
- zebra_day/print_mgr.py +261 -185
- zebra_day/templates/modern/config.html +7 -0
- zebra_day/templates/modern/config_backups.html +59 -0
- zebra_day/templates/modern/config_editor.html +95 -0
- zebra_day/templates/modern/config_new.html +93 -0
- zebra_day/templates/modern/print_request.html +70 -8
- zebra_day/templates/modern/printer_detail.html +161 -34
- zebra_day/templates/modern/printers.html +17 -6
- zebra_day/templates/modern/template_editor.html +7 -4
- zebra_day/web/__init__.py +1 -1
- zebra_day/web/app.py +99 -17
- zebra_day/web/auth.py +17 -15
- zebra_day/web/middleware.py +8 -5
- zebra_day/web/routers/__init__.py +0 -1
- zebra_day/web/routers/api.py +330 -31
- zebra_day/web/routers/ui.py +174 -591
- zebra_day/zpl_renderer.py +45 -34
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/METADATA +144 -74
- zebra_day-2.1.4.dist-info/RECORD +240 -0
- zebra_day/bin/fetch_zebra_config.py +0 -15
- zebra_day/bin/generate_coord_grid_zpl.py +0 -50
- zebra_day/bin/print_zpl_from_file.py +0 -21
- zebra_day/bin/probe_new_label_dimensions.py +0 -75
- zebra_day/bin/scan_for_networed_zebra_printers.py +0 -23
- zebra_day/bin/scan_for_networed_zebra_printers_arp_scan.sh +0 -1
- zebra_day/bin/scan_for_networed_zebra_printers_curl.sh +0 -30
- zebra_day/bin/zserve.py +0 -1062
- zebra_day/templates/base.html +0 -36
- zebra_day/templates/bpr.html +0 -72
- zebra_day/templates/build_new_config.html +0 -36
- zebra_day/templates/build_print_request.html +0 -32
- zebra_day/templates/chg_ui_style.html +0 -19
- zebra_day/templates/edit_template.html +0 -128
- zebra_day/templates/edit_zpl.html +0 -37
- zebra_day/templates/index.html +0 -82
- zebra_day/templates/legacy/base.html +0 -37
- zebra_day/templates/legacy/bpr.html +0 -72
- zebra_day/templates/legacy/build_new_config.html +0 -36
- zebra_day/templates/legacy/build_print_request.html +0 -32
- zebra_day/templates/legacy/chg_ui_style.html +0 -19
- zebra_day/templates/legacy/edit_template.html +0 -128
- zebra_day/templates/legacy/edit_zpl.html +0 -37
- zebra_day/templates/legacy/index.html +0 -82
- zebra_day/templates/legacy/list_prior_configs.html +0 -24
- zebra_day/templates/legacy/print_result.html +0 -30
- zebra_day/templates/legacy/printer_details.html +0 -25
- zebra_day/templates/legacy/printer_status.html +0 -70
- zebra_day/templates/legacy/save_result.html +0 -17
- zebra_day/templates/legacy/send_print_request.html +0 -34
- zebra_day/templates/legacy/simple_print.html +0 -94
- zebra_day/templates/legacy/view_pstation_json.html +0 -29
- zebra_day/templates/list_prior_configs.html +0 -24
- zebra_day/templates/print_result.html +0 -30
- zebra_day/templates/printer_details.html +0 -25
- zebra_day/templates/printer_status.html +0 -70
- zebra_day/templates/save_result.html +0 -17
- zebra_day/templates/send_print_request.html +0 -34
- zebra_day/templates/simple_print.html +0 -94
- zebra_day/templates/view_pstation_json.html +0 -29
- zebra_day-1.0.2.dist-info/RECORD +0 -179
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
|
@@ -81,6 +81,13 @@
|
|
|
81
81
|
<i class="fas fa-external-link-alt"></i> View Full
|
|
82
82
|
</a>
|
|
83
83
|
</div>
|
|
84
|
+
|
|
85
|
+
<!-- Config File Path -->
|
|
86
|
+
<div class="mb-md" style="padding: 0.75rem 1rem; background: var(--color-gray-700); border-radius: var(--radius-sm); font-family: 'JetBrains Mono', monospace; font-size: 0.875rem;">
|
|
87
|
+
<span class="text-muted"><i class="fas fa-file-alt"></i> Loaded from:</span>
|
|
88
|
+
<code style="color: var(--color-highlight); margin-left: 0.5rem;">{{ config_file_path | default('Unknown') }}</code>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
84
91
|
{% if config_summary %}
|
|
85
92
|
<div class="grid grid-4 mb-lg">
|
|
86
93
|
<div class="stat-card">
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{% extends "modern/base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}Config Backups - Zebra Day{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="page-header">
|
|
7
|
+
<h1 class="page-title">Configuration Backups</h1>
|
|
8
|
+
<div class="header-actions">
|
|
9
|
+
<a href="/config" class="btn btn-outline"><i class="fas fa-arrow-left"></i> Back</a>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="card">
|
|
14
|
+
<div class="card-header">
|
|
15
|
+
<h3 class="card-title"><i class="fas fa-history"></i> Saved Configuration Files</h3>
|
|
16
|
+
<span class="badge">{{ backup_files | length }} backups</span>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<p class="text-muted mb-md" style="padding: 0 1rem;">
|
|
20
|
+
To restore a backup, download the file, open in a text editor, copy the contents,
|
|
21
|
+
then paste into the <a href="/config/edit">config editor</a> and save.
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
{% if backup_files %}
|
|
25
|
+
<div class="table-container">
|
|
26
|
+
<table class="table">
|
|
27
|
+
<thead>
|
|
28
|
+
<tr>
|
|
29
|
+
<th>Filename</th>
|
|
30
|
+
<th>Actions</th>
|
|
31
|
+
</tr>
|
|
32
|
+
</thead>
|
|
33
|
+
<tbody>
|
|
34
|
+
{% for file in backup_files %}
|
|
35
|
+
<tr>
|
|
36
|
+
<td>
|
|
37
|
+
<i class="fas fa-file-code text-muted"></i>
|
|
38
|
+
{{ file }}
|
|
39
|
+
</td>
|
|
40
|
+
<td>
|
|
41
|
+
<a href="/etc/old_printer_config/{{ file }}" class="btn btn-sm btn-outline" download>
|
|
42
|
+
<i class="fas fa-download"></i> Download
|
|
43
|
+
</a>
|
|
44
|
+
</td>
|
|
45
|
+
</tr>
|
|
46
|
+
{% endfor %}
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
</div>
|
|
50
|
+
{% else %}
|
|
51
|
+
<div class="empty-state">
|
|
52
|
+
<i class="fas fa-history"></i>
|
|
53
|
+
<p>No backup files found</p>
|
|
54
|
+
<small class="text-muted">Backups are created automatically when you save configuration changes</small>
|
|
55
|
+
</div>
|
|
56
|
+
{% endif %}
|
|
57
|
+
</div>
|
|
58
|
+
{% endblock %}
|
|
59
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{% extends "modern/base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ title }} - Zebra Day{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="page-header">
|
|
7
|
+
<h1 class="page-title">{{ title }}</h1>
|
|
8
|
+
<div class="header-actions">
|
|
9
|
+
<a href="/config" class="btn btn-outline"><i class="fas fa-arrow-left"></i> Back</a>
|
|
10
|
+
{% if mode == 'edit' %}
|
|
11
|
+
<button type="button" class="btn btn-outline" onclick="resetConfig()"><i class="fas fa-undo"></i> Reset</button>
|
|
12
|
+
<button type="button" class="btn btn-outline" onclick="clearConfig()"><i class="fas fa-trash"></i> Clear</button>
|
|
13
|
+
{% endif %}
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
{% if error_msg %}
|
|
18
|
+
<div class="alert alert-error mb-lg">
|
|
19
|
+
<i class="fas fa-exclamation-circle"></i> {{ error_msg }}
|
|
20
|
+
</div>
|
|
21
|
+
{% endif %}
|
|
22
|
+
|
|
23
|
+
<div class="card">
|
|
24
|
+
<div class="card-header">
|
|
25
|
+
<h3 class="card-title"><i class="fas fa-file-code"></i> Printer Configuration JSON</h3>
|
|
26
|
+
{% if mode == 'edit' %}
|
|
27
|
+
<span class="badge badge-warning">Editing</span>
|
|
28
|
+
{% else %}
|
|
29
|
+
<span class="badge badge-info">Read Only</span>
|
|
30
|
+
{% endif %}
|
|
31
|
+
</div>
|
|
32
|
+
<form method="post" action="/config/save">
|
|
33
|
+
<div class="form-group">
|
|
34
|
+
<textarea name="json_data" id="json-editor" class="form-control code-editor" rows="30" {% if mode != 'edit' %}readonly{% endif %}>{{ config_json }}</textarea>
|
|
35
|
+
</div>
|
|
36
|
+
{% if mode == 'edit' %}
|
|
37
|
+
<div class="form-actions">
|
|
38
|
+
<button type="submit" class="btn btn-primary" onclick="showLoading('Saving configuration...')">
|
|
39
|
+
<i class="fas fa-save"></i> Save Configuration
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
{% endif %}
|
|
43
|
+
</form>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<style>
|
|
47
|
+
.code-editor {
|
|
48
|
+
font-family: 'JetBrains Mono', 'Consolas', monospace;
|
|
49
|
+
font-size: 0.875rem;
|
|
50
|
+
line-height: 1.5;
|
|
51
|
+
background: var(--color-gray-700);
|
|
52
|
+
border: 1px solid var(--color-gray-600);
|
|
53
|
+
padding: 1rem;
|
|
54
|
+
resize: vertical;
|
|
55
|
+
min-height: 400px;
|
|
56
|
+
}
|
|
57
|
+
.code-editor:read-only {
|
|
58
|
+
background: var(--color-gray-800);
|
|
59
|
+
cursor: default;
|
|
60
|
+
}
|
|
61
|
+
.form-actions {
|
|
62
|
+
display: flex;
|
|
63
|
+
gap: 1rem;
|
|
64
|
+
padding: 1rem;
|
|
65
|
+
border-top: 1px solid var(--color-gray-600);
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
68
|
+
|
|
69
|
+
<script>
|
|
70
|
+
async function resetConfig() {
|
|
71
|
+
if (confirm('Reset configuration to template defaults? This will backup the current config.')) {
|
|
72
|
+
showLoading('Resetting configuration...');
|
|
73
|
+
window.location.href = '/config/reset';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function clearConfig() {
|
|
78
|
+
if (confirm('Clear all printer configuration? This will backup the current config.')) {
|
|
79
|
+
showLoading('Clearing configuration...');
|
|
80
|
+
window.location.href = '/config/clear';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Auto-format JSON on blur
|
|
85
|
+
document.getElementById('json-editor')?.addEventListener('blur', function() {
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(this.value);
|
|
88
|
+
this.value = JSON.stringify(parsed, null, 4);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
// Invalid JSON, leave as-is
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
{% endblock %}
|
|
95
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{% extends "modern/base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}New Configuration - Zebra Day{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="page-header">
|
|
7
|
+
<h1 class="page-title">Build New Configuration</h1>
|
|
8
|
+
<div class="header-actions">
|
|
9
|
+
<a href="/config" class="btn btn-outline"><i class="fas fa-arrow-left"></i> Back</a>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div class="grid grid-2">
|
|
14
|
+
<!-- Network Scan -->
|
|
15
|
+
<div class="card">
|
|
16
|
+
<div class="card-header">
|
|
17
|
+
<h3 class="card-title"><i class="fas fa-wifi"></i> Scan Network for Printers</h3>
|
|
18
|
+
</div>
|
|
19
|
+
<form action="/config/scan" method="get">
|
|
20
|
+
<div class="form-group">
|
|
21
|
+
<label class="form-label">IP Range Prefix</label>
|
|
22
|
+
<input type="text" name="ip_stub" class="form-control" value="{{ ip_root }}" placeholder="192.168.1">
|
|
23
|
+
<small class="text-muted">Enter the first three octets of your network</small>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="form-group">
|
|
26
|
+
<label class="form-label">Lab Name</label>
|
|
27
|
+
<input type="text" name="lab" class="form-control" value="scan-results" placeholder="Enter lab name">
|
|
28
|
+
<small class="text-muted">Printers found will be added to this lab</small>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="form-group">
|
|
31
|
+
<label class="form-label">Scan Wait Time</label>
|
|
32
|
+
<select name="scan_wait" class="form-control">
|
|
33
|
+
<option value="0.15">Fast (0.15s)</option>
|
|
34
|
+
<option value="0.25" selected>Normal (0.25s)</option>
|
|
35
|
+
<option value="0.5">Slow (0.5s)</option>
|
|
36
|
+
<option value="1.0">Very Slow (1.0s)</option>
|
|
37
|
+
</select>
|
|
38
|
+
<small class="text-muted">Longer wait times find more printers on slow networks</small>
|
|
39
|
+
</div>
|
|
40
|
+
<button type="submit" class="btn btn-primary" onclick="showLoading('Scanning network for Zebra printers...')">
|
|
41
|
+
<i class="fas fa-search"></i> Start Network Scan
|
|
42
|
+
</button>
|
|
43
|
+
</form>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- Quick Actions -->
|
|
47
|
+
<div class="card">
|
|
48
|
+
<div class="card-header">
|
|
49
|
+
<h3 class="card-title"><i class="fas fa-bolt"></i> Quick Actions</h3>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="quick-actions">
|
|
52
|
+
<a href="/config/reset" class="action-card" onclick="return confirm('Reset config to template defaults?')">
|
|
53
|
+
<i class="fas fa-undo"></i>
|
|
54
|
+
<div>
|
|
55
|
+
<strong>Reset to Template</strong>
|
|
56
|
+
<small class="text-muted d-block">Restore default configuration</small>
|
|
57
|
+
</div>
|
|
58
|
+
</a>
|
|
59
|
+
<a href="/config/clear" class="action-card" onclick="return confirm('Clear all printer configuration?')">
|
|
60
|
+
<i class="fas fa-trash"></i>
|
|
61
|
+
<div>
|
|
62
|
+
<strong>Clear Configuration</strong>
|
|
63
|
+
<small class="text-muted d-block">Remove all printers</small>
|
|
64
|
+
</div>
|
|
65
|
+
</a>
|
|
66
|
+
<a href="/config/edit" class="action-card">
|
|
67
|
+
<i class="fas fa-edit"></i>
|
|
68
|
+
<div>
|
|
69
|
+
<strong>Manual Edit</strong>
|
|
70
|
+
<small class="text-muted d-block">Edit JSON directly</small>
|
|
71
|
+
</div>
|
|
72
|
+
</a>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<hr class="my-md">
|
|
76
|
+
|
|
77
|
+
<h4 class="mb-md">Existing Labs</h4>
|
|
78
|
+
{% if labs %}
|
|
79
|
+
<div class="grid grid-3">
|
|
80
|
+
{% for lab in labs %}
|
|
81
|
+
<a href="/printers/{{ lab }}" class="action-card">
|
|
82
|
+
<i class="fas fa-building"></i>
|
|
83
|
+
<strong>{{ lab }}</strong>
|
|
84
|
+
</a>
|
|
85
|
+
{% endfor %}
|
|
86
|
+
</div>
|
|
87
|
+
{% else %}
|
|
88
|
+
<p class="text-muted">No labs configured yet. Run a network scan to discover printers.</p>
|
|
89
|
+
{% endif %}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
{% endblock %}
|
|
93
|
+
|
|
@@ -96,9 +96,14 @@
|
|
|
96
96
|
<a href="/" class="btn btn-outline">
|
|
97
97
|
<i class="fas fa-arrow-left"></i> Cancel
|
|
98
98
|
</a>
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
|
|
99
|
+
<div class="d-flex" style="gap: var(--spacing-md);">
|
|
100
|
+
<button type="button" class="btn btn-secondary btn-lg" onclick="downloadPNG()">
|
|
101
|
+
<i class="fas fa-download"></i> Download PNG
|
|
102
|
+
</button>
|
|
103
|
+
<button type="submit" class="btn btn-primary btn-lg" onclick="showLoading('Sending print request...')">
|
|
104
|
+
<i class="fas fa-print"></i> Print Label
|
|
105
|
+
</button>
|
|
106
|
+
</div>
|
|
102
107
|
</div>
|
|
103
108
|
</div>
|
|
104
109
|
</form>
|
|
@@ -116,12 +121,16 @@
|
|
|
116
121
|
|
|
117
122
|
printerSelect.innerHTML = '<option value="">Select a printer...</option>';
|
|
118
123
|
|
|
119
|
-
if (lab && labsDict[lab]) {
|
|
120
|
-
|
|
124
|
+
if (lab && labsDict[lab] && labsDict[lab].printers) {
|
|
125
|
+
// v2 schema: printers are nested under 'printers' key
|
|
126
|
+
var printers = labsDict[lab].printers;
|
|
127
|
+
for (var printerId in printers) {
|
|
128
|
+
var printerInfo = printers[printerId];
|
|
121
129
|
var option = document.createElement('option');
|
|
122
|
-
option.value =
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
option.value = printerId;
|
|
131
|
+
// Display friendly name if available, otherwise use ID
|
|
132
|
+
option.text = printerInfo.printer_name || printerId;
|
|
133
|
+
if (printerId === selectedPrinter) {
|
|
125
134
|
option.selected = true;
|
|
126
135
|
}
|
|
127
136
|
printerSelect.appendChild(option);
|
|
@@ -136,6 +145,59 @@
|
|
|
136
145
|
updatePrinters();
|
|
137
146
|
}
|
|
138
147
|
});
|
|
148
|
+
|
|
149
|
+
async function downloadPNG() {
|
|
150
|
+
var form = document.getElementById('print-form');
|
|
151
|
+
var template = form.querySelector('select[name="label_zpl_style"]').value;
|
|
152
|
+
|
|
153
|
+
if (!template) {
|
|
154
|
+
showToast('error', 'Error', 'Please select a label template');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
showLoading('Rendering PNG...');
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
var response = await fetch('/api/v1/render/png', {
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: {'Content-Type': 'application/json'},
|
|
164
|
+
body: JSON.stringify({
|
|
165
|
+
template: template,
|
|
166
|
+
uid_barcode: form.querySelector('input[name="uid_barcode"]').value || '',
|
|
167
|
+
alt_a: form.querySelector('input[name="alt_a"]').value || '',
|
|
168
|
+
alt_b: form.querySelector('input[name="alt_b"]').value || '',
|
|
169
|
+
alt_c: form.querySelector('input[name="alt_c"]').value || '',
|
|
170
|
+
alt_d: form.querySelector('input[name="alt_d"]').value || '',
|
|
171
|
+
alt_e: form.querySelector('input[name="alt_e"]').value || '',
|
|
172
|
+
alt_f: form.querySelector('input[name="alt_f"]').value || ''
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
hideLoading();
|
|
177
|
+
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
var error = await response.json();
|
|
180
|
+
showToast('error', 'Render Failed', error.detail || 'Unknown error');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Download the PNG file
|
|
185
|
+
var blob = await response.blob();
|
|
186
|
+
var url = window.URL.createObjectURL(blob);
|
|
187
|
+
var a = document.createElement('a');
|
|
188
|
+
a.href = url;
|
|
189
|
+
a.download = template + '_label.png';
|
|
190
|
+
document.body.appendChild(a);
|
|
191
|
+
a.click();
|
|
192
|
+
window.URL.revokeObjectURL(url);
|
|
193
|
+
a.remove();
|
|
194
|
+
|
|
195
|
+
showToast('success', 'Success', 'PNG downloaded');
|
|
196
|
+
} catch (e) {
|
|
197
|
+
hideLoading();
|
|
198
|
+
showToast('error', 'Error', 'Failed to render PNG: ' + e.message);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
139
201
|
</script>
|
|
140
202
|
{% endblock %}
|
|
141
203
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{% block content %}
|
|
6
6
|
<div class="page-header">
|
|
7
7
|
<h1 class="page-title">{{ printer_name }}</h1>
|
|
8
|
-
<p class="page-subtitle">Printer details for {{ lab }}</p>
|
|
8
|
+
<p class="page-subtitle">Printer details for {{ lab_name | default(lab) }}</p>
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
11
|
<!-- Breadcrumb -->
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<span class="text-muted"> / </span>
|
|
15
15
|
<a href="/printers">Printers</a>
|
|
16
16
|
<span class="text-muted"> / </span>
|
|
17
|
-
<a href="/printers/{{ lab }}">{{ lab }}</a>
|
|
17
|
+
<a href="/printers/{{ lab }}">{{ lab_name | default(lab) }}</a>
|
|
18
18
|
<span class="text-muted"> / </span>
|
|
19
19
|
<span>{{ printer_name }}</span>
|
|
20
20
|
</div>
|
|
@@ -32,53 +32,149 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
<table class="table" style="background: transparent; box-shadow: none;">
|
|
34
34
|
<tbody>
|
|
35
|
-
{% for key, value in printer_info.items() %}
|
|
36
35
|
<tr>
|
|
37
|
-
<td style="width: 40%;"><strong>
|
|
36
|
+
<td style="width: 40%;"><strong>Printer ID</strong></td>
|
|
37
|
+
<td>{{ printer_id }}</td>
|
|
38
|
+
</tr>
|
|
39
|
+
<tr>
|
|
40
|
+
<td><strong>Display Name</strong></td>
|
|
41
|
+
<td>{{ printer_info.printer_name | default('Not set', true) }}</td>
|
|
42
|
+
</tr>
|
|
43
|
+
<tr>
|
|
44
|
+
<td><strong>Location</strong></td>
|
|
45
|
+
<td>{{ printer_info.lab_location | default('Not set', true) }}</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td><strong>Manufacturer</strong></td>
|
|
49
|
+
<td>{{ printer_info.manufacturer | default('zebra') | title }}</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td><strong>Model</strong></td>
|
|
53
|
+
<td>{{ printer_info.model | default('Unknown') }}</td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td><strong>Serial</strong></td>
|
|
57
|
+
<td>{{ printer_info.serial | default('Unknown') }}</td>
|
|
58
|
+
</tr>
|
|
59
|
+
<tr>
|
|
60
|
+
<td><strong>IP Address</strong></td>
|
|
38
61
|
<td>
|
|
39
|
-
{% if
|
|
40
|
-
<a href="http://{{
|
|
41
|
-
{% elif key == 'status' %}
|
|
42
|
-
{% if value == 'online' %}
|
|
43
|
-
<span class="badge badge-success">Online</span>
|
|
62
|
+
{% if printer_info.ip_address != 'dl_png' %}
|
|
63
|
+
<a href="http://{{ printer_info.ip_address }}" target="_blank">{{ printer_info.ip_address }}</a>
|
|
44
64
|
{% else %}
|
|
45
|
-
|
|
65
|
+
{{ printer_info.ip_address }}
|
|
46
66
|
{% endif %}
|
|
47
|
-
|
|
48
|
-
|
|
67
|
+
</td>
|
|
68
|
+
</tr>
|
|
69
|
+
<tr>
|
|
70
|
+
<td><strong>Print Method</strong></td>
|
|
71
|
+
<td>{{ printer_info.print_method | default('socket') }}</td>
|
|
72
|
+
</tr>
|
|
73
|
+
<tr>
|
|
74
|
+
<td><strong>Label Styles</strong></td>
|
|
75
|
+
<td>
|
|
76
|
+
{% for style in printer_info.label_zpl_styles %}
|
|
49
77
|
<span class="badge badge-primary">{{ style }}</span>
|
|
50
78
|
{% endfor %}
|
|
79
|
+
</td>
|
|
80
|
+
</tr>
|
|
81
|
+
<tr>
|
|
82
|
+
<td><strong>Default Label Style</strong></td>
|
|
83
|
+
<td>
|
|
84
|
+
{% if printer_info.default_label_style %}
|
|
85
|
+
<span class="badge badge-success">{{ printer_info.default_label_style }}</span>
|
|
51
86
|
{% else %}
|
|
52
|
-
{{
|
|
87
|
+
<span class="text-muted">{{ printer_info.label_zpl_styles[0] if printer_info.label_zpl_styles else 'None' }} (first in list)</span>
|
|
53
88
|
{% endif %}
|
|
54
89
|
</td>
|
|
55
90
|
</tr>
|
|
56
|
-
{%
|
|
91
|
+
{% if printer_info.notes %}
|
|
92
|
+
<tr>
|
|
93
|
+
<td><strong>Notes</strong></td>
|
|
94
|
+
<td>{{ printer_info.notes }}</td>
|
|
95
|
+
</tr>
|
|
96
|
+
{% endif %}
|
|
57
97
|
</tbody>
|
|
58
98
|
</table>
|
|
59
99
|
</div>
|
|
60
|
-
|
|
61
|
-
<!--
|
|
100
|
+
|
|
101
|
+
<!-- Edit Printer Settings -->
|
|
62
102
|
<div class="card">
|
|
63
103
|
<div class="card-header">
|
|
64
|
-
<h3 class="card-title">
|
|
65
|
-
</div>
|
|
66
|
-
<div class="quick-actions">
|
|
67
|
-
<a href="/print?lab={{ lab }}&printer={{ printer_name }}" class="action-card">
|
|
68
|
-
<i class="fas fa-print"></i>
|
|
69
|
-
<div>
|
|
70
|
-
<strong>Print Label</strong>
|
|
71
|
-
<small class="text-muted d-block">Send a print request</small>
|
|
72
|
-
</div>
|
|
73
|
-
</a>
|
|
74
|
-
<a href="/templates" class="action-card">
|
|
75
|
-
<i class="fas fa-file-code"></i>
|
|
76
|
-
<div>
|
|
77
|
-
<strong>View Templates</strong>
|
|
78
|
-
<small class="text-muted d-block">Available label styles</small>
|
|
79
|
-
</div>
|
|
80
|
-
</a>
|
|
104
|
+
<h3 class="card-title">Edit Settings</h3>
|
|
81
105
|
</div>
|
|
106
|
+
<form id="printer-edit-form" class="form-group">
|
|
107
|
+
<div class="form-group">
|
|
108
|
+
<label class="form-label">Display Name</label>
|
|
109
|
+
<input type="text" name="printer_name" class="form-control"
|
|
110
|
+
value="{{ printer_info.printer_name | default('', true) }}"
|
|
111
|
+
placeholder="e.g., Lab 3 - Bench A">
|
|
112
|
+
<small class="text-muted">User-friendly name for this printer</small>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="form-group">
|
|
115
|
+
<label class="form-label">Location</label>
|
|
116
|
+
{% if available_locations %}
|
|
117
|
+
<select name="lab_location" class="form-control">
|
|
118
|
+
<option value="">-- Select Location --</option>
|
|
119
|
+
{% for loc in available_locations %}
|
|
120
|
+
<option value="{{ loc }}" {% if printer_info.lab_location == loc %}selected{% endif %}>{{ loc }}</option>
|
|
121
|
+
{% endfor %}
|
|
122
|
+
</select>
|
|
123
|
+
{% else %}
|
|
124
|
+
<input type="text" name="lab_location" class="form-control"
|
|
125
|
+
value="{{ printer_info.lab_location | default('', true) }}"
|
|
126
|
+
placeholder="No locations defined for this lab">
|
|
127
|
+
<small class="text-muted">Define locations at the lab level first</small>
|
|
128
|
+
{% endif %}
|
|
129
|
+
</div>
|
|
130
|
+
<div class="form-group">
|
|
131
|
+
<label class="form-label">Default Label Style</label>
|
|
132
|
+
<select name="default_label_style" class="form-control">
|
|
133
|
+
<option value="">-- Use first in list --</option>
|
|
134
|
+
{% for style in printer_info.label_zpl_styles %}
|
|
135
|
+
<option value="{{ style }}" {% if printer_info.default_label_style == style %}selected{% endif %}>{{ style }}</option>
|
|
136
|
+
{% endfor %}
|
|
137
|
+
</select>
|
|
138
|
+
<small class="text-muted">Style used when printing without specifying a template</small>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="form-group">
|
|
141
|
+
<label class="form-label">Notes</label>
|
|
142
|
+
<textarea name="notes" class="form-control" rows="2" placeholder="Optional notes">{{ printer_info.notes | default('', true) }}</textarea>
|
|
143
|
+
</div>
|
|
144
|
+
<button type="submit" class="btn btn-primary">
|
|
145
|
+
<i class="fas fa-save"></i> Save Changes
|
|
146
|
+
</button>
|
|
147
|
+
</form>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<!-- Quick Actions -->
|
|
152
|
+
<div class="card mt-lg">
|
|
153
|
+
<div class="card-header">
|
|
154
|
+
<h3 class="card-title">Quick Actions</h3>
|
|
155
|
+
</div>
|
|
156
|
+
<div class="grid grid-3">
|
|
157
|
+
<a href="/print?lab={{ lab }}&printer={{ printer_id }}" class="action-card">
|
|
158
|
+
<i class="fas fa-print"></i>
|
|
159
|
+
<div>
|
|
160
|
+
<strong>Print Label</strong>
|
|
161
|
+
<small class="text-muted d-block">Send a print request</small>
|
|
162
|
+
</div>
|
|
163
|
+
</a>
|
|
164
|
+
<a href="/templates" class="action-card">
|
|
165
|
+
<i class="fas fa-file-code"></i>
|
|
166
|
+
<div>
|
|
167
|
+
<strong>View Templates</strong>
|
|
168
|
+
<small class="text-muted d-block">Available label styles</small>
|
|
169
|
+
</div>
|
|
170
|
+
</a>
|
|
171
|
+
<a href="/printers/{{ lab }}" class="action-card">
|
|
172
|
+
<i class="fas fa-arrow-left"></i>
|
|
173
|
+
<div>
|
|
174
|
+
<strong>Back to Lab</strong>
|
|
175
|
+
<small class="text-muted d-block">View all printers</small>
|
|
176
|
+
</div>
|
|
177
|
+
</a>
|
|
82
178
|
</div>
|
|
83
179
|
</div>
|
|
84
180
|
|
|
@@ -103,7 +199,7 @@
|
|
|
103
199
|
<p class="text-muted mb-lg">Send a test label to verify the printer is working correctly.</p>
|
|
104
200
|
<div class="grid grid-3">
|
|
105
201
|
{% for style in printer_info.label_zpl_styles[:6] %}
|
|
106
|
-
<a href="/print?lab={{ lab }}&printer={{
|
|
202
|
+
<a href="/print?lab={{ lab }}&printer={{ printer_id }}&template={{ style }}&test=1" class="action-card">
|
|
107
203
|
<i class="fas fa-tag"></i>
|
|
108
204
|
<div>
|
|
109
205
|
<strong>{{ style }}</strong>
|
|
@@ -113,5 +209,36 @@
|
|
|
113
209
|
{% endfor %}
|
|
114
210
|
</div>
|
|
115
211
|
</div>
|
|
212
|
+
|
|
213
|
+
<script>
|
|
214
|
+
document.getElementById('printer-edit-form').addEventListener('submit', async (e) => {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
const form = e.target;
|
|
217
|
+
const data = {
|
|
218
|
+
printer_name: form.printer_name.value || null,
|
|
219
|
+
lab_location: form.lab_location.value || null,
|
|
220
|
+
default_label_style: form.default_label_style.value || null,
|
|
221
|
+
notes: form.notes.value || ''
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const response = await fetch('/api/v1/labs/{{ lab }}/printers/{{ printer_id }}', {
|
|
226
|
+
method: 'PATCH',
|
|
227
|
+
headers: { 'Content-Type': 'application/json' },
|
|
228
|
+
body: JSON.stringify(data)
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (response.ok) {
|
|
232
|
+
showToast('success', 'Saved', 'Printer settings updated successfully');
|
|
233
|
+
setTimeout(() => window.location.reload(), 1000);
|
|
234
|
+
} else {
|
|
235
|
+
const err = await response.json();
|
|
236
|
+
showToast('error', 'Error', err.detail || 'Failed to save settings');
|
|
237
|
+
}
|
|
238
|
+
} catch (err) {
|
|
239
|
+
showToast('error', 'Error', 'Network error: ' + err.message);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
</script>
|
|
116
243
|
{% endblock %}
|
|
117
244
|
|