seizu-cli 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.
- seizu_cli/__init__.py +0 -0
- seizu_cli/__main__.py +4 -0
- seizu_cli/auth.py +365 -0
- seizu_cli/client.py +62 -0
- seizu_cli/commands/__init__.py +0 -0
- seizu_cli/commands/auth.py +84 -0
- seizu_cli/commands/reports.py +223 -0
- seizu_cli/commands/scheduled_queries.py +157 -0
- seizu_cli/commands/seed.py +852 -0
- seizu_cli/commands/skillsets.py +371 -0
- seizu_cli/commands/toolsets.py +506 -0
- seizu_cli/config.py +38 -0
- seizu_cli/main.py +181 -0
- seizu_cli/schema.py +31 -0
- seizu_cli/state.py +29 -0
- seizu_cli-2.0.0.dist-info/METADATA +13 -0
- seizu_cli-2.0.0.dist-info/RECORD +22 -0
- seizu_cli-2.0.0.dist-info/WHEEL +5 -0
- seizu_cli-2.0.0.dist-info/entry_points.txt +2 -0
- seizu_cli-2.0.0.dist-info/top_level.txt +2 -0
- seizu_schema/__init__.py +1 -0
- seizu_schema/reporting_config.py +939 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""CLI commands for managing reports."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from seizu_cli import state
|
|
12
|
+
from seizu_cli.client import APIError
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(help="Manage reports.", no_args_is_help=True)
|
|
15
|
+
console = Console()
|
|
16
|
+
err_console = Console(stderr=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _die(exc: Exception) -> None:
|
|
20
|
+
if isinstance(exc, APIError):
|
|
21
|
+
err_console.print(f"[red]Error {exc.status_code}[/red]: {exc}")
|
|
22
|
+
else:
|
|
23
|
+
err_console.print(f"[red]Error[/red]: {exc}")
|
|
24
|
+
sys.exit(1)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _print_report_detail(data: dict[str, Any], as_json: bool) -> None:
|
|
28
|
+
if as_json:
|
|
29
|
+
sanitized = dict(data)
|
|
30
|
+
sanitized.pop("query_capabilities", None)
|
|
31
|
+
console.print_json(json.dumps(sanitized))
|
|
32
|
+
return
|
|
33
|
+
console.print(f"[bold]ID[/bold]: {data['report_id']}")
|
|
34
|
+
console.print(f"[bold]Name[/bold]: {data['name']}")
|
|
35
|
+
console.print(f"[bold]Version[/bold]: {data['version']}")
|
|
36
|
+
console.print(f"[bold]Access[/bold]: {data.get('access', {}).get('scope', 'unknown')}")
|
|
37
|
+
console.print(f"[bold]Created By[/bold]: {data['created_by']}")
|
|
38
|
+
console.print(f"[bold]Created At[/bold]: {data['created_at']}")
|
|
39
|
+
if data.get("comment"):
|
|
40
|
+
console.print(f"[bold]Comment[/bold]: {data['comment']}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@app.command("list")
|
|
44
|
+
def list_reports(
|
|
45
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""List all reports."""
|
|
48
|
+
try:
|
|
49
|
+
data = state.get_client().get("/api/v1/reports")
|
|
50
|
+
except Exception as exc:
|
|
51
|
+
_die(exc)
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
if output == "json":
|
|
55
|
+
console.print_json(json.dumps(data))
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
reports = data.get("reports", [])
|
|
59
|
+
if not reports:
|
|
60
|
+
console.print("[dim]No reports found.[/dim]")
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
table = Table(show_header=True, header_style="bold")
|
|
64
|
+
table.add_column("ID")
|
|
65
|
+
table.add_column("Name")
|
|
66
|
+
table.add_column("Access")
|
|
67
|
+
table.add_column("Version", justify="right")
|
|
68
|
+
table.add_column("Updated At")
|
|
69
|
+
|
|
70
|
+
for r in reports:
|
|
71
|
+
table.add_row(
|
|
72
|
+
r["report_id"],
|
|
73
|
+
r["name"],
|
|
74
|
+
r.get("access", {}).get("scope", "unknown"),
|
|
75
|
+
str(r["current_version"]),
|
|
76
|
+
r["updated_at"],
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
console.print(table)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@app.command("get")
|
|
83
|
+
def get_report(
|
|
84
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
85
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Get the latest version of a report."""
|
|
88
|
+
try:
|
|
89
|
+
data = state.get_client().get(f"/api/v1/reports/{report_id}")
|
|
90
|
+
except Exception as exc:
|
|
91
|
+
_die(exc)
|
|
92
|
+
return
|
|
93
|
+
_print_report_detail(data, as_json=(output == "json"))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@app.command("create")
|
|
97
|
+
def create_report(
|
|
98
|
+
name: str = typer.Argument(help="Report name."),
|
|
99
|
+
) -> None:
|
|
100
|
+
"""Create a new empty report."""
|
|
101
|
+
try:
|
|
102
|
+
data = state.get_client().post("/api/v1/reports", json={"name": name})
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
_die(exc)
|
|
105
|
+
return
|
|
106
|
+
console.print(f"[green]Created[/green]: {data['report_id']} name={data['name']!r}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@app.command("clone")
|
|
110
|
+
def clone_report(
|
|
111
|
+
report_id: str = typer.Argument(help="Source report ID."),
|
|
112
|
+
name: str = typer.Argument(help="Name for the cloned report."),
|
|
113
|
+
) -> None:
|
|
114
|
+
"""Clone a report into a new report."""
|
|
115
|
+
try:
|
|
116
|
+
data = state.get_client().post(f"/api/v1/reports/{report_id}/clone", json={"name": name})
|
|
117
|
+
except Exception as exc:
|
|
118
|
+
_die(exc)
|
|
119
|
+
return
|
|
120
|
+
console.print(f"[green]Cloned[/green]: {data['report_id']} name={data['name']!r} source={report_id!r}")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@app.command("publish")
|
|
124
|
+
def publish_report(
|
|
125
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
126
|
+
) -> None:
|
|
127
|
+
"""Make a report public."""
|
|
128
|
+
try:
|
|
129
|
+
state.get_client().put(f"/api/v1/reports/{report_id}/visibility", json={"access": {"scope": "public"}})
|
|
130
|
+
except Exception as exc:
|
|
131
|
+
_die(exc)
|
|
132
|
+
return
|
|
133
|
+
console.print(f"[green]Published[/green]: {report_id}")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@app.command("unpublish")
|
|
137
|
+
def unpublish_report(
|
|
138
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Make a report private."""
|
|
141
|
+
try:
|
|
142
|
+
state.get_client().put(f"/api/v1/reports/{report_id}/visibility", json={"access": {"scope": "private"}})
|
|
143
|
+
except Exception as exc:
|
|
144
|
+
_die(exc)
|
|
145
|
+
return
|
|
146
|
+
console.print(f"[green]Unpublished[/green]: {report_id}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@app.command("delete")
|
|
150
|
+
def delete_report(
|
|
151
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
152
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
|
|
153
|
+
) -> None:
|
|
154
|
+
"""Delete a report and all its versions."""
|
|
155
|
+
if not yes:
|
|
156
|
+
typer.confirm(f"Delete report {report_id!r} and all its versions?", abort=True)
|
|
157
|
+
try:
|
|
158
|
+
state.get_client().delete(f"/api/v1/reports/{report_id}")
|
|
159
|
+
except Exception as exc:
|
|
160
|
+
_die(exc)
|
|
161
|
+
return
|
|
162
|
+
console.print(f"[red]Deleted[/red]: {report_id}")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@app.command("set-dashboard")
|
|
166
|
+
def set_dashboard(
|
|
167
|
+
report_id: str = typer.Argument(help="Report ID to set as the default dashboard."),
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Set a report as the default dashboard."""
|
|
170
|
+
try:
|
|
171
|
+
state.get_client().put(f"/api/v1/reports/{report_id}/dashboard")
|
|
172
|
+
except Exception as exc:
|
|
173
|
+
_die(exc)
|
|
174
|
+
return
|
|
175
|
+
console.print(f"[green]Dashboard set to[/green]: {report_id}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@app.command("versions")
|
|
179
|
+
def list_versions(
|
|
180
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
181
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
182
|
+
) -> None:
|
|
183
|
+
"""List all versions of a report."""
|
|
184
|
+
try:
|
|
185
|
+
data = state.get_client().get(f"/api/v1/reports/{report_id}/versions")
|
|
186
|
+
except Exception as exc:
|
|
187
|
+
_die(exc)
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
if output == "json":
|
|
191
|
+
console.print_json(json.dumps(data))
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
versions = data.get("versions", [])
|
|
195
|
+
table = Table(show_header=True, header_style="bold")
|
|
196
|
+
table.add_column("Version", justify="right")
|
|
197
|
+
table.add_column("Created By")
|
|
198
|
+
table.add_column("Created At")
|
|
199
|
+
table.add_column("Comment")
|
|
200
|
+
|
|
201
|
+
for v in versions:
|
|
202
|
+
table.add_row(
|
|
203
|
+
str(v["version"]),
|
|
204
|
+
v["created_by"],
|
|
205
|
+
v["created_at"],
|
|
206
|
+
v.get("comment") or "",
|
|
207
|
+
)
|
|
208
|
+
console.print(table)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@app.command("version-get")
|
|
212
|
+
def get_version(
|
|
213
|
+
report_id: str = typer.Argument(help="Report ID."),
|
|
214
|
+
version: int = typer.Argument(help="Version number."),
|
|
215
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
216
|
+
) -> None:
|
|
217
|
+
"""Get a specific version of a report."""
|
|
218
|
+
try:
|
|
219
|
+
data = state.get_client().get(f"/api/v1/reports/{report_id}/versions/{version}")
|
|
220
|
+
except Exception as exc:
|
|
221
|
+
_die(exc)
|
|
222
|
+
return
|
|
223
|
+
_print_report_detail(data, as_json=(output == "json"))
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""CLI commands for managing scheduled queries."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.table import Table
|
|
10
|
+
|
|
11
|
+
from seizu_cli import state
|
|
12
|
+
from seizu_cli.client import APIError
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(help="Manage scheduled queries.", no_args_is_help=True)
|
|
15
|
+
console = Console()
|
|
16
|
+
err_console = Console(stderr=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _die(exc: Exception) -> None:
|
|
20
|
+
if isinstance(exc, APIError):
|
|
21
|
+
err_console.print(f"[red]Error {exc.status_code}[/red]: {exc}")
|
|
22
|
+
else:
|
|
23
|
+
err_console.print(f"[red]Error[/red]: {exc}")
|
|
24
|
+
sys.exit(1)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _print_sq_detail(data: dict[str, Any], as_json: bool) -> None:
|
|
28
|
+
if as_json:
|
|
29
|
+
console.print_json(json.dumps(data))
|
|
30
|
+
return
|
|
31
|
+
console.print(f"[bold]ID[/bold]: {data['scheduled_query_id']}")
|
|
32
|
+
console.print(f"[bold]Name[/bold]: {data['name']}")
|
|
33
|
+
console.print(f"[bold]Enabled[/bold]: {data.get('enabled', True)}")
|
|
34
|
+
console.print(f"[bold]Frequency[/bold]: {data.get('frequency')}")
|
|
35
|
+
console.print(f"[bold]Version[/bold]: {data.get('current_version', data.get('version'))}")
|
|
36
|
+
console.print(f"[bold]Created By[/bold]: {data['created_by']}")
|
|
37
|
+
console.print(f"[bold]Updated By[/bold]: {data.get('updated_by', '')}")
|
|
38
|
+
console.print(f"[bold]Cypher[/bold]\n{data['cypher']}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.command("list")
|
|
42
|
+
def list_scheduled_queries(
|
|
43
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
44
|
+
) -> None:
|
|
45
|
+
"""List all scheduled queries."""
|
|
46
|
+
try:
|
|
47
|
+
data = state.get_client().get("/api/v1/scheduled-queries")
|
|
48
|
+
except Exception as exc:
|
|
49
|
+
_die(exc)
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
if output == "json":
|
|
53
|
+
console.print_json(json.dumps(data))
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
items = data.get("scheduled_queries", [])
|
|
57
|
+
if not items:
|
|
58
|
+
console.print("[dim]No scheduled queries found.[/dim]")
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
table = Table(show_header=True, header_style="bold")
|
|
62
|
+
table.add_column("ID")
|
|
63
|
+
table.add_column("Name")
|
|
64
|
+
table.add_column("Enabled")
|
|
65
|
+
table.add_column("Frequency (s)", justify="right")
|
|
66
|
+
table.add_column("Version", justify="right")
|
|
67
|
+
table.add_column("Updated At")
|
|
68
|
+
|
|
69
|
+
for q in items:
|
|
70
|
+
table.add_row(
|
|
71
|
+
q["scheduled_query_id"],
|
|
72
|
+
q["name"],
|
|
73
|
+
"yes" if q.get("enabled", True) else "no",
|
|
74
|
+
str(q.get("frequency") or ""),
|
|
75
|
+
str(q.get("current_version", "")),
|
|
76
|
+
q.get("updated_at", ""),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
console.print(table)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@app.command("get")
|
|
83
|
+
def get_scheduled_query(
|
|
84
|
+
sq_id: str = typer.Argument(help="Scheduled query ID."),
|
|
85
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
86
|
+
) -> None:
|
|
87
|
+
"""Get a scheduled query by ID."""
|
|
88
|
+
try:
|
|
89
|
+
data = state.get_client().get(f"/api/v1/scheduled-queries/{sq_id}")
|
|
90
|
+
except Exception as exc:
|
|
91
|
+
_die(exc)
|
|
92
|
+
return
|
|
93
|
+
_print_sq_detail(data, as_json=(output == "json"))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@app.command("delete")
|
|
97
|
+
def delete_scheduled_query(
|
|
98
|
+
sq_id: str = typer.Argument(help="Scheduled query ID."),
|
|
99
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
|
|
100
|
+
) -> None:
|
|
101
|
+
"""Delete a scheduled query."""
|
|
102
|
+
if not yes:
|
|
103
|
+
typer.confirm(f"Delete scheduled query {sq_id!r}?", abort=True)
|
|
104
|
+
try:
|
|
105
|
+
state.get_client().delete(f"/api/v1/scheduled-queries/{sq_id}")
|
|
106
|
+
except Exception as exc:
|
|
107
|
+
_die(exc)
|
|
108
|
+
return
|
|
109
|
+
console.print(f"[red]Deleted[/red]: {sq_id}")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@app.command("versions")
|
|
113
|
+
def list_versions(
|
|
114
|
+
sq_id: str = typer.Argument(help="Scheduled query ID."),
|
|
115
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
116
|
+
) -> None:
|
|
117
|
+
"""List all versions of a scheduled query."""
|
|
118
|
+
try:
|
|
119
|
+
data = state.get_client().get(f"/api/v1/scheduled-queries/{sq_id}/versions")
|
|
120
|
+
except Exception as exc:
|
|
121
|
+
_die(exc)
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
if output == "json":
|
|
125
|
+
console.print_json(json.dumps(data))
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
versions = data.get("versions", [])
|
|
129
|
+
table = Table(show_header=True, header_style="bold")
|
|
130
|
+
table.add_column("Version", justify="right")
|
|
131
|
+
table.add_column("Created By")
|
|
132
|
+
table.add_column("Created At")
|
|
133
|
+
table.add_column("Comment")
|
|
134
|
+
|
|
135
|
+
for v in versions:
|
|
136
|
+
table.add_row(
|
|
137
|
+
str(v["version"]),
|
|
138
|
+
v["created_by"],
|
|
139
|
+
v["created_at"],
|
|
140
|
+
v.get("comment") or "",
|
|
141
|
+
)
|
|
142
|
+
console.print(table)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@app.command("version-get")
|
|
146
|
+
def get_version(
|
|
147
|
+
sq_id: str = typer.Argument(help="Scheduled query ID."),
|
|
148
|
+
version: int = typer.Argument(help="Version number."),
|
|
149
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table or json."),
|
|
150
|
+
) -> None:
|
|
151
|
+
"""Get a specific version of a scheduled query."""
|
|
152
|
+
try:
|
|
153
|
+
data = state.get_client().get(f"/api/v1/scheduled-queries/{sq_id}/versions/{version}")
|
|
154
|
+
except Exception as exc:
|
|
155
|
+
_die(exc)
|
|
156
|
+
return
|
|
157
|
+
_print_sq_detail(data, as_json=(output == "json"))
|