fastapi-voyager 0.11.4__tar.gz → 0.11.6__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 (50) hide show
  1. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/PKG-INFO +21 -24
  2. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/README.md +20 -23
  3. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/server.py +10 -3
  4. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/version.py +1 -1
  5. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/index.html +54 -26
  6. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/vue-main.js +17 -1
  7. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/programatic.py +1 -0
  8. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/.github/workflows/publish.yml +0 -0
  9. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/.gitignore +0 -0
  10. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/.python-version +0 -0
  11. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/LICENSE +0 -0
  12. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/pyproject.toml +0 -0
  13. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/release.md +0 -0
  14. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/__init__.py +0 -0
  15. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/cli.py +0 -0
  16. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/filter.py +0 -0
  17. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/module.py +0 -0
  18. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/render.py +0 -0
  19. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/type.py +0 -0
  20. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/type_helper.py +0 -0
  21. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/voyager.py +0 -0
  22. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/component/render-graph.js +0 -0
  23. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/component/route-code-display.js +0 -0
  24. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/component/schema-code-display.js +0 -0
  25. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/component/schema-field-filter.js +0 -0
  26. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/graph-ui.js +0 -0
  27. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/graphviz.svg.css +0 -0
  28. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/graphviz.svg.js +0 -0
  29. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/android-chrome-192x192.png +0 -0
  30. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/android-chrome-512x512.png +0 -0
  31. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/apple-touch-icon.png +0 -0
  32. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/favicon-16x16.png +0 -0
  33. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/favicon-32x32.png +0 -0
  34. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/favicon.ico +0 -0
  35. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/icon/site.webmanifest +0 -0
  36. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/quasar.min.css +0 -0
  37. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/src/fastapi_voyager/web/quasar.min.js +0 -0
  38. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/__init__.py +0 -0
  39. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/demo.py +0 -0
  40. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/demo_anno.py +0 -0
  41. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/service/__init__.py +0 -0
  42. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/service/schema.py +0 -0
  43. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_analysis.py +0 -0
  44. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_filter.py +0 -0
  45. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_generic.py +0 -0
  46. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_import.py +0 -0
  47. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_module.py +0 -0
  48. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/tests/test_type_helper.py +0 -0
  49. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/uv.lock +0 -0
  50. {fastapi_voyager-0.11.4 → fastapi_voyager-0.11.6}/voyager.jpg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.11.4
3
+ Version: 0.11.6
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
@@ -45,8 +45,7 @@ interactively !!
45
45
 
