fastapi-voyager 0.11.1__tar.gz → 0.11.2__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.
Files changed (48) hide show
  1. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/PKG-INFO +30 -19
  2. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/README.md +27 -18
  3. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/pyproject.toml +2 -0
  4. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/render.py +54 -40
  5. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/server.py +2 -0
  6. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/version.py +1 -1
  7. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/voyager.py +5 -3
  8. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/index.html +16 -3
  9. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/vue-main.js +8 -0
  10. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/.gitignore +0 -0
  11. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/.python-version +0 -0
  12. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/LICENSE +0 -0
  13. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/__init__.py +0 -0
  14. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/cli.py +0 -0
  15. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/filter.py +0 -0
  16. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/module.py +0 -0
  17. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/type.py +0 -0
  18. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/type_helper.py +0 -0
  19. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/component/render-graph.js +0 -0
  20. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
  21. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
  22. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
  23. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/graph-ui.js +0 -0
  24. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
  25. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
  26. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
  27. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
  28. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
  29. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
  30. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
  31. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/favicon.ico +0 -0
  32. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/icon/site.webmanifest +0 -0
  33. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/quasar.min.css +0 -0
  34. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/src/fastapi_voyager/web/quasar.min.js +0 -0
  35. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/__init__.py +0 -0
  36. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/demo.py +0 -0
  37. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/demo_anno.py +0 -0
  38. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/programatic.py +0 -0
  39. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/service/__init__.py +0 -0
  40. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/service/schema.py +0 -0
  41. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_analysis.py +0 -0
  42. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_filter.py +0 -0
  43. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_generic.py +0 -0
  44. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_import.py +0 -0
  45. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_module.py +0 -0
  46. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/tests/test_type_helper.py +0 -0
  47. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/uv.lock +0 -0
  48. {fastapi_voyager-0.11.1 → fastapi_voyager-0.11.2}/voyager.jpg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.11.1
3
+ Version: 0.11.2
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
@@ -16,6 +16,8 @@ Classifier: Programming Language :: Python :: 3.9
16
16
  Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
19
21
  Requires-Python: >=3.10
20
22
  Requires-Dist: fastapi>=0.110
21
23
  Requires-Dist: pydantic-resolve>=1.13.2
@@ -32,7 +34,14 @@ Description-Content-Type: text/markdown
32
34
 
33
35
  > This repo is still in early stage, it supports pydantic v2 only
34
36
 
35
- Inspect your API interactively!
37
+ FastAPI can help you:
38
+
39
+ - design your API
40
+ - inspect your API
41
+ - refactor your API
42
+
43
+ interactively !!
44
+
36
45
 
