zebra-day 2.0.0__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 +21 -16
- 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 +7 -1
- zebra_day/etc/printer_config.template.json +3 -17
- zebra_day/etc/tmp_printers139.json +10 -0
- zebra_day/etc/tmp_printers147.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_printers508.json +10 -0
- zebra_day/etc/tmp_printers543.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/exceptions.py +1 -1
- zebra_day/files/corners_smallTube_preview.png +0 -0
- zebra_day/files/test_png_2897.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_56349.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_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_9572.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 +165 -145
- zebra_day/templates/modern/config.html +7 -0
- zebra_day/templates/modern/print_request.html +61 -3
- zebra_day/web/__init__.py +1 -1
- zebra_day/web/app.py +21 -16
- 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 +192 -43
- zebra_day/web/routers/ui.py +31 -33
- zebra_day/zpl_renderer.py +45 -34
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/METADATA +76 -67
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/RECORD +101 -29
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {zebra_day-2.0.0.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
zebra_day/__init__.py
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
zebra_day - A Python library to manage Zebra printer fleets and ZPL print requests.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
from __future__ import annotations
|
|
5
6
|
|
|
7
|
+
try:
|
|
8
|
+
from zebra_day._version import __version__
|
|
9
|
+
except ImportError:
|
|
10
|
+
__version__ = "0.0.0.dev0"
|
|
11
|
+
|
|
6
12
|
from zebra_day.exceptions import (
|
|
7
13
|
ConfigError,
|
|
8
14
|
ConfigFileNotFoundError,
|
|
@@ -18,10 +24,9 @@ from zebra_day.exceptions import (
|
|
|
18
24
|
from zebra_day.logging_config import configure_logging, get_logger
|
|
19
25
|
|
|
20
26
|
__all__ = [
|
|
21
|
-
|
|
27
|
+
"__version__",
|
|
22
28
|
"configure_logging",
|
|
23
29
|
"get_logger",
|
|
24
|
-
# Exceptions
|
|
25
30
|
"ZebraDayError",
|
|
26
31
|
"PrinterConnectionError",
|
|
27
32
|
"PrinterNotFoundError",
|
zebra_day/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.4"
|
zebra_day/cli/__init__.py
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"""zebra_day CLI - Zebra Printer Fleet Management CLI using Typer."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import os
|
|
6
|
+
import socket
|
|
4
7
|
import sys
|
|
5
|
-
from
|
|
6
|
-
from typing import Optional
|
|
8
|
+
from typing import Any
|
|
7
9
|
|
|
8
10
|
import typer
|
|
9
11
|
from rich.console import Console
|
|
10
12
|
from rich.table import Table
|
|
11
13
|
|
|
12
14
|
from zebra_day import paths as xdg
|
|
15
|
+
from zebra_day.cli.cognito import cognito_app
|
|
13
16
|
from zebra_day.cli.gui import gui_app
|
|
14
17
|
from zebra_day.cli.printer import printer_app
|
|
15
18
|
from zebra_day.cli.template import template_app
|
|
16
|
-
from zebra_day.cli.cognito import cognito_app
|
|
17
19
|
|
|
18
20
|
console = Console()
|
|
19
21
|
|
|
@@ -35,6 +37,7 @@ def _get_version() -> str:
|
|
|
35
37
|
"""Get zebra_day version."""
|
|
36
38
|
try:
|
|
37
39
|
from importlib.metadata import version
|
|
40
|
+
|
|
38
41
|
return version("zebra_day")
|
|
39
42
|
except Exception:
|
|
40
43
|
return "dev"
|
|
@@ -92,7 +95,7 @@ def status(
|
|
|
92
95
|
"""Show printer fleet status, network connectivity, and service health."""
|
|
93
96
|
import json as json_mod
|
|
94
97
|
|
|
95
|
-
status_data = {
|
|
98
|
+
status_data: dict[str, dict[str, Any]] = {
|
|
96
99
|
"gui_server": {"running": False, "pid": None, "url": None},
|
|
97
100
|
"printers": {"configured": 0, "labs": []},
|
|
98
101
|
"config": {"exists": False, "path": None},
|
|
@@ -117,14 +120,12 @@ def status(
|
|
|
117
120
|
status_data["config"]["exists"] = True
|
|
118
121
|
try:
|
|
119
122
|
import zebra_day.print_mgr as zdpm
|
|
123
|
+
|
|
120
124
|
zp = zdpm.zpl()
|
|
121
125
|
if hasattr(zp, "printers") and "labs" in zp.printers:
|
|
122
126
|
labs = list(zp.printers["labs"].keys())
|
|
123
127
|
status_data["printers"]["labs"] = labs
|
|
124
|
-
total_printers = sum(
|
|
125
|
-
len([k for k in zp.printers["labs"][lab].keys()])
|
|
126
|
-
for lab in labs
|
|
127
|
-
)
|
|
128
|
+
total_printers = sum(len(list(zp.printers["labs"][lab].keys())) for lab in labs)
|
|
128
129
|
status_data["printers"]["configured"] = total_printers
|
|
129
130
|
except Exception:
|
|
130
131
|
pass
|
|
@@ -136,25 +137,29 @@ def status(
|
|
|
136
137
|
# Human-readable output
|
|
137
138
|
console.print("\n[bold]Service Status[/bold]")
|
|
138
139
|
if status_data["gui_server"]["running"]:
|
|
139
|
-
console.print(
|
|
140
|
+
console.print(
|
|
141
|
+
f" [green]●[/green] GUI Server: [green]Running[/green] (PID {status_data['gui_server']['pid']})"
|
|
142
|
+
)
|
|
140
143
|
console.print(f" URL: [cyan]{status_data['gui_server']['url']}[/cyan]")
|
|
141
144
|
else:
|
|
142
145
|
console.print(" [dim]○[/dim] GUI Server: [dim]Not running[/dim]")
|
|
143
146
|
|
|
144
147
|
console.print("\n[bold]Printer Fleet[/bold]")
|
|
145
148
|
if status_data["config"]["exists"]:
|
|
146
|
-
console.print(
|
|
149
|
+
console.print(" [green]●[/green] Config: [green]Loaded[/green]")
|
|
147
150
|
console.print(f" Printers: {status_data['printers']['configured']}")
|
|
148
151
|
console.print(f" Labs: {', '.join(status_data['printers']['labs']) or 'none'}")
|
|
149
152
|
else:
|
|
150
153
|
console.print(" [yellow]○[/yellow] Config: [yellow]Not found[/yellow]")
|
|
151
|
-
console.print(
|
|
154
|
+
console.print(" Run [cyan]zday bootstrap[/cyan] to initialize")
|
|
152
155
|
console.print()
|
|
153
156
|
|
|
154
157
|
|
|
155
158
|
@app.command("bootstrap")
|
|
156
159
|
def bootstrap(
|
|
157
|
-
ip_stub:
|
|
160
|
+
ip_stub: str | None = typer.Option(
|
|
161
|
+
None, "--ip-stub", "-i", help="IP stub for printer scan (e.g., 192.168.1)"
|
|
162
|
+
),
|
|
158
163
|
skip_scan: bool = typer.Option(False, "--skip-scan", "-s", help="Skip printer network scan"),
|
|
159
164
|
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
160
165
|
):
|
|
@@ -166,20 +171,16 @@ def bootstrap(
|
|
|
166
171
|
3. Scan the network for Zebra printers (unless --skip-scan)
|
|
167
172
|
"""
|
|
168
173
|
import json as json_mod
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"data_dir": str(xdg.get_data_dir()),
|
|
175
|
-
"printers_found": 0,
|
|
176
|
-
"labs": [],
|
|
177
|
-
}
|
|
174
|
+
|
|
175
|
+
config_dir = str(xdg.get_config_dir())
|
|
176
|
+
data_dir = str(xdg.get_data_dir())
|
|
177
|
+
printers_found = 0
|
|
178
|
+
labs: list[str] = []
|
|
178
179
|
|
|
179
180
|
if not json_output:
|
|
180
181
|
console.print("\n[bold cyan]zebra_day Bootstrap[/bold cyan]\n")
|
|
181
|
-
console.print("[green]✓[/green] Config directory: " +
|
|
182
|
-
console.print("[green]✓[/green] Data directory: " +
|
|
182
|
+
console.print("[green]✓[/green] Config directory: " + config_dir)
|
|
183
|
+
console.print("[green]✓[/green] Data directory: " + data_dir)
|
|
183
184
|
|
|
184
185
|
if skip_scan:
|
|
185
186
|
if not json_output:
|
|
@@ -202,24 +203,74 @@ def bootstrap(
|
|
|
202
203
|
|
|
203
204
|
try:
|
|
204
205
|
import zebra_day.print_mgr as zdpm
|
|
206
|
+
|
|
205
207
|
zp = zdpm.zpl()
|
|
206
208
|
zp.probe_zebra_printers_add_to_printers_json(ip_stub=ip_stub)
|
|
207
209
|
|
|
208
210
|
if hasattr(zp, "printers") and "labs" in zp.printers:
|
|
209
211
|
for lab in zp.printers["labs"]:
|
|
210
|
-
printers_in_lab = len(
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
printers_in_lab = len(list(zp.printers["labs"][lab].keys()))
|
|
213
|
+
printers_found += printers_in_lab
|
|
214
|
+
labs.append(lab)
|
|
213
215
|
|
|
214
216
|
if not json_output:
|
|
215
|
-
console.print(f"[green]✓[/green] Scan complete: {
|
|
216
|
-
if
|
|
217
|
-
console.print(f" Labs: {', '.join(
|
|
217
|
+
console.print(f"[green]✓[/green] Scan complete: {printers_found} printer(s) found")
|
|
218
|
+
if labs:
|
|
219
|
+
console.print(f" Labs: {', '.join(labs)}")
|
|
218
220
|
except Exception as e:
|
|
219
221
|
if not json_output:
|
|
220
222
|
console.print(f"[yellow]⚠[/yellow] Scan error: {e}")
|
|
221
223
|
|
|
224
|
+
# Generate HTTPS certificates if mkcert is available
|
|
225
|
+
certs_generated = False
|
|
226
|
+
cert_path_str = None
|
|
227
|
+
|
|
228
|
+
if not json_output:
|
|
229
|
+
console.print("\n[cyan]→[/cyan] Checking HTTPS certificates...")
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
from zebra_day import mkcert
|
|
233
|
+
|
|
234
|
+
if not mkcert.is_mkcert_installed():
|
|
235
|
+
if not json_output:
|
|
236
|
+
console.print("[yellow]⚠[/yellow] mkcert not installed")
|
|
237
|
+
console.print(
|
|
238
|
+
" Install with: [dim]brew install mkcert[/dim] (macOS) or "
|
|
239
|
+
"[dim]sudo apt install mkcert[/dim] (Ubuntu)"
|
|
240
|
+
)
|
|
241
|
+
elif not mkcert.is_ca_installed():
|
|
242
|
+
if not json_output:
|
|
243
|
+
console.print("[yellow]⚠[/yellow] mkcert CA not installed")
|
|
244
|
+
console.print(" Run: [dim]mkcert -install[/dim] (one-time, requires password)")
|
|
245
|
+
elif mkcert.certificates_exist():
|
|
246
|
+
if not json_output:
|
|
247
|
+
console.print(f"[green]✓[/green] Certificates exist: {mkcert.CERT_FILE}")
|
|
248
|
+
certs_generated = True
|
|
249
|
+
cert_path_str = str(mkcert.CERT_FILE)
|
|
250
|
+
else:
|
|
251
|
+
if not json_output:
|
|
252
|
+
console.print(" Generating certificates...")
|
|
253
|
+
if mkcert.generate_certificates():
|
|
254
|
+
if not json_output:
|
|
255
|
+
console.print(f"[green]✓[/green] Certificates generated: {mkcert.CERT_FILE}")
|
|
256
|
+
certs_generated = True
|
|
257
|
+
cert_path_str = str(mkcert.CERT_FILE)
|
|
258
|
+
else:
|
|
259
|
+
if not json_output:
|
|
260
|
+
console.print("[yellow]⚠[/yellow] Failed to generate certificates")
|
|
261
|
+
except Exception as e:
|
|
262
|
+
if not json_output:
|
|
263
|
+
console.print(f"[yellow]⚠[/yellow] Certificate check error: {e}")
|
|
264
|
+
|
|
222
265
|
if json_output:
|
|
266
|
+
result = {
|
|
267
|
+
"config_dir": config_dir,
|
|
268
|
+
"data_dir": data_dir,
|
|
269
|
+
"printers_found": printers_found,
|
|
270
|
+
"labs": labs,
|
|
271
|
+
"https_certs_generated": certs_generated,
|
|
272
|
+
"cert_path": cert_path_str,
|
|
273
|
+
}
|
|
223
274
|
console.print(json_mod.dumps(result, indent=2))
|
|
224
275
|
else:
|
|
225
276
|
console.print("\n[bold green]✓ Bootstrap complete![/bold green]")
|
|
@@ -237,4 +288,3 @@ def main():
|
|
|
237
288
|
|
|
238
289
|
if __name__ == "__main__":
|
|
239
290
|
raise SystemExit(main())
|
|
240
|
-
|
zebra_day/cli/cognito.py
CHANGED
|
@@ -5,7 +5,6 @@ basic status and info commands.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import typer
|
|
11
10
|
from rich.console import Console
|
|
@@ -18,6 +17,7 @@ def _is_cognito_available() -> bool:
|
|
|
18
17
|
"""Check if daylily-cognito is installed."""
|
|
19
18
|
try:
|
|
20
19
|
from daylily_cognito.cli import cognito_app as _ # noqa: F401
|
|
20
|
+
|
|
21
21
|
return True
|
|
22
22
|
except ImportError:
|
|
23
23
|
return False
|
|
@@ -28,7 +28,8 @@ def _get_cognito_app() -> typer.Typer:
|
|
|
28
28
|
if _is_cognito_available():
|
|
29
29
|
# Import and return the full cognito CLI from daylily-cognito
|
|
30
30
|
from daylily_cognito.cli import cognito_app
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
return cognito_app # type: ignore[no-any-return]
|
|
32
33
|
else:
|
|
33
34
|
# Return a minimal fallback app
|
|
34
35
|
return _create_fallback_app()
|
|
@@ -36,7 +37,9 @@ def _get_cognito_app() -> typer.Typer:
|
|
|
36
37
|
|
|
37
38
|
def _create_fallback_app() -> typer.Typer:
|
|
38
39
|
"""Create a fallback cognito app with basic commands."""
|
|
39
|
-
app = typer.Typer(
|
|
40
|
+
app = typer.Typer(
|
|
41
|
+
help="Cognito authentication management (limited - daylily-cognito not installed)"
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
@app.command("status")
|
|
42
45
|
def status():
|
|
@@ -76,7 +79,9 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
76
79
|
console.print(" Start server with: [cyan]zday gui start --auth cognito[/cyan]")
|
|
77
80
|
else:
|
|
78
81
|
console.print("\n[yellow]⚠[/yellow] Cognito is not fully configured")
|
|
79
|
-
console.print(
|
|
82
|
+
console.print(
|
|
83
|
+
" Set environment variables or install daylily-cognito for full management"
|
|
84
|
+
)
|
|
80
85
|
|
|
81
86
|
@app.command("info")
|
|
82
87
|
def info():
|
|
@@ -85,7 +90,7 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
85
90
|
console.print("To enable Cognito authentication for zebra_day:\n")
|
|
86
91
|
|
|
87
92
|
console.print("[bold]1. Install auth dependencies:[/bold]")
|
|
88
|
-
console.print(
|
|
93
|
+
console.print(' [cyan]pip install -e ".[auth]"[/cyan]\n')
|
|
89
94
|
|
|
90
95
|
console.print("[bold]2. Set environment variables:[/bold]")
|
|
91
96
|
console.print(" [cyan]export COGNITO_USER_POOL_ID=your-pool-id[/cyan]")
|
|
@@ -96,21 +101,23 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
96
101
|
console.print(" [cyan]zday gui start --auth cognito[/cyan]\n")
|
|
97
102
|
|
|
98
103
|
if not _is_cognito_available():
|
|
99
|
-
console.print(
|
|
104
|
+
console.print(
|
|
105
|
+
"[dim]For full Cognito management (create, teardown), install daylily-cognito:[/dim]"
|
|
106
|
+
)
|
|
100
107
|
console.print("[dim] pip install daylily-cognito[/dim]")
|
|
101
108
|
|
|
102
109
|
@app.command("create")
|
|
103
110
|
def create():
|
|
104
111
|
"""Create/configure a Cognito user pool (requires daylily-cognito)."""
|
|
105
112
|
console.print("[yellow]⚠[/yellow] This command requires daylily-cognito")
|
|
106
|
-
console.print(
|
|
113
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
107
114
|
raise typer.Exit(1)
|
|
108
115
|
|
|
109
116
|
@app.command("teardown")
|
|
110
117
|
def teardown():
|
|
111
118
|
"""Remove Cognito configuration (requires daylily-cognito)."""
|
|
112
119
|
console.print("[yellow]⚠[/yellow] This command requires daylily-cognito")
|
|
113
|
-
console.print(
|
|
120
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
114
121
|
raise typer.Exit(1)
|
|
115
122
|
|
|
116
123
|
return app
|
|
@@ -118,4 +125,3 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
118
125
|
|
|
119
126
|
# Export the cognito app - either the full version from daylily-cognito or the fallback
|
|
120
127
|
cognito_app = _get_cognito_app()
|
|
121
|
-
|
zebra_day/cli/gui.py
CHANGED
|
@@ -7,7 +7,6 @@ import sys
|
|
|
7
7
|
import time
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Optional, Literal
|
|
11
10
|
|
|
12
11
|
import typer
|
|
13
12
|
from rich.console import Console
|
|
@@ -39,13 +38,13 @@ def _get_log_file() -> Path:
|
|
|
39
38
|
return LOG_DIR / f"gui_{ts}.log"
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
def _get_latest_log() ->
|
|
41
|
+
def _get_latest_log() -> Path | None:
|
|
43
42
|
"""Get the most recent log file."""
|
|
44
43
|
logs = sorted(LOG_DIR.glob("gui_*.log"), reverse=True)
|
|
45
44
|
return logs[0] if logs else None
|
|
46
45
|
|
|
47
46
|
|
|
48
|
-
def _get_pid() ->
|
|
47
|
+
def _get_pid() -> int | None:
|
|
49
48
|
"""Get the running server PID if exists."""
|
|
50
49
|
if PID_FILE.exists():
|
|
51
50
|
try:
|
|
@@ -61,14 +60,13 @@ def _check_auth_dependencies() -> bool:
|
|
|
61
60
|
"""Check if auth dependencies are available."""
|
|
62
61
|
try:
|
|
63
62
|
import jose # noqa: F401
|
|
63
|
+
|
|
64
64
|
return True
|
|
65
65
|
except ImportError:
|
|
66
66
|
return False
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
def _resolve_ssl_paths(
|
|
70
|
-
cert: Optional[str], key: Optional[str]
|
|
71
|
-
) -> tuple[Optional[str], Optional[str], bool]:
|
|
69
|
+
def _resolve_ssl_paths(cert: str | None, key: str | None) -> tuple[str | None, str | None, bool]:
|
|
72
70
|
"""
|
|
73
71
|
Resolve SSL certificate and key paths.
|
|
74
72
|
|
|
@@ -109,10 +107,14 @@ def start(
|
|
|
109
107
|
host: str = typer.Option("0.0.0.0", "--host", "-h", help="Host to bind to"),
|
|
110
108
|
auth: str = typer.Option("none", "--auth", "-a", help="Authentication mode: none or cognito"),
|
|
111
109
|
reload: bool = typer.Option(False, "--reload", "-r", help="Enable auto-reload (foreground)"),
|
|
112
|
-
background: bool = typer.Option(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
background: bool = typer.Option(
|
|
111
|
+
True, "--background/--foreground", "-b/-f", help="Run in background"
|
|
112
|
+
),
|
|
113
|
+
cert: str | None = typer.Option(None, "--cert", help="Path to SSL certificate file"),
|
|
114
|
+
key: str | None = typer.Option(None, "--key", help="Path to SSL private key file"),
|
|
115
|
+
no_https: bool = typer.Option(
|
|
116
|
+
False, "--no-https", help="Disable HTTPS even if certificates are available"
|
|
117
|
+
),
|
|
116
118
|
):
|
|
117
119
|
"""Start the zebra_day web UI server.
|
|
118
120
|
|
|
@@ -141,7 +143,7 @@ def start(
|
|
|
141
143
|
if auth == "cognito":
|
|
142
144
|
if not _check_auth_dependencies():
|
|
143
145
|
console.print("[red]✗[/red] Authentication requested but python-jose is not installed")
|
|
144
|
-
console.print(
|
|
146
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
145
147
|
raise typer.Exit(1)
|
|
146
148
|
|
|
147
149
|
# Check required env vars
|
|
@@ -168,14 +170,16 @@ def start(
|
|
|
168
170
|
protocol = "https" if use_https else "http"
|
|
169
171
|
|
|
170
172
|
if use_https:
|
|
171
|
-
console.print(
|
|
173
|
+
console.print("[green]✓[/green] HTTPS enabled")
|
|
172
174
|
console.print(f" Certificate: [dim]{cert_path}[/dim]")
|
|
173
175
|
console.print(f" Private key: [dim]{key_path}[/dim]")
|
|
174
176
|
else:
|
|
175
177
|
console.print("[yellow]⚠[/yellow] Running in HTTP mode (insecure)")
|
|
176
178
|
console.print(" For HTTPS, generate certificates with mkcert:")
|
|
177
179
|
console.print(f" [dim]mkdir -p {DEFAULT_CERT_DIR}[/dim]")
|
|
178
|
-
console.print(
|
|
180
|
+
console.print(
|
|
181
|
+
f" [dim]mkcert -cert-file {DEFAULT_CERT_FILE} -key-file {DEFAULT_KEY_FILE} localhost 127.0.0.1 ::1[/dim]"
|
|
182
|
+
)
|
|
179
183
|
|
|
180
184
|
# Build command with SSL parameters
|
|
181
185
|
ssl_args = ""
|
|
@@ -232,7 +236,9 @@ def start(
|
|
|
232
236
|
console.print(f" URL: [cyan]{protocol}://{host}:{port}[/cyan]")
|
|
233
237
|
console.print(f" Logs: [dim]{log_file}[/dim]")
|
|
234
238
|
else:
|
|
235
|
-
console.print(
|
|
239
|
+
console.print(
|
|
240
|
+
f"[green]✓[/green] Starting server on [cyan]{protocol}://{host}:{port}[/cyan]"
|
|
241
|
+
)
|
|
236
242
|
console.print(" Press Ctrl+C to stop\n")
|
|
237
243
|
try:
|
|
238
244
|
result = subprocess.run(cmd, cwd=Path.cwd(), env=env)
|
|
@@ -268,7 +274,7 @@ def stop():
|
|
|
268
274
|
console.print("[yellow]⚠[/yellow] Server was not running")
|
|
269
275
|
except PermissionError:
|
|
270
276
|
console.print(f"[red]✗[/red] Permission denied stopping PID {pid}")
|
|
271
|
-
raise typer.Exit(1)
|
|
277
|
+
raise typer.Exit(1) from None
|
|
272
278
|
|
|
273
279
|
|
|
274
280
|
@gui_app.command("status")
|
|
@@ -335,4 +341,3 @@ def restart(
|
|
|
335
341
|
stop()
|
|
336
342
|
time.sleep(1)
|
|
337
343
|
start(port=port, host=host, auth=auth, reload=False, background=True)
|
|
338
|
-
|
zebra_day/cli/printer.py
CHANGED
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import socket
|
|
5
|
-
from typing import Optional
|
|
6
5
|
|
|
7
6
|
import typer
|
|
8
7
|
from rich.console import Console
|
|
9
8
|
from rich.table import Table
|
|
10
9
|
|
|
11
|
-
from zebra_day import paths as xdg
|
|
12
|
-
|
|
13
10
|
printer_app = typer.Typer(help="Printer fleet management commands")
|
|
14
11
|
console = Console()
|
|
15
12
|
|
|
@@ -19,7 +16,7 @@ def _get_local_ip() -> str:
|
|
|
19
16
|
try:
|
|
20
17
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
21
18
|
s.connect(("8.8.8.8", 80))
|
|
22
|
-
ip = s.getsockname()[0]
|
|
19
|
+
ip: str = s.getsockname()[0]
|
|
23
20
|
s.close()
|
|
24
21
|
return ip
|
|
25
22
|
except Exception:
|
|
@@ -28,9 +25,13 @@ def _get_local_ip() -> str:
|
|
|
28
25
|
|
|
29
26
|
@printer_app.command("scan")
|
|
30
27
|
def scan(
|
|
31
|
-
ip_stub:
|
|
28
|
+
ip_stub: str | None = typer.Option(
|
|
29
|
+
None, "--ip-stub", "-i", help="IP stub to scan (e.g., 192.168.1)"
|
|
30
|
+
),
|
|
32
31
|
wait: float = typer.Option(0.25, "--wait", "-w", help="Seconds to wait per IP probe"),
|
|
33
|
-
lab: str = typer.Option(
|
|
32
|
+
lab: str = typer.Option(
|
|
33
|
+
"scan-results", "--lab", "-l", help="Lab name to assign found printers"
|
|
34
|
+
),
|
|
34
35
|
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
35
36
|
):
|
|
36
37
|
"""Scan network for Zebra printers."""
|
|
@@ -45,6 +46,7 @@ def scan(
|
|
|
45
46
|
|
|
46
47
|
try:
|
|
47
48
|
import zebra_day.print_mgr as zdpm
|
|
49
|
+
|
|
48
50
|
zp = zdpm.zpl()
|
|
49
51
|
zp.probe_zebra_printers_add_to_printers_json(
|
|
50
52
|
ip_stub=ip_stub,
|
|
@@ -56,12 +58,14 @@ def scan(
|
|
|
56
58
|
if hasattr(zp, "printers") and "labs" in zp.printers and lab in zp.printers["labs"]:
|
|
57
59
|
for name, info in zp.printers["labs"][lab].items():
|
|
58
60
|
if isinstance(info, dict) and info.get("ip_address") not in ["dl_png"]:
|
|
59
|
-
found.append(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
found.append(
|
|
62
|
+
{
|
|
63
|
+
"name": name,
|
|
64
|
+
"ip": info.get("ip_address"),
|
|
65
|
+
"model": info.get("model", "unknown"),
|
|
66
|
+
"serial": info.get("serial", "unknown"),
|
|
67
|
+
}
|
|
68
|
+
)
|
|
65
69
|
|
|
66
70
|
if json_output:
|
|
67
71
|
console.print(json.dumps(found, indent=2))
|
|
@@ -82,17 +86,18 @@ def scan(
|
|
|
82
86
|
console.print(json.dumps({"error": str(e)}))
|
|
83
87
|
else:
|
|
84
88
|
console.print(f"[red]✗[/red] Scan error: {e}")
|
|
85
|
-
raise typer.Exit(1)
|
|
89
|
+
raise typer.Exit(1) from None
|
|
86
90
|
|
|
87
91
|
|
|
88
92
|
@printer_app.command("list")
|
|
89
93
|
def list_printers(
|
|
90
|
-
lab:
|
|
94
|
+
lab: str | None = typer.Option(None, "--lab", "-l", help="Filter by lab name"),
|
|
91
95
|
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
92
96
|
):
|
|
93
97
|
"""List configured printers."""
|
|
94
98
|
try:
|
|
95
99
|
import zebra_day.print_mgr as zdpm
|
|
100
|
+
|
|
96
101
|
zp = zdpm.zpl()
|
|
97
102
|
|
|
98
103
|
printers = []
|
|
@@ -102,13 +107,15 @@ def list_printers(
|
|
|
102
107
|
continue
|
|
103
108
|
for name, info in lab_printers.items():
|
|
104
109
|
if isinstance(info, dict):
|
|
105
|
-
printers.append(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
printers.append(
|
|
111
|
+
{
|
|
112
|
+
"lab": lab_name,
|
|
113
|
+
"name": name,
|
|
114
|
+
"ip": info.get("ip_address", "unknown"),
|
|
115
|
+
"model": info.get("model", "unknown"),
|
|
116
|
+
"styles": info.get("label_zpl_styles", []),
|
|
117
|
+
}
|
|
118
|
+
)
|
|
112
119
|
|
|
113
120
|
if json_output:
|
|
114
121
|
console.print(json.dumps(printers, indent=2))
|
|
@@ -128,7 +135,7 @@ def list_printers(
|
|
|
128
135
|
for p in printers:
|
|
129
136
|
styles = ", ".join(p["styles"][:2])
|
|
130
137
|
if len(p["styles"]) > 2:
|
|
131
|
-
styles += f" (+{len(p['styles'])-2})"
|
|
138
|
+
styles += f" (+{len(p['styles']) - 2})"
|
|
132
139
|
table.add_row(p["lab"], p["name"], p["ip"], p["model"], styles)
|
|
133
140
|
console.print(table)
|
|
134
141
|
|
|
@@ -137,7 +144,7 @@ def list_printers(
|
|
|
137
144
|
console.print(json.dumps({"error": str(e)}))
|
|
138
145
|
else:
|
|
139
146
|
console.print(f"[red]✗[/red] Error: {e}")
|
|
140
|
-
raise typer.Exit(1)
|
|
147
|
+
raise typer.Exit(1) from None
|
|
141
148
|
|
|
142
149
|
|
|
143
150
|
@printer_app.command("test")
|
|
@@ -149,10 +156,11 @@ def test_print(
|
|
|
149
156
|
"""Send a test print to a specific printer."""
|
|
150
157
|
try:
|
|
151
158
|
import zebra_day.print_mgr as zdpm
|
|
159
|
+
|
|
152
160
|
zp = zdpm.zpl()
|
|
153
161
|
|
|
154
162
|
console.print(f"[cyan]→[/cyan] Sending test print to {printer_name}...")
|
|
155
|
-
|
|
163
|
+
zp.print_zpl(
|
|
156
164
|
lab=lab,
|
|
157
165
|
printer_name=printer_name,
|
|
158
166
|
uid_barcode="TEST-PRINT",
|
|
@@ -160,9 +168,8 @@ def test_print(
|
|
|
160
168
|
alt_b="zebra_day CLI",
|
|
161
169
|
label_zpl_style=label_style,
|
|
162
170
|
)
|
|
163
|
-
console.print(
|
|
171
|
+
console.print("[green]✓[/green] Test print sent successfully")
|
|
164
172
|
|
|
165
173
|
except Exception as e:
|
|
166
174
|
console.print(f"[red]✗[/red] Print error: {e}")
|
|
167
|
-
raise typer.Exit(1)
|
|
168
|
-
|
|
175
|
+
raise typer.Exit(1) from None
|