46
46
  [visit online demo](https://www.newsyeah.fun/voyager/) of project: [composition oriented development pattern](https://github.com/allmonday/composition-oriented-development-pattern)
47
47
 
48
- <p align="center"><img src="./voyager.jpg" alt="" /></p>
49
- <p align="center"><a target="_blank" rel="" href="https://www.youtube.com/watch?v=PGlbQq1M-n8"><img src="http://img.youtube.com/vi/PGlbQq1M-n8/0.jpg" alt="" style="max-width: 100%;"></a></p>
48
+ <img width="1600" height="986" alt="image" src="https://github.com/user-attachments/assets/8829cda0-f42d-4c84-be2f-b019bb5fe7e1" />
50
49
 
51
50
  ## Installation
52
51
 
@@ -97,32 +96,25 @@ voyager -m tests.demo
97
96
  --module_color=tests.demo:tomato
98
97
  ```
99
98
 
100
- ### generate the graph
101
- after initialization, pick tag, rotue to render graph
102
-
103
- <img width="1628" height="765" alt="image" src="https://github.com/user-attachments/assets/b4712f82-e754-453b-aa69-24c932b8f48f" />
104
-
105
99
  ### highlight
106
100
  click a node to highlight it's upperstream and downstream nodes. figure out the related models of one page, or homw many pages are related with one model.
107
101
 
108
- <img width="1485" height="616" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/70c4095f-86c7-45da-a6f0-fd41ac645813" />
102
+ <img width="1100" height="700" alt="image" src="https://github.com/user-attachments/assets/3e0369ea-5fa4-469a-82c1-ed57d407e53d" />
109
103
 
110
- ### filter related nodes
111
- `shift` click a node to check related node, pick a field to narrow the result, picked node is marked as red.
104
+ ### focus on nodes
105
+ toggle focus to hide nodes not related with current picked one.
112
106
 
113
- <img width="1423" height="552" alt="image" src="https://github.com/user-attachments/assets/468a058d-afa1-4601-a7c5-c6aad6a8a557" />
107
+ before:
108
+ <img width="1066" height="941" alt="image" src="https://github.com/user-attachments/assets/39f30817-899a-4289-93f4-a1646d3441c1" />
109
+ after:
110
+ <img width="1061" height="937" alt="image" src="https://github.com/user-attachments/assets/79709b02-7571-43fc-abc9-17a287a97515" />
114
111
 
115
112
  ### view source code
116
- `alt` click a node to show source code or open file in vscode.
117
-
118
- <img width="1049" height="694" alt="image" src="https://github.com/user-attachments/assets/7839ac83-8d60-44ad-b1c9-9652a76339b1" />
119
-
120
- <img width="1042" height="675" alt="image" src="https://github.com/user-attachments/assets/38ae705f-5982-4a02-9c3f-038b1d00bcf6" />
121
-
122
- `alt` click a route to show source code or open file in vscode
123
-
124
- <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
113
+ double click a node to show source code or open file in vscode.
114
+ <img width="1297" height="940" alt="image" src="https://github.com/user-attachments/assets/c8bb2e7d-b727-42a6-8c9e-64dce297d2d8" />
125
115
 
116
+ double click a route to show source code or open file in vscode
117
+ <img width="1132" height="824" alt="image" src="https://github.com/user-attachments/assets/b706e879-e4fc-48dd-ace1-99bf97e3ed6a" />
126
118
 
127
119
 
128
120
 
@@ -191,6 +183,9 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
191
183
  - [ ] animation effect for edges
192
184
  - [ ] customrized right click panel
193
185
  - [ ] show own dependencies
186
+ - [ ] sort field name
187
+ - [ ] set max limit for fields
188
+ - [ ] logging information
194
189
 
195
190
  ### plan:
196
191
  #### <0.9:
@@ -274,9 +269,11 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
274
269
  - 0.11.4
275
270
  - [x] add loading for field detail panel
276
271
  - 0.11.5
277
- - [ ] logging information
278
- - [ ] sort field name
279
- - [ ] set max limit for fields
272
+ - [x] optimize open in swagger link
273
+ - [x] change jquery cdn
274
+ - 0.11.6
275
+ - [x] flag of loading full graph in first render or not
276
+ - [x] optimize loading static resource
280
277
 
281
278
  #### 0.12
282
279
  - [ ] add tests
@@ -16,8 +16,7 @@ interactively !!
16
16
 
17
17
  [visit online demo](https://www.newsyeah.fun/voyager/) of project: [composition oriented development pattern](https://github.com/allmonday/composition-oriented-development-pattern)
18
18
 
19
- <p align="center"><img src="./voyager.jpg" alt="" /></p>
20
- <p align="center"><a target="_blank" rel="" href="https://www.youtube.com/watch?v=PGlbQq1M-n8"><img src="http://img.youtube.com/vi/PGlbQq1M-n8/0.jpg" alt="" style="max-width: 100%;"></a></p>
19
+ <img width="1600" height="986" alt="image" src="https://github.com/user-attachments/assets/8829cda0-f42d-4c84-be2f-b019bb5fe7e1" />
21
20
 
22
21
  ## Installation
23
22
 
@@ -68,32 +67,25 @@ voyager -m tests.demo
68
67
  --module_color=tests.demo:tomato
69
68
  ```
70
69
 
71
- ### generate the graph
72
- after initialization, pick tag, rotue to render graph
73
-
74
- <img width="1628" height="765" alt="image" src="https://github.com/user-attachments/assets/b4712f82-e754-453b-aa69-24c932b8f48f" />
75
-
76
70
  ### highlight
77
71
  click a node to highlight it's upperstream and downstream nodes. figure out the related models of one page, or homw many pages are related with one model.
78
72
 
79
- <img width="1485" height="616" alt="image" style="border: 1px solid #aaa" src="https://github.com/user-attachments/assets/70c4095f-86c7-45da-a6f0-fd41ac645813" />
73
+ <img width="1100" height="700" alt="image" src="https://github.com/user-attachments/assets/3e0369ea-5fa4-469a-82c1-ed57d407e53d" />
80
74
 
81
- ### filter related nodes
82
- `shift` click a node to check related node, pick a field to narrow the result, picked node is marked as red.
75
+ ### focus on nodes
76
+ toggle focus to hide nodes not related with current picked one.
83
77
 
84
- <img width="1423" height="552" alt="image" src="https://github.com/user-attachments/assets/468a058d-afa1-4601-a7c5-c6aad6a8a557" />
78
+ before:
79
+ <img width="1066" height="941" alt="image" src="https://github.com/user-attachments/assets/39f30817-899a-4289-93f4-a1646d3441c1" />
80
+ after:
81
+ <img width="1061" height="937" alt="image" src="https://github.com/user-attachments/assets/79709b02-7571-43fc-abc9-17a287a97515" />
85
82
 
86
83
  ### view source code
87
- `alt` click a node to show source code or open file in vscode.
88
-
89
- <img width="1049" height="694" alt="image" src="https://github.com/user-attachments/assets/7839ac83-8d60-44ad-b1c9-9652a76339b1" />
90
-
91
- <img width="1042" height="675" alt="image" src="https://github.com/user-attachments/assets/38ae705f-5982-4a02-9c3f-038b1d00bcf6" />
92
-
93
- `alt` click a route to show source code or open file in vscode
94
-
95
- <img width="882" height="445" alt="image" src="https://github.com/user-attachments/assets/158560ef-63ca-4991-9b7d-587be4fa04e4" />
84
+ double click a node to show source code or open file in vscode.
85
+ <img width="1297" height="940" alt="image" src="https://github.com/user-attachments/assets/c8bb2e7d-b727-42a6-8c9e-64dce297d2d8" />
96
86
 
87
+ double click a route to show source code or open file in vscode
88
+ <img width="1132" height="824" alt="image" src="https://github.com/user-attachments/assets/b706e879-e4fc-48dd-ace1-99bf97e3ed6a" />
97
89
 
98
90
 
99
91
 
@@ -162,6 +154,9 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
162
154
  - [ ] animation effect for edges
163
155
  - [ ] customrized right click panel
164
156
  - [ ] show own dependencies
157
+ - [ ] sort field name
158
+ - [ ] set max limit for fields
159
+ - [ ] logging information
165
160
 
166
161
  ### plan:
167
162
  #### <0.9:
@@ -245,9 +240,11 @@ or you can open router_viz.dot with vscode extension `graphviz interactive previ
245
240
  - 0.11.4
246
241
  - [x] add loading for field detail panel
247
242
  - 0.11.5
248
- - [ ] logging information
249
- - [ ] sort field name
250
- - [ ] set max limit for fields
243
+ - [x] optimize open in swagger link
244
+ - [x] change jquery cdn
245
+ - 0.11.6
246
+ - [x] flag of loading full graph in first render or not
247
+ - [x] optimize loading static resource
251
248
 
252
249
  #### 0.12
253
250
  - [ ] add tests
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import Optional
2
+ from typing import Optional, Literal
3
3
  from fastapi import FastAPI, APIRouter
4
4
  from starlette.middleware.gzip import GZipMiddleware
5
5
  from pydantic import BaseModel
@@ -15,6 +15,7 @@ from fastapi_voyager.version import __version__
15
15
  WEB_DIR = Path(__file__).parent / "web"
16
16
  WEB_DIR.mkdir(exist_ok=True)
17
17
 
18
+ INITIAL_PAGE_POLICY = Literal['first', 'full', 'empty']
18
19
 
19
20
  class OptionParam(BaseModel):
20
21
  tags: list[Tag]
@@ -22,6 +23,7 @@ class OptionParam(BaseModel):
22
23
  dot: str
23
24
  enable_brief_mode: bool
24
25
  version: str
26
+ initial_page_policy: INITIAL_PAGE_POLICY
25
27
  swagger_url: Optional[str] = None
26
28
 
27
29
  class Payload(BaseModel):
@@ -42,6 +44,7 @@ def create_route(
42
44
  swagger_url: Optional[str] = None,
43
45
  module_prefix: Optional[str] = None,
44
46
  online_repo_url: Optional[str] = None,
47
+ initial_page_policy: INITIAL_PAGE_POLICY = 'first',
45
48
  ):
46
49
  """
47
50
  module_color: dict mapping module name to color string, e.g. {'models': 'lightblue'}
@@ -67,7 +70,8 @@ def create_route(
67
70
  dot=dot,
68
71
  enable_brief_mode=bool(module_prefix),
69
72
  version=__version__,
70
- swagger_url=swagger_url)
73
+ swagger_url=swagger_url,
74
+ initial_page_policy=initial_page_policy)
71
75
 
72
76
  @router.post("/dot", response_class=PlainTextResponse)
73
77
  def get_filtered_dot(payload: Payload) -> str:
@@ -213,13 +217,16 @@ def create_voyager(
213
217
  module_prefix: Optional[str] = None,
214
218
  swagger_url: Optional[str] = None,
215
219
  online_repo_url: Optional[str] = None,
220
+ initial_page_policy: INITIAL_PAGE_POLICY = 'first',
216
221
  ) -> FastAPI:
217
222
  router = create_route(
218
223
  target_app,
219
224
  module_color=module_color,
220
225
  module_prefix=module_prefix,
221
226
  swagger_url=swagger_url,
222
- online_repo_url=online_repo_url)
227
+ online_repo_url=online_repo_url,
228
+ initial_page_policy=initial_page_policy,
229
+ )
223
230
 
224
231
  app = FastAPI(title="fastapi-voyager demo server")
225
232
  if gzip_minimum_size is not None and gzip_minimum_size >= 0:
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.11.4"
2
+ __version__ = "0.11.6"
@@ -59,8 +59,39 @@
59
59
  .adjust-fit {
60
60
  height: calc(100vh - 54px);
61
61
  }
62
+ /* App boot loading overlay & gating */
63
+ #app-loading-overlay {
64
+ position: fixed;
65
+ inset: 0;
66
+ display: none;
67
+ align-items: center;
68
+ justify-content: center;
69
+ gap: 12px;
70
+ background: #ffffff;
71
+ z-index: 9999;
72
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
73
+ color: #009485;
74
+ }
75
+ .loading-text { font-size: 14px; }
76
+ .spinner {
77
+ width: 20px;
78
+ height: 20px;
79
+ border: 2px solid rgba(0, 148, 133, 0.2);
80
+ border-top-color: #009485;
81
+ border-radius: 50%;
82
+ animation: frv-spin 0.8s linear infinite;
83
+ }
84
+ @keyframes frv-spin { to { transform: rotate(360deg); } }
85
+ /* While JS not ready: hide app, show overlay */
86
+ body.app-loading #q-app { visibility: hidden; }
87
+ body.app-loading #app-loading-overlay { display: flex; }
62
88
  </style>
63
- <body>
89
+ <body class="app-loading">
90
+ <!-- App boot loading overlay: shown until JS initializes -->
91
+ <div id="app-loading-overlay" aria-busy="true" aria-live="polite">
92
+ <div class="spinner" aria-hidden="true"></div>
93
+ <div class="loading-text">Loading…</div>
94
+ </div>
64
95
  <div id="q-app">
65
96
  <q-layout view="hHh lpR fff">
66
97
  <q-header bordered class="bg-primary text-white">
@@ -75,7 +106,7 @@
75
106
  </div>
76
107
  <div class="col-auto" style="font-size: 16px">
77
108
  <q-option-group
78
- style="margin-left: 140px"
109
+ style="margin-left: 80px"
79
110
  v-model="state.showFields"
80
111
  :options="state.fieldOptions"
81
112
  @update:model-value="(val) => toggleShowField(val)"
@@ -218,9 +249,9 @@
218
249
  class="q-mr-sm"
219
250
  :name="state.tag == tag.name ? 'folder' : 'folder_open'"
220
251
  ></q-icon>
221
- <span>{{ tag.name }} <q-chip style="position:relative; top: -1px;" class="q-ml-sm" dense>{{ tag.routes.length }}</q-chip></span>
222
- <a target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name">
223
- <q-icon size="small" name="link"></q-icon>
252
+ <span>{{ tag.name }} <q-chip style="position:relative; top: -1px;" class="q-ml-md" dense>{{ tag.routes.length }}</q-chip></span>
253
+ <a v-if="state._tag == tag.name" target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name">
254
+ <q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
224
255
  </a>
225
256
  </div>
226
257
  </template>
@@ -241,8 +272,8 @@
241
272
  name="data_object"
242
273
  ></q-icon>
243
274
  {{ route.name }}
244
- <a target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name + '/' + route.unique_id">
245
- <q-icon size="small" name="link"></q-icon>
275
+ <a v-if="state.routeId == route.id" target="_blank" class="q-ml-md" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name + '/' + route.unique_id">
276
+ <q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
246
277
  </a>
247
278
  </span>
248
279
  </q-item-section>
@@ -410,11 +441,9 @@
410
441
  />
411
442
  </q-dialog>
412
443
  </div>
413
-
414
- <script
415
- type="text/javascript"
416
- src="https://code.jquery.com/jquery-2.1.3.min.js"
417
- ></script>
444
+ <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
445
+ <script src="fastapi-voyager-static/quasar.min.js"></script>
446
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" integrity="sha512-egJ/Y+22P9NQ9aIyVCh0VCOsfydyn8eNmqBy+y2CnJG+fpRIxXMS6jbWP8tVKp0jp+NO5n8WtMUAnNnGoJKi4w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
418
447
  <script
419
448
  src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"
420
449
  integrity="sha512-vc58qvvBdrDR4etbxMdlTt4GBQk1qjvyORR2nrsPsFPyrs+/u5c3+1Ct6upOgdZoIl7eq6k3a1UPDSNAQi/32A=="
@@ -422,18 +451,9 @@
422
451
  referrerpolicy="no-referrer"
423
452
  ></script>
424
453
  <script src="https://unpkg.com/@hpcc-js/wasm@2.20.0/dist/graphviz.umd.js"></script>
425
- <script src="https://unpkg.com/d3-graphviz@5.6.0/build/d3-graphviz.js"></script>
454
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-graphviz/5.6.0/d3-graphviz.min.js" integrity="sha512-Le8HpIpS2Tc7SDHLM6AOgAKq6ZR4uDwLhjPSR20DtXE5dFb9xECHRwgpc1nxxnU0Dv+j6FNMoSddky5gyvI3lQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
426
455
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js"></script>
427
456
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-color/2.1.2/jquery.color.min.js"></script>
428
-
429
- <!-- Add the following at the end of your body tag -->
430
- <script
431
- src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.5.22/vue.global.prod.min.js"
432
- integrity="sha512-Y9sKU0AwzWRxKSLd2i35LuDpUdHY/E9tJrKG0mxw0qYQ75VVgGYazIUQPwKhFK9vGO3jIgAtxLiSq8GQ7PDfUg=="
433
- crossorigin="anonymous"
434
- referrerpolicy="no-referrer"
435
- ></script>
436
- <script src="fastapi-voyager-static/quasar.min.js"></script>
437
457
  <script src="fastapi-voyager-static/graphviz.svg.js"></script>
438
458
  <!-- highlight.js minimal ES module load (python only) -->
439
459
  <link
@@ -441,10 +461,18 @@
441
461
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css"
442
462
  />
443
463
  <script type="module">
444
- import hljs from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/es/highlight.min.js";
445
- import python from "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/es/languages/python.min.js";
446
- hljs.registerLanguage("python", python);
447
- window.hljs = hljs;
464
+ window.addEventListener('DOMContentLoaded', async () => {
465
+ if (!window.hljs) {
466
+ try {
467
+ const { default: hljs } = await import('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/es/highlight.min.js');
468
+ const { default: python } = await import('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/es/languages/python.min.js');
469
+ hljs.registerLanguage("python", python);
470
+ window.hljs = hljs;
471
+ } catch (e) {
472
+ console.warn("Failed to preload highlight.js", e);
473
+ }
474
+ }
475
+ });
448
476
  </script>
449
477
  <script type="module" src="fastapi-voyager-static/vue-main.js"></script>
450
478
  </body>
@@ -34,7 +34,7 @@ const app = createApp({
34
34
  detailDrawer: false,
35
35
  drawerWidth: 300, // drawer 宽度
36
36
  version: "", // version from backend
37
- showModule: true
37
+ showModule: true,
38
38
  });
39
39
 
40
40
  const showDetail = ref(false);
@@ -82,6 +82,19 @@ const app = createApp({
82
82
  state.version = data.version || "";
83
83
  state.swaggerUrl = data.swagger_url || null
84
84
 
85
+ switch (data.initial_page_policy) {
86
+ case "full":
87
+ onGenerate()
88
+ return
89
+ case "empty":
90
+ return
91
+ case "first":
92
+ state.tag = state.rawTags.length > 0 ? state.rawTags[0].name : null;
93
+ state._tag = state.tag;
94
+ onGenerate();
95
+ return
96
+ }
97
+
85
98
  // default route options placeholder
86
99
  } catch (e) {
87
100
  console.error("Initial load failed", e);
@@ -226,6 +239,7 @@ const app = createApp({
226
239
 
227
240
  async function onReset() {
228
241
  state.tag = null;
242
+ state._tag = null;
229
243
  state.routeId = "";
230
244
  state.schemaId = null;
231
245
  // state.showFields = "object";
@@ -308,7 +322,9 @@ const app = createApp({
308
322
  }
309
323
 
310
324
  onMounted(async () => {
325
+ document.body.classList.remove("app-loading")
311
326
  await loadInitial();
327
+ // Reveal app content only after initial JS/data is ready
312
328
  });
313
329
 
314
330
  return {
@@ -8,4 +8,5 @@ app.mount(
8
8
  module_color={"tests.service": "red"},
9
9
  module_prefix="tests.service",
10
10
  swagger_url="/docs",
11
+ initial_page_policy='first',
11
12
  online_repo_url="https://github.com/allmonday/fastapi-voyager/blob/main"))