fastapi-voyager 0.10.5__tar.gz → 0.11.1__tar.gz
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.
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/PKG-INFO +14 -12
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/README.md +13 -11
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/filter.py +91 -1
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/render.py +2 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/server.py +16 -3
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/type.py +3 -1
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/version.py +1 -1
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/voyager.py +28 -4
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/index.html +6 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/vue-main.js +2 -1
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/programatic.py +1 -1
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/.gitignore +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/.python-version +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/LICENSE +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/pyproject.toml +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/__init__.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/cli.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/module.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/type_helper.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/component/render-graph.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/graph-ui.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/favicon.ico +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/site.webmanifest +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/quasar.min.css +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/quasar.min.js +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/__init__.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/demo.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/demo_anno.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/service/__init__.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/service/schema.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_analysis.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_filter.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_generic.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_import.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_module.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/tests/test_type_helper.py +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/uv.lock +0 -0
- {fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/voyager.jpg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-voyager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.1
|
|
4
4
|
Summary: Visualize FastAPI application's routing tree and dependencies
|
|
5
5
|
Project-URL: Homepage, https://github.com/allmonday/fastapi-voyager
|
|
6
6
|
Project-URL: Source, https://github.com/allmonday/fastapi-voyager
|
|
@@ -244,6 +244,7 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
|
|
|
244
244
|
- [x] fix focus in brief-mode
|
|
245
245
|
- [x] ui: adjust focus position
|
|
246
246
|
- [x] refactor naming
|
|
247
|
+
- [x] fix layout issue when rendering huge graph
|
|
247
248
|
- 0.10.4
|
|
248
249
|
- [x] fix: when focus is on, should ensure changes from other params not broken.
|
|
249
250
|
- 0.10.5
|
|
@@ -251,19 +252,20 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
|
|
|
251
252
|
|
|
252
253
|
|
|
253
254
|
#### 0.11
|
|
254
|
-
-
|
|
255
|
-
- [
|
|
256
|
-
- [
|
|
257
|
-
- [
|
|
258
|
-
|
|
259
|
-
- [ ]
|
|
260
|
-
- [ ]
|
|
261
|
-
- [ ] sort field name
|
|
262
|
-
- [ ] set max limit for fields
|
|
263
|
-
- [ ] add info icon alone with schema node
|
|
264
|
-
- [ ] add loading for field detail panel
|
|
255
|
+
- 0.11.1
|
|
256
|
+
- [x] support opening route in swagger
|
|
257
|
+
- [x] config docs path
|
|
258
|
+
- [x] provide option to hide routes in brief mode (auto hide in full graph mode)
|
|
259
|
+
- 0.11.2
|
|
260
|
+
- [ ] enable/disable module cluster (to save space)
|
|
261
|
+
- [ ] logging information
|
|
262
|
+
- [ ] sort field name
|
|
263
|
+
- [ ] set max limit for fields
|
|
264
|
+
- [ ] add info icon alone with schema node
|
|
265
|
+
- [ ] add loading for field detail panel
|
|
265
266
|
|
|
266
267
|
#### 0.12
|
|
268
|
+
- [ ] add tests
|
|
267
269
|
- [ ] integration with pydantic-resolve
|
|
268
270
|
- [ ] show hint for resolve, post fields
|
|
269
271
|
- [ ] display loader as edges
|
|
@@ -217,6 +217,7 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
|
|
|
217
217
|
- [x] fix focus in brief-mode
|
|
218
218
|
- [x] ui: adjust focus position
|
|
219
219
|
- [x] refactor naming
|
|
220
|
+
- [x] fix layout issue when rendering huge graph
|
|
220
221
|
- 0.10.4
|
|
221
222
|
- [x] fix: when focus is on, should ensure changes from other params not broken.
|
|
222
223
|
- 0.10.5
|
|
@@ -224,19 +225,20 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
|
|
|
224
225
|
|
|
225
226
|
|
|
226
227
|
#### 0.11
|
|
227
|
-
-
|
|
228
|
-
- [
|
|
229
|
-
- [
|
|
230
|
-
- [
|
|
231
|
-
|
|
232
|
-
- [ ]
|
|
233
|
-
- [ ]
|
|
234
|
-
- [ ] sort field name
|
|
235
|
-
- [ ] set max limit for fields
|
|
236
|
-
- [ ] add info icon alone with schema node
|
|
237
|
-
- [ ] add loading for field detail panel
|
|
228
|
+
- 0.11.1
|
|
229
|
+
- [x] support opening route in swagger
|
|
230
|
+
- [x] config docs path
|
|
231
|
+
- [x] provide option to hide routes in brief mode (auto hide in full graph mode)
|
|
232
|
+
- 0.11.2
|
|
233
|
+
- [ ] enable/disable module cluster (to save space)
|
|
234
|
+
- [ ] logging information
|
|
235
|
+
- [ ] sort field name
|
|
236
|
+
- [ ] set max limit for fields
|
|
237
|
+
- [ ] add info icon alone with schema node
|
|
238
|
+
- [ ] add loading for field detail panel
|
|
238
239
|
|
|
239
240
|
#### 0.12
|
|
241
|
+
- [ ] add tests
|
|
240
242
|
- [ ] integration with pydantic-resolve
|
|
241
243
|
- [ ] show hint for resolve, post fields
|
|
242
244
|
- [ ] display loader as edges
|
|
@@ -192,4 +192,94 @@ def filter_subgraph_by_module_prefix(
|
|
|
192
192
|
|
|
193
193
|
filtered_links = tag_route_links + merged_links + module_prefix_links
|
|
194
194
|
|
|
195
|
-
return tags, routes, filtered_nodes, filtered_links
|
|
195
|
+
return tags, routes, filtered_nodes, filtered_links
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def filter_subgraph_from_tag_to_schema_by_module_prefix(
|
|
199
|
+
*,
|
|
200
|
+
tags: list[Tag],
|
|
201
|
+
routes: list[Route],
|
|
202
|
+
links: list[Link],
|
|
203
|
+
nodes: list[SchemaNode],
|
|
204
|
+
module_prefix: str
|
|
205
|
+
) -> Tuple[list[Tag], list[Route], list[SchemaNode], list[Link]]:
|
|
206
|
+
"""Collapse schema graph so routes link directly to nodes whose module matches ``module_prefix``.
|
|
207
|
+
|
|
208
|
+
The routine keeps tag→route links untouched, prunes schema nodes whose module does not start
|
|
209
|
+
with ``module_prefix``, and merges the remaining schema relationships so each route connects
|
|
210
|
+
directly to the surviving schema nodes. Traversal stops once a qualifying node is reached and
|
|
211
|
+
guards against cycles in the schema graph.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
if not module_prefix:
|
|
215
|
+
# empty prefix keeps existing graph structure, so simply reuse incoming data
|
|
216
|
+
return tags, routes, nodes, [lk for lk in links if lk.type in ("tag_route", "route_to_schema")]
|
|
217
|
+
|
|
218
|
+
route_links = [lk for lk in links if lk.type == "route_to_schema"]
|
|
219
|
+
schema_links = [lk for lk in links if lk.type in {"schema", "parent", "subset"}]
|
|
220
|
+
tag_route_links = [lk for lk in links if lk.type == "tag_route"]
|
|
221
|
+
|
|
222
|
+
node_lookup: dict[str, SchemaNode] = {node.id: node for node in (nodes + routes)}
|
|
223
|
+
|
|
224
|
+
filtered_nodes = [node for node in nodes if node_lookup[node.id].module.startswith(module_prefix)]
|
|
225
|
+
filtered_node_ids = {node.id for node in filtered_nodes}
|
|
226
|
+
|
|
227
|
+
adjacency: dict[str, list[str]] = {}
|
|
228
|
+
for link in (schema_links + route_links):
|
|
229
|
+
if link.source_origin not in node_lookup or link.target_origin not in node_lookup:
|
|
230
|
+
continue
|
|
231
|
+
adjacency.setdefault(link.source_origin, [])
|
|
232
|
+
if link.target_origin not in adjacency[link.source_origin]:
|
|
233
|
+
adjacency[link.source_origin].append(link.target_origin)
|
|
234
|
+
|
|
235
|
+
merged_links: list[Link] = []
|
|
236
|
+
seen_pairs: set[tuple[str, str]] = set()
|
|
237
|
+
|
|
238
|
+
for link in tag_route_links:
|
|
239
|
+
# print(link)
|
|
240
|
+
tag_id = link.source_origin
|
|
241
|
+
start_node_id = link.target_origin
|
|
242
|
+
if tag_id is None or start_node_id is None:
|
|
243
|
+
continue
|
|
244
|
+
if start_node_id not in node_lookup:
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
visited: set[str] = set()
|
|
248
|
+
queue: deque[str] = deque([start_node_id])
|
|
249
|
+
|
|
250
|
+
while queue:
|
|
251
|
+
current = queue.popleft()
|
|
252
|
+
if current in visited:
|
|
253
|
+
continue
|
|
254
|
+
visited.add(current)
|
|
255
|
+
|
|
256
|
+
if current in filtered_node_ids:
|
|
257
|
+
key = (tag_id, current)
|
|
258
|
+
if key not in seen_pairs:
|
|
259
|
+
seen_pairs.add(key)
|
|
260
|
+
merged_links.append(
|
|
261
|
+
Link(
|
|
262
|
+
source=link.source,
|
|
263
|
+
source_origin=tag_id,
|
|
264
|
+
target=f"{current}::{PK}",
|
|
265
|
+
target_origin=current,
|
|
266
|
+
type="tag_to_schema",
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
# stop traversing past a qualifying node
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
for next_node in adjacency.get(current, () ):
|
|
273
|
+
if next_node not in visited:
|
|
274
|
+
queue.append(next_node)
|
|
275
|
+
|
|
276
|
+
module_prefix_links = [
|
|
277
|
+
lk
|
|
278
|
+
for lk in links
|
|
279
|
+
if (lk.source_origin or "").startswith(module_prefix)
|
|
280
|
+
and (lk.target_origin or "").startswith(module_prefix)
|
|
281
|
+
]
|
|
282
|
+
|
|
283
|
+
filtered_links = merged_links + module_prefix_links
|
|
284
|
+
|
|
285
|
+
return tags, [], filtered_nodes, filtered_links # route is skipped
|
|
@@ -59,6 +59,8 @@ class Renderer:
|
|
|
59
59
|
return f"""{h(link.source)}:e -> {h(link.target)}:w [style = "solid, dashed", dir="back", minlen=3, taillabel = "< inherit >", color = "purple", tailport="n"];"""
|
|
60
60
|
elif link.type == 'subset':
|
|
61
61
|
return f"""{h(link.source)}:e -> {h(link.target)}:w [style = "solid, dashed", dir="back", minlen=3, taillabel = "< subset >", color = "orange", tailport="n"];"""
|
|
62
|
+
elif link.type == 'tag_to_schema':
|
|
63
|
+
return f"""{h(link.source)}:e -> {h(link.target)}:w [style = "solid", dir="back", arrowtail="odot", minlen=3];"""
|
|
62
64
|
else:
|
|
63
65
|
raise ValueError(f'Unknown link type: {link.type}')
|
|
64
66
|
|
|
@@ -22,6 +22,7 @@ class OptionParam(BaseModel):
|
|
|
22
22
|
dot: str
|
|
23
23
|
enable_brief_mode: bool
|
|
24
24
|
version: str
|
|
25
|
+
swagger_url: Optional[str] = None
|
|
25
26
|
|
|
26
27
|
class Payload(BaseModel):
|
|
27
28
|
tags: Optional[list[str]] = None
|
|
@@ -33,9 +34,11 @@ class Payload(BaseModel):
|
|
|
33
34
|
brief: bool = False
|
|
34
35
|
hide_primitive_route: bool = False
|
|
35
36
|
|
|
37
|
+
|
|
36
38
|
def create_route(
|
|
37
39
|
target_app: FastAPI,
|
|
38
40
|
module_color: dict[str, str] | None = None,
|
|
41
|
+
swagger_url: Optional[str] = None,
|
|
39
42
|
module_prefix: Optional[str] = None,
|
|
40
43
|
):
|
|
41
44
|
"""
|
|
@@ -56,7 +59,13 @@ def create_route(
|
|
|
56
59
|
schemas = voyager.nodes[:]
|
|
57
60
|
schemas.sort(key=lambda s: s.name)
|
|
58
61
|
|
|
59
|
-
return OptionParam(
|
|
62
|
+
return OptionParam(
|
|
63
|
+
tags=tags,
|
|
64
|
+
schemas=schemas,
|
|
65
|
+
dot=dot,
|
|
66
|
+
enable_brief_mode=bool(module_prefix),
|
|
67
|
+
version=__version__,
|
|
68
|
+
swagger_url=swagger_url)
|
|
60
69
|
|
|
61
70
|
@router.post("/dot", response_class=PlainTextResponse)
|
|
62
71
|
def get_filtered_dot(payload: Payload) -> str:
|
|
@@ -71,7 +80,10 @@ def create_route(
|
|
|
71
80
|
)
|
|
72
81
|
voyager.analysis(target_app)
|
|
73
82
|
if payload.brief:
|
|
74
|
-
|
|
83
|
+
if payload.tags:
|
|
84
|
+
return voyager.render_tag_level_brief_dot(module_prefix=module_prefix)
|
|
85
|
+
else:
|
|
86
|
+
return voyager.render_overall_brief_dot(module_prefix=module_prefix)
|
|
75
87
|
else:
|
|
76
88
|
return voyager.render_dot()
|
|
77
89
|
|
|
@@ -196,8 +208,9 @@ def create_voyager(
|
|
|
196
208
|
module_color: dict[str, str] | None = None,
|
|
197
209
|
gzip_minimum_size: int | None = 500,
|
|
198
210
|
module_prefix: Optional[str] = None,
|
|
211
|
+
swagger_url: Optional[str] = None,
|
|
199
212
|
) -> FastAPI:
|
|
200
|
-
router = create_route(target_app, module_color=module_color, module_prefix=module_prefix)
|
|
213
|
+
router = create_route(target_app, module_color=module_color, module_prefix=module_prefix, swagger_url=swagger_url)
|
|
201
214
|
|
|
202
215
|
app = FastAPI(title="fastapi-voyager demo server")
|
|
203
216
|
if gzip_minimum_size is not None and gzip_minimum_size >= 0:
|
|
@@ -22,6 +22,7 @@ class Tag(NodeBase):
|
|
|
22
22
|
@dataclass
|
|
23
23
|
class Route(NodeBase):
|
|
24
24
|
module: str
|
|
25
|
+
unique_id: str = ''
|
|
25
26
|
response_schema: str = ''
|
|
26
27
|
is_primitive: bool = True
|
|
27
28
|
|
|
@@ -51,7 +52,8 @@ class ModuleNode:
|
|
|
51
52
|
# - subset: schema -> schema (subset)
|
|
52
53
|
# - parent: schema -> schema (inheritance)
|
|
53
54
|
# - schema: schema -> schema (field reference)
|
|
54
|
-
|
|
55
|
+
# - tag_to_schema: tag -> schema (only happens in module prefix filtering, aka brief mode)
|
|
56
|
+
LinkType = Literal['schema', 'parent', 'tag_route', 'subset', 'route_to_schema', 'tag_to_schema']
|
|
55
57
|
|
|
56
58
|
@dataclass
|
|
57
59
|
class Link:
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.11.1"
|
|
@@ -6,15 +6,13 @@ from fastapi_voyager.type_helper import (
|
|
|
6
6
|
get_bases_fields,
|
|
7
7
|
is_inheritance_of_pydantic_base,
|
|
8
8
|
get_pydantic_fields,
|
|
9
|
-
get_vscode_link,
|
|
10
|
-
get_source,
|
|
11
9
|
get_type_name,
|
|
12
10
|
update_forward_refs,
|
|
13
11
|
is_non_pydantic_type
|
|
14
12
|
)
|
|
15
13
|
from pydantic import BaseModel
|
|
16
14
|
from fastapi_voyager.type import Route, SchemaNode, Link, Tag, LinkType, FieldType, PK, CoreData
|
|
17
|
-
from fastapi_voyager.filter import filter_graph, filter_subgraph_by_module_prefix
|
|
15
|
+
from fastapi_voyager.filter import filter_graph, filter_subgraph_from_tag_to_schema_by_module_prefix, filter_subgraph_by_module_prefix
|
|
18
16
|
from fastapi_voyager.render import Renderer
|
|
19
17
|
import pydantic_resolve.constant as const
|
|
20
18
|
|
|
@@ -123,6 +121,7 @@ class Voyager:
|
|
|
123
121
|
id=route_id,
|
|
124
122
|
name=route_name,
|
|
125
123
|
module=route_module,
|
|
124
|
+
unique_id=route.unique_id,
|
|
126
125
|
response_schema=get_type_name(route.response_model),
|
|
127
126
|
is_primitive=is_primitive_response
|
|
128
127
|
)
|
|
@@ -307,7 +306,8 @@ class Voyager:
|
|
|
307
306
|
_tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
|
|
308
307
|
return renderer.render_dot(_tags, _routes, _nodes, _links)
|
|
309
308
|
|
|
310
|
-
|
|
309
|
+
|
|
310
|
+
def render_tag_level_brief_dot(self, module_prefix: str | None = None):
|
|
311
311
|
_tags, _routes, _nodes, _links = filter_graph(
|
|
312
312
|
schema=self.schema,
|
|
313
313
|
schema_field=self.schema_field,
|
|
@@ -328,5 +328,29 @@ class Voyager:
|
|
|
328
328
|
|
|
329
329
|
renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema)
|
|
330
330
|
|
|
331
|
+
_tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
|
|
332
|
+
return renderer.render_dot(_tags, _routes, _nodes, _links, True)
|
|
333
|
+
|
|
334
|
+
def render_overall_brief_dot(self, module_prefix: str | None = None):
|
|
335
|
+
_tags, _routes, _nodes, _links = filter_graph(
|
|
336
|
+
schema=self.schema,
|
|
337
|
+
schema_field=self.schema_field,
|
|
338
|
+
tags=self.tags,
|
|
339
|
+
routes=self.routes,
|
|
340
|
+
nodes=self.nodes,
|
|
341
|
+
links=self.links,
|
|
342
|
+
node_set=self.node_set,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
_tags, _routes, _nodes, _links = filter_subgraph_from_tag_to_schema_by_module_prefix(
|
|
346
|
+
module_prefix=module_prefix,
|
|
347
|
+
tags=_tags,
|
|
348
|
+
routes=_routes,
|
|
349
|
+
nodes=_nodes,
|
|
350
|
+
links=_links,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema)
|
|
354
|
+
|
|
331
355
|
_tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
|
|
332
356
|
return renderer.render_dot(_tags, _routes, _nodes, _links, True)
|
|
@@ -218,6 +218,9 @@
|
|
|
218
218
|
:name="state.tag == tag.name ? 'folder' : 'folder_open'"
|
|
219
219
|
></q-icon>
|
|
220
220
|
<span>{{ tag.name }} <q-chip style="position:relative; top: -1px;" class="q-ml-sm" dense>{{ tag.routes.length }}</q-chip></span>
|
|
221
|
+
<a target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name">
|
|
222
|
+
<q-icon size="small" name="link"></q-icon>
|
|
223
|
+
</a>
|
|
221
224
|
</div>
|
|
222
225
|
</template>
|
|
223
226
|
<q-list separator style="overflow: auto; max-height: 60vh;">
|
|
@@ -237,6 +240,9 @@
|
|
|
237
240
|
name="data_object"
|
|
238
241
|
></q-icon>
|
|
239
242
|
{{ route.name }}
|
|
243
|
+
<a target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name + '/' + route.unique_id">
|
|
244
|
+
<q-icon size="small" name="link"></q-icon>
|
|
245
|
+
</a>
|
|
240
246
|
</span>
|
|
241
247
|
</q-item-section>
|
|
242
248
|
</q-item>
|
|
@@ -24,6 +24,7 @@ const app = createApp({
|
|
|
24
24
|
focus: false,
|
|
25
25
|
hidePrimitiveRoute: false,
|
|
26
26
|
generating: false,
|
|
27
|
+
swaggerUrl: null,
|
|
27
28
|
rawTags: [], // [{ name, routes: [{ id, name }] }]
|
|
28
29
|
rawSchemas: new Set(), // [{ name, id }]
|
|
29
30
|
rawSchemasFull: {}, // full schemas dict: { [schema.id]: schema }
|
|
@@ -78,6 +79,7 @@ const app = createApp({
|
|
|
78
79
|
}, {});
|
|
79
80
|
state.enableBriefMode = data.enable_brief_mode || false;
|
|
80
81
|
state.version = data.version || "";
|
|
82
|
+
state.swaggerUrl = data.swagger_url || null
|
|
81
83
|
|
|
82
84
|
// default route options placeholder
|
|
83
85
|
} catch (e) {
|
|
@@ -225,7 +227,6 @@ const app = createApp({
|
|
|
225
227
|
state.routeId = "";
|
|
226
228
|
state.schemaId = null;
|
|
227
229
|
// state.showFields = "object";
|
|
228
|
-
state.brief = false;
|
|
229
230
|
state.focus = false;
|
|
230
231
|
schemaCodeName.value = "";
|
|
231
232
|
onGenerate();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from fastapi_voyager import create_voyager
|
|
2
2
|
from tests.demo import app
|
|
3
3
|
|
|
4
|
-
app.mount('/voyager', create_voyager(app, module_color={"tests.service": "red"}, module_prefix="tests.service"))
|
|
4
|
+
app.mount('/voyager', create_voyager(app, module_color={"tests.service": "red"}, module_prefix="tests.service", swagger_url='/docs'))
|
|
5
5
|
# app.mount('/voyager', create_voyager(app, module_color={"tests.service": "red"}))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/component/render-graph.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/apple-touch-icon.png
RENAMED
|
File without changes
|
{fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/favicon-16x16.png
RENAMED
|
File without changes
|
{fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/favicon-32x32.png
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_voyager-0.10.5 → fastapi_voyager-0.11.1}/src/fastapi_voyager/web/icon/site.webmanifest
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|