37
46
  [visit online demo](https://www.newsyeah.fun/voyager/) of project: [composition oriented development pattern](https://github.com/allmonday/composition-oriented-development-pattern)
38
47
 
@@ -51,6 +60,22 @@ uv add fastapi-voyager
51
60
  voyager -m path.to.your.app.module --server
52
61
  ```
53
62
 
63
+ ## Mount into project
64
+
65
+ ```python
66
+ from fastapi import FastAPI
67
+ from fastapi_voyager import create_voyager
68
+ from tests.demo import app
69
+
70
+ app.mount('/voyager', create_voyager(
71
+ app,
72
+ module_color={"tests.service": "red"},
73
+ module_prefix="tests.service"),
74
+ swagger_url="/docs")
75
+ ```
76
+
77
+ more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
78
+
54
79
 
55
80
  ## Feature
56
81
 
@@ -99,20 +124,6 @@ click a node to highlight it's upperstream and downstream nodes. figure out the
99
124
  <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
100
125
 
101
126
 
102
- ## Mount to target project
103
-
104
- ```python
105
- from fastapi import FastAPI
106
- from fastapi_voyager import create_voyager
107
- from tests.demo import app
108
-
109
- app.mount('/voyager', create_voyager(
110
- app,
111
- module_color={"tests.service": "red"},
112
- module_prefix="tests.service"))
113
- ```
114
-
115
- more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
116
127
 
117
128
 
118
129
  ## Command Line Usage
@@ -257,12 +268,12 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
257
268
  - [x] config docs path
258
269
  - [x] provide option to hide routes in brief mode (auto hide in full graph mode)
259
270
  - 0.11.2
260
- - [ ] enable/disable module cluster (to save space)
271
+ - [x] enable/disable module cluster (to save space)
272
+ - 0.11.3
273
+ - [ ] add loading for field detail panel
261
274
  - [ ] logging information
262
275
  - [ ] sort field name
263
276
  - [ ] set max limit for fields
264
- - [ ] add info icon alone with schema node
265
- - [ ] add loading for field detail panel
266
277
 
267
278
  #### 0.12
268
279
  - [ ] add tests
@@ -5,7 +5,14 @@
5
5
 
6
6
  > This repo is still in early stage, it supports pydantic v2 only
7
7
 
8
- Inspect your API interactively!
8
+ FastAPI can help you:
9
+
10
+ - design your API
11
+ - inspect your API
12
+ - refactor your API
13
+
14
+ interactively !!
15
+
9
16
 
10
17
  [visit online demo](https://www.newsyeah.fun/voyager/) of project: [composition oriented development pattern](https://github.com/allmonday/composition-oriented-development-pattern)
11
18
 
@@ -24,6 +31,22 @@ uv add fastapi-voyager
24
31
  voyager -m path.to.your.app.module --server
25
32
  ```
26
33
 
34
+ ## Mount into project
35
+
36
+ ```python
37
+ from fastapi import FastAPI
38
+ from fastapi_voyager import create_voyager
39
+ from tests.demo import app
40
+
41
+ app.mount('/voyager', create_voyager(
42
+ app,
43
+ module_color={"tests.service": "red"},
44
+ module_prefix="tests.service"),
45
+ swagger_url="/docs")
46
+ ```
47
+
48
+ more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
49
+
27
50
 
28
51
  ## Feature
29
52
 
@@ -72,20 +95,6 @@ click a node to highlight it's upperstream and downstream nodes. figure out the
72
95
  <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
73
96
 
74
97
 
75
- ## Mount to target project
76
-
77
- ```python
78
- from fastapi import FastAPI
79
- from fastapi_voyager import create_voyager
80
- from tests.demo import app
81
-
82
- app.mount('/voyager', create_voyager(
83
- app,
84
- module_color={"tests.service": "red"},
85
- module_prefix="tests.service"))
86
- ```
87
-
88
- more about [sub application](https://fastapi.tiangolo.com/advanced/sub-applications/?h=sub)
89
98
 
90
99
 
91
100
  ## Command Line Usage
@@ -230,12 +239,12 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
230
239
  - [x] config docs path
231
240
  - [x] provide option to hide routes in brief mode (auto hide in full graph mode)
232
241
  - 0.11.2
233
- - [ ] enable/disable module cluster (to save space)
242
+ - [x] enable/disable module cluster (to save space)
243
+ - 0.11.3
244
+ - [ ] add loading for field detail panel
234
245
  - [ ] logging information
235
246
  - [ ] sort field name
236
247
  - [ ] set max limit for fields
237
- - [ ] add info icon alone with schema node
238
- - [ ] add loading for field detail panel
239
248
 
240
249
  #### 0.12
241
250
  - [ ] add tests
@@ -17,6 +17,8 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3.10",
18
18
  "Programming Language :: Python :: 3.11",
19
19
  "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
20
22
  "Framework :: FastAPI",
21
23
  "Intended Audience :: Developers",
22
24
  "License :: OSI Approved :: MIT License"
@@ -10,10 +10,12 @@ class Renderer:
10
10
  show_fields: FieldType = 'single',
11
11
  module_color: dict[str, str] | None = None,
12
12
  schema: str | None = None,
13
+ show_module: bool = True
13
14
  ) -> None:
14
15
  self.show_fields = show_fields if show_fields in ('single', 'object', 'all') else 'single'
15
16
  self.module_color = module_color or {}
16
17
  self.schema = schema
18
+ self.show_module = show_module
17
19
 
18
20
  def render_schema_label(self, node: SchemaNode) -> str:
19
21
  has_base_fields = any(f.from_base for f in node.fields)
@@ -60,13 +62,18 @@ class Renderer:
60
62
  elif link.type == 'subset':
61
63
  return f"""{h(link.source)}:e -> {h(link.target)}:w [style = "solid, dashed", dir="back", minlen=3, taillabel = "< subset >", color = "orange", tailport="n"];"""
62
64
  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];"""
65
+ return f"""{h(link.source)}:e -> {h(link.target)}:w [style = "solid", minlen=3];"""
64
66
  else:
65
67
  raise ValueError(f'Unknown link type: {link.type}')
66
68
 
67
- def render_module_schema_content(self, mods: list[ModuleNode]) -> str:
68
- module_color_flag = set(self.module_color.keys())
69
-
69
+ def render_module_schema_content(self, nodes: list[SchemaNode]) -> str:
70
+ def render_node(node: SchemaNode) -> str:
71
+ return f'''
72
+ "{node.id}" [
73
+ label = {self.render_schema_label(node)}
74
+ shape = "plain"
75
+ margin="0.5,0.1"
76
+ ];'''
70
77
  def render_module_schema(mod: ModuleNode) -> str:
71
78
  color: Optional[str] = None
72
79
 
@@ -76,14 +83,7 @@ class Renderer:
76
83
  color = self.module_color[k]
77
84
  break
78
85
 
79
- inner_nodes = [
80
- f'''
81
- "{node.id}" [
82
- label = {self.render_schema_label(node)}
83
- shape = "plain"
84
- margin="0.5,0.1"
85
- ];''' for node in mod.schema_nodes
86
- ]
86
+ inner_nodes = [ render_node(node) for node in mod.schema_nodes ]
87
87
  inner_nodes_str = '\n'.join(inner_nodes)
88
88
  child_str = '\n'.join(render_module_schema(m) for m in mod.modules)
89
89
  return f'''
@@ -98,34 +98,49 @@ class Renderer:
98
98
  {inner_nodes_str}
99
99
  {child_str}
100
100
  }}'''
101
- return '\n'.join(render_module_schema(m) for m in mods)
101
+ if self.show_module:
102
+ module_schemas = build_module_schema_tree(nodes)
103
+ module_color_flag = set(self.module_color.keys())
104
+ return '\n'.join(render_module_schema(m) for m in module_schemas)
105
+ else:
106
+ return '\n'.join(render_node(n) for n in nodes)
102
107
 
103
- def render_module_route(self, mod: ModuleRoute) -> str:
104
- # Inner route nodes, same style as flat route_str
105
- inner_nodes = [
106
- f'''
107
- "{r.id}" [
108
- label = " {r.name} | {r.response_schema} "
109
- margin="0.5,0.1"
110
- shape = "record"
111
- ];''' for r in mod.routes
112
- ]
113
- inner_nodes_str = '\n'.join(inner_nodes)
114
- child_str = '\n'.join(self.render_module_route(m) for m in mod.modules)
115
- return f'''
116
- subgraph cluster_route_module_{mod.fullname.replace('.', '_')} {{
117
- tooltip="{mod.fullname}"
118
- color = "#666"
119
- style="rounded"
120
- label = " {mod.name}"
121
- labeljust = "l"
122
- {inner_nodes_str}
123
- {child_str}
124
- }}'''
108
+ def render_module_route_content(self, routes: list[Route]) -> str:
109
+ def render_route(route: Route) -> str:
110
+ response_schema = route.response_schema[:25] + '..' if len(route.response_schema) > 25 else route.response_schema
111
+ return f'''
112
+ "{route.id}" [
113
+ label = " {route.name} | {response_schema} "
114
+ margin="0.5,0.1"
115
+ shape = "record"
116
+ ];'''
117
+
118
+ def render_module_route(mod: ModuleRoute) -> str:
119
+ # Inner route nodes, same style as flat route_str
120
+ inner_nodes = [
121
+ render_route(r) for r in mod.routes
122
+ ]
123
+ inner_nodes_str = '\n'.join(inner_nodes)
124
+ child_str = '\n'.join(render_module_route(m) for m in mod.modules)
125
+ return f'''
126
+ subgraph cluster_route_module_{mod.fullname.replace('.', '_')} {{
127
+ tooltip="{mod.fullname}"
128
+ color = "#666"
129
+ style="rounded"
130
+ label = " {mod.name}"
131
+ labeljust = "l"
132
+ {inner_nodes_str}
133
+ {child_str}
134
+ }}'''
135
+ if self.show_module:
136
+ module_routes = build_module_route_tree(routes)
137
+ module_routes_str = '\n'.join(render_module_route(m) for m in module_routes)
138
+ return module_routes_str
139
+ else:
140
+ return '\n'.join(render_route(r) for r in routes)
141
+
125
142
 
126
143
  def render_dot(self, tags: list[Tag], routes: list[Route], nodes: list[SchemaNode], links: list[Link], spline_line=False) -> str:
127
- module_schemas = build_module_schema_tree(nodes)
128
- module_routes = build_module_route_tree(routes)
129
144
 
130
145
  tag_str = '\n'.join([
131
146
  f'''
@@ -136,9 +151,8 @@ class Renderer:
136
151
  ];''' for t in tags
137
152
  ])
138
153
 
139
-
140
- module_schemas_str = self.render_module_schema_content(module_schemas)
141
- module_routes_str = '\n'.join(self.render_module_route(m) for m in module_routes)
154
+ module_routes_str = self.render_module_route_content(routes)
155
+ module_schemas_str = self.render_module_schema_content(nodes)
142
156
  link_str = '\n'.join(self.render_link(link) for link in links)
143
157
 
144
158
  dot_str = f'''
@@ -33,6 +33,7 @@ class Payload(BaseModel):
33
33
  show_meta: bool = False
34
34
  brief: bool = False
35
35
  hide_primitive_route: bool = False
36
+ show_module: bool = True
36
37
 
37
38
 
38
39
  def create_route(
@@ -77,6 +78,7 @@ def create_route(
77
78
  module_color=module_color,
78
79
  route_name=payload.route_name,
79
80
  hide_primitive_route=payload.hide_primitive_route,
81
+ show_module=payload.show_module,
80
82
  )
81
83
  voyager.analysis(target_app)
82
84
  if payload.brief:
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.11.1"
2
+ __version__ = "0.11.2"
@@ -27,6 +27,7 @@ class Voyager:
27
27
  module_color: dict[str, str] | None = None,
28
28
  route_name: str | None = None,
29
29
  hide_primitive_route: bool = False,
30
+ show_module: bool = True
30
31
  ):
31
32
 
32
33
  self.routes: list[Route] = []
@@ -48,6 +49,7 @@ class Voyager:
48
49
  self.module_color = module_color or {}
49
50
  self.route_name = route_name
50
51
  self.hide_primitive_route = hide_primitive_route
52
+ self.show_module = show_module
51
53
 
52
54
 
53
55
  def _get_available_route(self, app: FastAPI):
@@ -301,7 +303,7 @@ class Voyager:
301
303
  node_set=self.node_set,
302
304
  )
303
305
 
304
- renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema)
306
+ renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema, show_module=self.show_module)
305
307
 
306
308
  _tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
307
309
  return renderer.render_dot(_tags, _routes, _nodes, _links)
@@ -326,7 +328,7 @@ class Voyager:
326
328
  links=_links,
327
329
  )
328
330
 
329
- renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema)
331
+ renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema, show_module=self.show_module)
330
332
 
331
333
  _tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
332
334
  return renderer.render_dot(_tags, _routes, _nodes, _links, True)
@@ -350,7 +352,7 @@ class Voyager:
350
352
  links=_links,
351
353
  )
352
354
 
353
- renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema)
355
+ renderer = Renderer(show_fields=self.show_fields, module_color=self.module_color, schema=self.schema, show_module=self.show_module)
354
356
 
355
357
  _tags, _routes, _links = self.handle_hide(_tags, _routes, _links)
356
358
  return renderer.render_dot(_tags, _routes, _nodes, _links, True)
@@ -148,6 +148,7 @@
148
148
  side="right"
149
149
  style="border-left: 1px solid #888;"
150
150
  bordered
151
+ overlay
151
152
  >
152
153
  <!-- 可拖拽的调整栏 -->
153
154
  <div
@@ -265,32 +266,44 @@
265
266
  <div style="position: relative; width: 100%; height: 100%;">
266
267
  <div id="graph" class="adjust-fit"></div>
267
268
  <div style="position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(255,255,255,0.85); border-radius: 4px; padding: 2px 8px;">
268
- <div>
269
+ <div class="q-mt-sm">
269
270
  <q-toggle
270
271
  v-model="state.focus"
271
272
  v-show="schemaCodeName"
272
273
  @update:model-value="val => onFocusChange(val)"
273
274
  label="Focus"
275
+ dense
274
276
  title="pick a schema and toggle focus on to display related nodes only"
275
277
  />
276
278
  </div>
277
- <div>
279
+ <div class="q-mt-sm">
278
280
  <q-toggle
279
281
  v-if="state.enableBriefMode"
282
+ dense
280
283
  v-model="state.brief"
281
284
  label="Brief Mode"
282
285
  @update:model-value="(val) => toggleBrief(val)"
283
286
  title="skip middle classes, config module_prefix to enable it"
284
287
  />
285
288
  </div>
286
- <div>
289
+ <div class="q-mt-sm">
287
290
  <q-toggle
288
291
  v-model="state.hidePrimitiveRoute"
289
292
  @update:model-value="(val) => toggleHidePrimitiveRoute(val)"
290
293
  label="Hide Primitive"
294
+ dense
291
295
  title="hide routes return primitive"
292
296
  />
293
297
  </div>
298
+ <div class="q-mt-sm">
299
+ <q-toggle
300
+ v-model="state.showModule"
301
+ @update:model-value="(val) => toggleShowModule(val)"
302
+ label="Show Module Cluster"
303
+ dense
304
+ title="show module cluster"
305
+ />
306
+ </div>
294
307
  </div>
295
308
  </div>
296
309
  </template>
@@ -34,6 +34,7 @@ const app = createApp({
34
34
  detailDrawer: false,
35
35
  drawerWidth: 300, // drawer 宽度
36
36
  version: "", // version from backend
37
+ showModule: true
37
38
  });
38
39
 
39
40
  const showDetail = ref(false);
@@ -112,6 +113,7 @@ const app = createApp({
112
113
  show_fields: state.showFields,
113
114
  brief: state.brief,
114
115
  hide_primitive_route: state.hidePrimitiveRoute,
116
+ show_module: state.showModule,
115
117
  };
116
118
  const res = await fetch("dot", {
117
119
  method: "POST",
@@ -261,6 +263,11 @@ const app = createApp({
261
263
  onGenerate();
262
264
  }
263
265
 
266
+ function toggleShowModule(val) {
267
+ state.showModule = val;
268
+ onGenerate()
269
+ }
270
+
264
271
  function toggleShowField(field) {
265
272
  state.showFields = field;
266
273
  onGenerate(false);
@@ -337,6 +344,7 @@ const app = createApp({
337
344
  toggleShowField,
338
345
  startDragDrawer,
339
346
  onFocusChange,
347
+ toggleShowModule
340
348
  };
341
349
  },
342
350
  });