zebra-day 0.0.37__py3-none-any.whl → 2.0.0__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.
Files changed (173) hide show
  1. zebra_day/__init__.py +35 -0
  2. zebra_day/bin/__init__.py +0 -0
  3. zebra_day/cli/__init__.py +240 -0
  4. zebra_day/cli/cognito.py +121 -0
  5. zebra_day/cli/gui.py +338 -0
  6. zebra_day/cli/printer.py +168 -0
  7. zebra_day/cli/template.py +176 -0
  8. zebra_day/cmd_mgr.py +35 -0
  9. zebra_day/etc/Monoid-Regular-HalfTight-Dollar-0-1-l.ttf +0 -0
  10. zebra_day/etc/label_styles/blank.zpl +0 -0
  11. zebra_day/etc/label_styles/cornersStripOf4Squares_1inX1in.zpl +55 -0
  12. zebra_day/etc/label_styles/corners_1inX2in.zpl +28 -0
  13. zebra_day/etc/label_styles/corners_20cmX30cm.zpl +6 -0
  14. zebra_day/etc/label_styles/corners_smallTube.zpl +7 -0
  15. zebra_day/etc/label_styles/corners_unspecifiedDimensions.zpl +15 -0
  16. zebra_day/etc/label_styles/generic_2inX1in.zpl +21 -0
  17. zebra_day/etc/label_styles/plate_1inX0.25in.zpl +9 -0
  18. zebra_day/etc/label_styles/plate_1inX0.25inHD.zpl +9 -0
  19. zebra_day/etc/label_styles/smallTubeWdotHD_prod.zpl +8 -0
  20. zebra_day/etc/label_styles/smallTubeWdot_corners.zpl +7 -0
  21. zebra_day/etc/label_styles/smallTubeWdot_prod.zpl +8 -0
  22. zebra_day/etc/label_styles/smallTubeWdot_prodAlt1.zpl +6 -0
  23. zebra_day/etc/label_styles/smallTubeWdot_prodAlt1b.zpl +3 -0
  24. zebra_day/etc/label_styles/smallTubeWdot_prodV2.zpl +8 -0
  25. zebra_day/etc/label_styles/smallTubeWdot_reagent.zpl +29 -0
  26. zebra_day/etc/label_styles/stripOf4Squares_1inX1in.zpl +32 -0
  27. zebra_day/etc/label_styles/test_800dX800dCoordinateArray.zpl +1 -0
  28. zebra_day/etc/label_styles/tmps/.hold +0 -0
  29. zebra_day/etc/label_styles/tmps/tmp_zpl_templates.here +0 -0
  30. zebra_day/etc/label_styles/tube_20mmX30mmA.zpl +7 -0
  31. zebra_day/etc/label_styles/tube_2inX0.3in.zpl +15 -0
  32. zebra_day/etc/label_styles/tube_2inX0.5in.zpl +15 -0
  33. zebra_day/etc/label_styles/tube_2inX0.5inHD.zpl +15 -0
  34. zebra_day/etc/label_styles/tube_2inX1in.zpl +25 -0
  35. zebra_day/etc/label_styles/tube_2inX1inHD.zpl +22 -0
  36. zebra_day/etc/label_styles/tube_2inX1inHDv3.zpl +21 -0
  37. zebra_day/etc/old_printer_config/.hold +0 -0
  38. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.022846_printer_config.json +1 -0
  39. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.033657_printer_config.json +1 -0
  40. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.039597_printer_config.json +3 -0
  41. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.047295_printer_config.json +1 -0
  42. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.055804_printer_config.json +1 -0
  43. zebra_day/etc/old_printer_config/2026-02-01_01:50:25.061337_printer_config.json +3 -0
  44. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.073326_printer_config.json +1 -0
  45. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.081950_printer_config.json +1 -0
  46. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.088251_printer_config.json +3 -0
  47. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.096501_printer_config.json +1 -0
  48. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.104767_printer_config.json +1 -0
  49. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.110364_printer_config.json +3 -0
  50. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.118239_printer_config.json +1 -0
  51. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.125950_printer_config.json +1 -0
  52. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.349866_printer_config.json +1 -0
  53. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.361085_printer_config.json +3 -0
  54. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.558323_printer_config.json +1 -0
  55. zebra_day/etc/old_printer_config/2026-02-01_01:51:24.565756_printer_config.json +3 -0
  56. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.739070_printer_config.json +16 -0
  57. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.753796_printer_config.json +1 -0
  58. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.760201_printer_config.json +3 -0
  59. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.768747_printer_config.json +1 -0
  60. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.775312_printer_config.json +3 -0
  61. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.782533_printer_config.json +1 -0
  62. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.789287_printer_config.json +1 -0
  63. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.794230_printer_config.json +3 -0
  64. zebra_day/etc/old_printer_config/2026-02-01_01:51:29.800021_printer_config.json +5 -0
  65. zebra_day/etc/printer_config.json +4 -0
  66. zebra_day/etc/printer_config.template.json +24 -0
  67. zebra_day/etc/tmp_printers0.json +5 -0
  68. zebra_day/etc/tmp_printers120.json +10 -0
  69. zebra_day/etc/tmp_printers145.json +10 -0
  70. zebra_day/etc/tmp_printers207.json +10 -0
  71. zebra_day/etc/tmp_printers374.json +5 -0
  72. zebra_day/etc/tmp_printers383.json +5 -0
  73. zebra_day/etc/tmp_printers450.json +5 -0
  74. zebra_day/etc/tmp_printers469.json +10 -0
  75. zebra_day/etc/tmp_printers485.json +10 -0
  76. zebra_day/etc/tmp_printers504.json +5 -0
  77. zebra_day/etc/tmp_printers531.json +10 -0
  78. zebra_day/etc/tmp_printers540.json +10 -0
  79. zebra_day/etc/tmp_printers542.json +10 -0
  80. zebra_day/etc/tmp_printers552.json +10 -0
  81. zebra_day/etc/tmp_printers608.json +5 -0
  82. zebra_day/etc/tmp_printers657.json +5 -0
  83. zebra_day/etc/tmp_printers715.json +10 -0
  84. zebra_day/etc/tmp_printers838.json +5 -0
  85. zebra_day/etc/tmp_printers839.json +5 -0
  86. zebra_day/etc/tmp_printers933.json +5 -0
  87. zebra_day/etc/tmp_printers957.json +5 -0
  88. zebra_day/etc/tmp_printers972.json +10 -0
  89. zebra_day/exceptions.py +88 -0
  90. zebra_day/files/.hold +0 -0
  91. zebra_day/files/blank_preview.png +0 -0
  92. zebra_day/files/corners_20cmX30cm_preview.png +0 -0
  93. zebra_day/files/generic_2inX1in_preview.png +0 -0
  94. zebra_day/files/hold +0 -0
  95. zebra_day/files/test_png_12020.png +0 -0
  96. zebra_day/files/test_png_12352.png +0 -0
  97. zebra_day/files/test_png_15472.png +0 -0
  98. zebra_day/files/test_png_17696.png +0 -0
  99. zebra_day/files/test_png_23477.png +0 -0
  100. zebra_day/files/test_png_24493.png +0 -0
  101. zebra_day/files/test_png_28157.png +0 -0
  102. zebra_day/files/test_png_30069.png +0 -0
  103. zebra_day/files/test_png_35832.png +0 -0
  104. zebra_day/files/test_png_36400.png +0 -0
  105. zebra_day/files/test_png_40816.png +0 -0
  106. zebra_day/files/test_png_47791.png +0 -0
  107. zebra_day/files/test_png_47799.png +0 -0
  108. zebra_day/files/test_png_49564.png +0 -0
  109. zebra_day/files/test_png_53848.png +0 -0
  110. zebra_day/files/test_png_55588.png +0 -0
  111. zebra_day/files/test_png_58809.png +0 -0
  112. zebra_day/files/test_png_62542.png +0 -0
  113. zebra_day/files/test_png_67242.png +0 -0
  114. zebra_day/files/test_png_89893.png +0 -0
  115. zebra_day/files/test_png_91597.png +0 -0
  116. zebra_day/files/test_png_93633.png +0 -0
  117. zebra_day/files/tmpbjo3k7q1.png +0 -0
  118. zebra_day/files/tmpigtr4pwy.png +0 -0
  119. zebra_day/files/tube_20mmX30mmA_preview.png +0 -0
  120. zebra_day/files/zpl_label_tube_2inX1in_2026-02-01_01:51:24.370964.png +0 -0
  121. zebra_day/logging_config.py +74 -0
  122. zebra_day/logs/.hold +0 -0
  123. zebra_day/logs/print_requests.log +2 -0
  124. zebra_day/paths.py +143 -0
  125. zebra_day/print_mgr.py +557 -117
  126. zebra_day/static/datschund.css +140 -0
  127. zebra_day/static/datschund.png +0 -0
  128. zebra_day/static/daylily.png +0 -0
  129. zebra_day/static/favicon.svg +20 -0
  130. zebra_day/static/general.css +99 -0
  131. zebra_day/static/js/zebra_modern.js +172 -0
  132. zebra_day/static/lsmc.css +354 -0
  133. zebra_day/static/moon.jpeg +0 -0
  134. zebra_day/static/oakland.css +197 -0
  135. zebra_day/static/petrichor.css +150 -0
  136. zebra_day/static/popday_daylily.css +140 -0
  137. zebra_day/static/style.css +183 -0
  138. zebra_day/static/triangles.css +122 -0
  139. zebra_day/static/tron.css +277 -0
  140. zebra_day/static/zebra_modern.css +771 -0
  141. zebra_day/static/zebras.css +176 -0
  142. zebra_day/templates/modern/base.html +98 -0
  143. zebra_day/templates/modern/config.html +141 -0
  144. zebra_day/templates/modern/config_backups.html +59 -0
  145. zebra_day/templates/modern/config_editor.html +95 -0
  146. zebra_day/templates/modern/config_new.html +93 -0
  147. zebra_day/templates/modern/dashboard.html +160 -0
  148. zebra_day/templates/modern/print_request.html +145 -0
  149. zebra_day/templates/modern/print_result.html +88 -0
  150. zebra_day/templates/modern/printer_detail.html +244 -0
  151. zebra_day/templates/modern/printers.html +144 -0
  152. zebra_day/templates/modern/save_result.html +46 -0
  153. zebra_day/templates/modern/template_editor.html +175 -0
  154. zebra_day/templates/modern/templates.html +122 -0
  155. zebra_day/web/__init__.py +9 -0
  156. zebra_day/web/app.py +248 -0
  157. zebra_day/web/auth.py +172 -0
  158. zebra_day/web/middleware.py +159 -0
  159. zebra_day/web/routers/__init__.py +2 -0
  160. zebra_day/web/routers/api.py +313 -0
  161. zebra_day/web/routers/ui.py +636 -0
  162. zebra_day/zpl_renderer.py +273 -0
  163. zebra_day-2.0.0.dist-info/METADATA +847 -0
  164. zebra_day-2.0.0.dist-info/RECORD +168 -0
  165. {zebra_day-0.0.37.dist-info → zebra_day-2.0.0.dist-info}/WHEEL +1 -1
  166. zebra_day-2.0.0.dist-info/entry_points.txt +4 -0
  167. zebra_day/bin/scan_for_networed_zebra_printers.py +0 -23
  168. zebra_day/bin/te.py +0 -905
  169. zebra_day/bin/zserve.py +0 -620
  170. zebra_day-0.0.37.dist-info/METADATA +0 -1177
  171. zebra_day-0.0.37.dist-info/RECORD +0 -10
  172. {zebra_day-0.0.37.dist-info → zebra_day-2.0.0.dist-info/licenses}/LICENSE +0 -0
  173. {zebra_day-0.0.37.dist-info → zebra_day-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,160 @@
1
+ {% extends "modern/base.html" %}
2
+
3
+ {% block title %}Dashboard - Zebra Day{% endblock %}
4
+
5
+ {% block content %}
6
+ <!-- Page Header -->
7
+ <div class="page-header">
8
+ <h1 class="page-title">Zebra Day Dashboard</h1>
9
+ <p class="page-subtitle">Zebra printer and label template management</p>
10
+ </div>
11
+
12
+ <!-- Stats Grid -->
13
+ <div class="grid grid-4 mb-xl">
14
+ <a href="/printers" class="stat-card stat-card-clickable">
15
+ <div class="card-icon primary">
16
+ <i class="fas fa-print"></i>
17
+ </div>
18
+ <div>
19
+ <div class="stat-value">{{ stats.total_printers | default(0) }}</div>
20
+ <div class="stat-label">Total Printers</div>
21
+ </div>
22
+ </a>
23
+
24
+ <a href="/printers" class="stat-card stat-card-clickable">
25
+ <div class="card-icon success">
26
+ <i class="fas fa-check-circle"></i>
27
+ </div>
28
+ <div>
29
+ <div class="stat-value">{{ stats.online_printers | default(0) }}</div>
30
+ <div class="stat-label">Online</div>
31
+ </div>
32
+ </a>
33
+
34
+ <a href="/printers" class="stat-card stat-card-clickable">
35
+ <div class="card-icon info">
36
+ <i class="fas fa-building"></i>
37
+ </div>
38
+ <div>
39
+ <div class="stat-value">{{ stats.total_labs | default(0) }}</div>
40
+ <div class="stat-label">Labs</div>
41
+ </div>
42
+ </a>
43
+
44
+ <a href="/templates" class="stat-card stat-card-clickable">
45
+ <div class="card-icon warning">
46
+ <i class="fas fa-file-code"></i>
47
+ </div>
48
+ <div>
49
+ <div class="stat-value">{{ stats.total_templates | default(0) }}</div>
50
+ <div class="stat-label">Templates</div>
51
+ </div>
52
+ </a>
53
+ </div>
54
+
55
+ <!-- Main Content Grid -->
56
+ <div class="grid grid-2">
57
+ <!-- Quick Actions -->
58
+ <div class="card">
59
+ <div class="card-header">
60
+ <h3 class="card-title">Quick Actions</h3>
61
+ </div>
62
+ <div class="quick-actions">
63
+ <a href="/print" class="action-card">
64
+ <i class="fas fa-tag"></i>
65
+ <div>
66
+ <strong>Print Label</strong>
67
+ <small class="text-muted d-block">Send a print request</small>
68
+ </div>
69
+ </a>
70
+ <a href="/config?action=scan" class="action-card">
71
+ <i class="fas fa-wifi"></i>
72
+ <div>
73
+ <strong>Scan Network</strong>
74
+ <small class="text-muted d-block">Discover printers</small>
75
+ </div>
76
+ </a>
77
+ <a href="/templates" class="action-card">
78
+ <i class="fas fa-edit"></i>
79
+ <div>
80
+ <strong>Edit Templates</strong>
81
+ <small class="text-muted d-block">Manage ZPL files</small>
82
+ </div>
83
+ </a>
84
+ <a href="/config" class="action-card">
85
+ <i class="fas fa-cog"></i>
86
+ <div>
87
+ <strong>Configuration</strong>
88
+ <small class="text-muted d-block">View/edit settings</small>
89
+ </div>
90
+ </a>
91
+ </div>
92
+ </div>
93
+
94
+ <!-- Labs Overview -->
95
+ <div class="card">
96
+ <div class="card-header">
97
+ <h3 class="card-title">Labs</h3>
98
+ <a href="/printers" class="btn btn-outline btn-sm">View All</a>
99
+ </div>
100
+ {% if labs %}
101
+ <div class="table-container" style="box-shadow: none;">
102
+ <table class="table">
103
+ <thead>
104
+ <tr>
105
+ <th>Lab Name</th>
106
+ <th>Printers</th>
107
+ <th>Actions</th>
108
+ </tr>
109
+ </thead>
110
+ <tbody>
111
+ {% for lab_name, printers in labs.items() %}
112
+ <tr>
113
+ <td><strong>{{ lab_name }}</strong></td>
114
+ <td>{{ printers | length }} printer(s)</td>
115
+ <td>
116
+ <a href="/printers/{{ lab_name }}" class="btn btn-sm btn-outline">
117
+ <i class="fas fa-eye"></i> View
118
+ </a>
119
+ </td>
120
+ </tr>
121
+ {% endfor %}
122
+ </tbody>
123
+ </table>
124
+ </div>
125
+ {% else %}
126
+ <div class="empty-state">
127
+ <i class="fas fa-building"></i>
128
+ <p>No labs configured yet</p>
129
+ <a href="/config?action=scan" class="btn btn-primary">
130
+ <i class="fas fa-wifi"></i> Scan Network
131
+ </a>
132
+ </div>
133
+ {% endif %}
134
+ </div>
135
+ </div>
136
+
137
+ <!-- API Documentation -->
138
+ <div class="card mt-lg">
139
+ <div class="card-header">
140
+ <h3 class="card-title">API Documentation</h3>
141
+ </div>
142
+ <div class="grid grid-2">
143
+ <a href="/docs" target="_blank" class="action-card">
144
+ <i class="fas fa-book-open"></i>
145
+ <div>
146
+ <strong>Swagger UI</strong>
147
+ <small class="text-muted d-block">Interactive API documentation</small>
148
+ </div>
149
+ </a>
150
+ <a href="/redoc" target="_blank" class="action-card">
151
+ <i class="fas fa-file-alt"></i>
152
+ <div>
153
+ <strong>ReDoc</strong>
154
+ <small class="text-muted d-block">Read-only API reference</small>
155
+ </div>
156
+ </a>
157
+ </div>
158
+ </div>
159
+ {% endblock %}
160
+
@@ -0,0 +1,145 @@
1
+ {% extends "modern/base.html" %}
2
+
3
+ {% block title %}Print Label - Zebra Day{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="page-header">
7
+ <h1 class="page-title">Print Label</h1>
8
+ <p class="page-subtitle">Send a label print request to a Zebra printer</p>
9
+ </div>
10
+
11
+ <form id="print-form" action="/_print_label" method="get">
12
+ <div class="grid grid-2">
13
+ <!-- Printer Selection -->
14
+ <div class="card">
15
+ <div class="card-header">
16
+ <h3 class="card-title">1. Select Printer</h3>
17
+ </div>
18
+ <div class="form-group">
19
+ <label class="form-label required">Lab</label>
20
+ <select id="lab-select" name="lab" class="form-control" onchange="updatePrinters()" required>
21
+ <option value="">Select a lab...</option>
22
+ {% for lab in labs %}
23
+ <option value="{{ lab }}" {% if selected_lab == lab %}selected{% endif %}>{{ lab }}</option>
24
+ {% endfor %}
25
+ </select>
26
+ </div>
27
+ <div class="form-group">
28
+ <label class="form-label required">Printer</label>
29
+ <select id="printer-select" name="printer" class="form-control" required>
30
+ <option value="">Select a printer...</option>
31
+ </select>
32
+ </div>
33
+ <div class="form-group mb-0">
34
+ <label class="form-label required">Label Template</label>
35
+ <select name="label_zpl_style" class="form-control" required>
36
+ <option value="">Select a template...</option>
37
+ {% if stable_templates %}
38
+ <optgroup label="Stable Templates">
39
+ {% for template in stable_templates %}
40
+ <option value="{{ template }}" {% if selected_template == template %}selected{% endif %}>{{ template }}</option>
41
+ {% endfor %}
42
+ </optgroup>
43
+ {% endif %}
44
+ {% if draft_templates %}
45
+ <optgroup label="Draft Templates">
46
+ {% for template in draft_templates %}
47
+ <option value="{{ template }}" {% if selected_template == template %}selected{% endif %}>{{ template }}</option>
48
+ {% endfor %}
49
+ </optgroup>
50
+ {% endif %}
51
+ </select>
52
+ </div>
53
+ </div>
54
+
55
+ <!-- Label Data -->
56
+ <div class="card">
57
+ <div class="card-header">
58
+ <h3 class="card-title">2. Label Data</h3>
59
+ </div>
60
+ <div class="form-group">
61
+ <label class="form-label">UID Barcode</label>
62
+ <input type="text" name="uid_barcode" class="form-control" placeholder="Enter barcode value">
63
+ </div>
64
+ <div class="grid grid-2" style="gap: var(--spacing-md);">
65
+ <div class="form-group">
66
+ <label class="form-label">Alt A</label>
67
+ <input type="text" name="alt_a" class="form-control" placeholder="Field A">
68
+ </div>
69
+ <div class="form-group">
70
+ <label class="form-label">Alt B</label>
71
+ <input type="text" name="alt_b" class="form-control" placeholder="Field B">
72
+ </div>
73
+ <div class="form-group">
74
+ <label class="form-label">Alt C</label>
75
+ <input type="text" name="alt_c" class="form-control" placeholder="Field C">
76
+ </div>
77
+ <div class="form-group">
78
+ <label class="form-label">Alt D</label>
79
+ <input type="text" name="alt_d" class="form-control" placeholder="Field D">
80
+ </div>
81
+ <div class="form-group">
82
+ <label class="form-label">Alt E</label>
83
+ <input type="text" name="alt_e" class="form-control" placeholder="Field E">
84
+ </div>
85
+ <div class="form-group mb-0">
86
+ <label class="form-label">Alt F</label>
87
+ <input type="text" name="alt_f" class="form-control" placeholder="Field F">
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ <!-- Submit -->
94
+ <div class="card mt-lg">
95
+ <div class="d-flex" style="justify-content: space-between; align-items: center;">
96
+ <a href="/" class="btn btn-outline">
97
+ <i class="fas fa-arrow-left"></i> Cancel
98
+ </a>
99
+ <button type="submit" class="btn btn-primary btn-lg" onclick="showLoading('Sending print request...')">
100
+ <i class="fas fa-print"></i> Print Label
101
+ </button>
102
+ </div>
103
+ </div>
104
+ </form>
105
+ {% endblock %}
106
+
107
+ {% block extra_scripts %}
108
+ <script>
109
+ var labsDict = {{ labs_dict | safe }};
110
+ var selectedPrinter = '{{ selected_printer | default("") }}';
111
+
112
+ function updatePrinters() {
113
+ var labSelect = document.getElementById('lab-select');
114
+ var printerSelect = document.getElementById('printer-select');
115
+ var lab = labSelect.value;
116
+
117
+ printerSelect.innerHTML = '<option value="">Select a printer...</option>';
118
+
119
+ if (lab && labsDict[lab] && labsDict[lab].printers) {
120
+ // v2 schema: printers are nested under 'printers' key
121
+ var printers = labsDict[lab].printers;
122
+ for (var printerId in printers) {
123
+ var printerInfo = printers[printerId];
124
+ var option = document.createElement('option');
125
+ option.value = printerId;
126
+ // Display friendly name if available, otherwise use ID
127
+ option.text = printerInfo.printer_name || printerId;
128
+ if (printerId === selectedPrinter) {
129
+ option.selected = true;
130
+ }
131
+ printerSelect.appendChild(option);
132
+ }
133
+ }
134
+ }
135
+
136
+ // Initialize printers if lab is pre-selected
137
+ document.addEventListener('DOMContentLoaded', function() {
138
+ var labSelect = document.getElementById('lab-select');
139
+ if (labSelect.value) {
140
+ updatePrinters();
141
+ }
142
+ });
143
+ </script>
144
+ {% endblock %}
145
+
@@ -0,0 +1,88 @@
1
+ {% extends "modern/base.html" %}
2
+
3
+ {% block title %}Print Result - Zebra Day{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="page-header">
7
+ <h1 class="page-title">Print Result</h1>
8
+ <p class="page-subtitle">Label print request completed</p>
9
+ </div>
10
+
11
+ <div class="grid grid-2">
12
+ <!-- Result Card -->
13
+ <div class="card">
14
+ <div class="card-header">
15
+ <h3 class="card-title">
16
+ {% if success %}
17
+ <i class="fas fa-check-circle text-success"></i> Success
18
+ {% else %}
19
+ <i class="fas fa-times-circle text-error"></i> Failed
20
+ {% endif %}
21
+ </h3>
22
+ </div>
23
+
24
+ {% if success %}
25
+ <p class="mb-lg">Your label has been sent to the printer successfully.</p>
26
+ {% else %}
27
+ <p class="mb-lg text-error">{{ error_message | default('An error occurred while printing.') }}</p>
28
+ {% endif %}
29
+
30
+ {% if full_url %}
31
+ <div class="form-group">
32
+ <label class="form-label">Request URL</label>
33
+ <div class="d-flex gap-sm">
34
+ <input type="text" class="form-control" value="{{ full_url }}" readonly id="request-url">
35
+ <button type="button" class="btn btn-outline btn-sm" onclick="copyToClipboard(document.getElementById('request-url').value)">
36
+ <i class="fas fa-copy"></i>
37
+ </button>
38
+ </div>
39
+ <small class="text-muted">Save this URL to quickly repeat this print request</small>
40
+ </div>
41
+ {% endif %}
42
+
43
+ <div class="quick-actions mt-lg">
44
+ <a href="/print" class="action-card">
45
+ <i class="fas fa-print"></i>
46
+ <div>
47
+ <strong>Print Another</strong>
48
+ <small class="text-muted d-block">New print request</small>
49
+ </div>
50
+ </a>
51
+ <a href="/" class="action-card">
52
+ <i class="fas fa-home"></i>
53
+ <div>
54
+ <strong>Dashboard</strong>
55
+ <small class="text-muted d-block">Go back home</small>
56
+ </div>
57
+ </a>
58
+ </div>
59
+ </div>
60
+
61
+ <!-- Preview Card -->
62
+ {% if png_url %}
63
+ <div class="card">
64
+ <div class="card-header">
65
+ <h3 class="card-title">Label Preview</h3>
66
+ <a href="{{ png_url }}" target="_blank" class="btn btn-outline btn-sm">
67
+ <i class="fas fa-external-link-alt"></i> Open Full Size
68
+ </a>
69
+ </div>
70
+ <div style="text-align: center; background: var(--color-white); padding: var(--spacing-lg); border-radius: var(--radius-md);">
71
+ <img src="{{ png_url }}" alt="Label preview" style="max-width: 100%; height: auto;">
72
+ </div>
73
+ </div>
74
+ {% else %}
75
+ <div class="card">
76
+ <div class="card-header">
77
+ <h3 class="card-title">Label Preview</h3>
78
+ </div>
79
+ <div class="empty-state">
80
+ <i class="fas fa-image"></i>
81
+ <p>Preview sent directly to printer</p>
82
+ <small class="text-muted">PNG preview is only available when using the dl_png virtual printer</small>
83
+ </div>
84
+ </div>
85
+ {% endif %}
86
+ </div>
87
+ {% endblock %}
88
+
@@ -0,0 +1,244 @@
1
+ {% extends "modern/base.html" %}
2
+
3
+ {% block title %}{{ printer_name }} - Zebra Day{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="page-header">
7
+ <h1 class="page-title">{{ printer_name }}</h1>
8
+ <p class="page-subtitle">Printer details for {{ lab_name | default(lab) }}</p>
9
+ </div>
10
+
11
+ <!-- Breadcrumb -->
12
+ <div class="mb-lg">
13
+ <a href="/" class="text-muted">Dashboard</a>
14
+ <span class="text-muted"> / </span>
15
+ <a href="/printers">Printers</a>
16
+ <span class="text-muted"> / </span>
17
+ <a href="/printers/{{ lab }}">{{ lab_name | default(lab) }}</a>
18
+ <span class="text-muted"> / </span>
19
+ <span>{{ printer_name }}</span>
20
+ </div>
21
+
22
+ <div class="grid grid-2">
23
+ <!-- Printer Info -->
24
+ <div class="card">
25
+ <div class="card-header">
26
+ <h3 class="card-title">Printer Information</h3>
27
+ {% if printer_info.ip_address != 'dl_png' %}
28
+ <a href="http://{{ printer_info.ip_address }}" target="_blank" class="btn btn-outline btn-sm">
29
+ <i class="fas fa-external-link-alt"></i> Web Interface
30
+ </a>
31
+ {% endif %}
32
+ </div>
33
+ <table class="table" style="background: transparent; box-shadow: none;">
34
+ <tbody>
35
+ <tr>
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>
61
+ <td>
62
+ {% if printer_info.ip_address != 'dl_png' %}
63
+ <a href="http://{{ printer_info.ip_address }}" target="_blank">{{ printer_info.ip_address }}</a>
64
+ {% else %}
65
+ {{ printer_info.ip_address }}
66
+ {% endif %}
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 %}
77
+ <span class="badge badge-primary">{{ style }}</span>
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>
86
+ {% else %}
87
+ <span class="text-muted">{{ printer_info.label_zpl_styles[0] if printer_info.label_zpl_styles else 'None' }} (first in list)</span>
88
+ {% endif %}
89
+ </td>
90
+ </tr>
91
+ {% if printer_info.notes %}
92
+ <tr>
93
+ <td><strong>Notes</strong></td>
94
+ <td>{{ printer_info.notes }}</td>
95
+ </tr>
96
+ {% endif %}
97
+ </tbody>
98
+ </table>
99
+ </div>
100
+
101
+ <!-- Edit Printer Settings -->
102
+ <div class="card">
103
+ <div class="card-header">
104
+ <h3 class="card-title">Edit Settings</h3>
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>
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Printer Configuration -->
182
+ {% if printer_config %}
183
+ <div class="card mt-lg">
184
+ <div class="card-header">
185
+ <h3 class="card-title">Printer Configuration</h3>
186
+ <button class="btn btn-outline btn-sm" onclick="copyToClipboard(document.getElementById('printer-config').textContent)">
187
+ <i class="fas fa-copy"></i> Copy
188
+ </button>
189
+ </div>
190
+ <pre id="printer-config">{{ printer_config }}</pre>
191
+ </div>
192
+ {% endif %}
193
+
194
+ <!-- Test Print Section -->
195
+ <div class="card mt-lg">
196
+ <div class="card-header">
197
+ <h3 class="card-title">Test Print</h3>
198
+ </div>
199
+ <p class="text-muted mb-lg">Send a test label to verify the printer is working correctly.</p>
200
+ <div class="grid grid-3">
201
+ {% for style in printer_info.label_zpl_styles[:6] %}
202
+ <a href="/print?lab={{ lab }}&printer={{ printer_id }}&template={{ style }}&test=1" class="action-card">
203
+ <i class="fas fa-tag"></i>
204
+ <div>
205
+ <strong>{{ style }}</strong>
206
+ <small class="text-muted d-block">Test print</small>
207
+ </div>
208
+ </a>
209
+ {% endfor %}
210
+ </div>
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>
243
+ {% endblock %}
244
+