fastapi-voyager 0.8.1__py3-none-any.whl → 0.8.3__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.
fastapi_voyager/server.py CHANGED
@@ -32,8 +32,8 @@ class Payload(BaseModel):
32
32
  route_name: Optional[str] = None
33
33
  show_fields: str = 'object'
34
34
  show_meta: bool = False
35
- brief: bool = False,
36
- hide_primitive_route: bool = False,
35
+ brief: bool = False
36
+ hide_primitive_route: bool = False
37
37
 
38
38
  def create_route(
39
39
  target_app: FastAPI,
@@ -66,6 +66,7 @@ def create_route(
66
66
 
67
67
  @router.post("/dot", response_class=PlainTextResponse)
68
68
  def get_filtered_dot(payload: Payload) -> str:
69
+ print(payload)
69
70
  voyager = Voyager(
70
71
  include_tags=payload.tags,
71
72
  schema=payload.schema_name,
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.8.1"
2
+ __version__ = "0.8.3"
@@ -92,8 +92,8 @@ class Voyager:
92
92
  # filter by route_name (route.id) if provided
93
93
  if self.route_name is not None and route_id != self.route_name:
94
94
  continue
95
+
95
96
  is_primitive_response = is_non_pydantic_type(route.response_model)
96
-
97
97
  # filter primitive route if needed
98
98
  if self.hide_primitive_route and is_primitive_response:
99
99
  continue
@@ -286,7 +286,6 @@ class Voyager:
286
286
  return renderer.render_dot(_tags, _routes, _nodes, _links)
287
287
 
288
288
  def render_brief_dot(self, module_prefix: str | None = None):
289
- print(module_prefix)
290
289
  _tags, _routes, _nodes, _links = filter_subgraph(
291
290
  module_prefix=module_prefix,
292
291
  tags=self.tags,
@@ -110,7 +110,7 @@ export class GraphUI {
110
110
  });
111
111
  }
112
112
 
113
- async render(dotSrc) {
113
+ async render(dotSrc, resetZoom = true) {
114
114
  const height = this.options.height || "100%";
115
115
  return new Promise((resolve, reject) => {
116
116
  try {
@@ -126,7 +126,7 @@ export class GraphUI {
126
126
  .renderDot(dotSrc)
127
127
  .on("end", () => {
128
128
  $(this.selector).data("graphviz.svg").setup();
129
- this.graphviz.resetZoom();
129
+ if (resetZoom) this.graphviz.resetZoom();
130
130
  resolve();
131
131
  });
132
132
  } catch (err) {
@@ -89,13 +89,20 @@
89
89
  >
90
90
  <div class="row items-center q-col-gutter-md">
91
91
  <div class="col-auto">
92
- <div style="width: 282px; margin-left: 8px;" class="text-h6">FastAPI Voyager</div>
92
+ <div
93
+ style="width: 282px; margin-left: 8px"
94
+ class="text-h6 text-primary"
95
+ >
96
+ <q-icon class="q-mr-sm" name="satellite_alt"></q-icon>
97
+ <span> FastAPI Voyager </span>
98
+ </div>
93
99
  </div>
94
100
  <div class="col-auto">
95
101
  <div class="column">
96
102
  <q-option-group
97
103
  v-model="state.showFields"
98
104
  :options="state.fieldOptions"
105
+ @update:model-value="(val) => toggleShowField(val)"
99
106
  color="primary"
100
107
  type="radio"
101
108
  inline
@@ -104,7 +111,6 @@
104
111
  </div>
105
112
  </div>
106
113
 
107
-
108
114
  <!-- <div class="col-auto">
109
115
  <q-btn-dropdown
110
116
  class="q-ml-md"
@@ -126,11 +132,31 @@
126
132
  </div> -->
127
133
 
128
134
  <div class="col-auto q-ml-auto">
129
- <q-toggle class="q-ml-md" v-model="state.brief" label="Brief Mode" title="config module_prefix to enable it" dense />
130
- <q-toggle class="q-ml-md" v-model="state.hidePrimitiveRoute" label="Hide Primitive Routes" title="" dense />
135
+ <q-toggle
136
+ class="q-ml-md"
137
+ v-model="state.brief"
138
+ label="Brief Mode"
139
+ @update:model-value="(val) => toggleBrief(val)"
140
+ title="skip middle classes, config module_prefix to enable it"
141
+ dense
142
+ />
143
+ </div>
144
+ <div class="col-auto">
145
+ <q-toggle
146
+ v-model="state.hidePrimitiveRoute"
147
+ @update:model-value="(val) => toggleHidePrimitiveRoute(val)"
148
+ label="Hide Primitive"
149
+ title="hide routes return primitive"
150
+ dense
151
+ />
131
152
  </div>
132
153
  <div class="col-auto">
133
- <q-btn outline @click="onReset" title="may be very slow" label="Show All" />
154
+ <q-btn
155
+ outline
156
+ @click="onReset"
157
+ title="may be very slow"
158
+ label="Show All"
159
+ />
134
160
  </div>
135
161
  <div class="col-auto">
136
162
  <q-btn outline icon="search" label="Search" @click="showDialog()" />
@@ -171,57 +197,80 @@
171
197
  </div>
172
198
  </div>
173
199
  </div>
174
- <div class="row no-wrap" style="flex: 1 1 auto; min-height: 0; height: 100px;">
175
- <div
176
- class="column no-wrap"
177
- :style="{
178
- minWidth: '300px',
179
- width: '300px',
180
- borderRight: '1px solid #e0e0e0',
181
- backgroundColor: '#fff',
182
- minHeight: 0,
183
- }"
200
+ <div style="flex: 1 1 auto; min-height: 0;">
201
+ <q-splitter
202
+ v-model="state.splitter"
203
+ unit="px"
204
+ :limits="[200, 800]"
205
+ class="fit"
184
206
  >
185
- <q-scroll-area class="fit">
186
- <q-list dense separator>
187
- <q-expansion-item
188
- v-for="tag in state.rawTags"
189
- :key="tag.name"
190
- expand-separator
191
- :model-value="state.tag === tag.name"
192
- @update:model-value="(val) => toggleTag(tag.name, val)"
193
- :header-class="state.tag === tag.name ? 'text-primary text-bold' : ''"
194
- content-class="q-pa-none"
195
- >
196
- <template #header>
197
- <div class="row items-center" style="width: 100%">
198
- <div class="">{{ tag.name }}</div>
199
- </div>
200
- </template>
201
-
202
- <q-list separator>
203
- <q-item
204
- v-for="route in (state.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
205
- :key="route.id"
206
- clickable
207
- v-ripple
208
- :active="state.routeId === route.id"
209
- active-class=""
210
- @click="selectRoute(route.id)"
207
+ <template #before>
208
+ <div
209
+ id="tag-navigator"
210
+ class="column no-wrap"
211
+ :style="{
212
+ borderRight: '1px solid #e0e0e0',
213
+ backgroundColor: '#fff',
214
+ minHeight: 0,
215
+ height: '100%'
216
+ }"
217
+ >
218
+ <q-scroll-area class="fit">
219
+ <q-list dense separator>
220
+ <q-expansion-item
221
+ v-for="tag in state.rawTags"
222
+ :key="tag.name"
223
+ expand-separator
224
+ :model-value="state.tag === tag.name"
225
+ @update:model-value="(val) => toggleTag(tag.name, val)"
226
+ :header-class="state.tag === tag.name ? 'text-primary text-bold' : ''"
227
+ content-class="q-pa-none"
211
228
  >
212
- <q-item-section>
213
- <span class="q-ml-sm"> <span style="font-weight: bold;">⋅</span> &nbsp; {{ route.name }}</span>
214
- </q-item-section>
215
- </q-item>
216
- <q-item v-if="!tag.routes || tag.routes.length === 0" dense>
217
- <q-item-section class="text-grey-6">No routes</q-item-section>
218
- </q-item>
229
+ <template #header>
230
+ <div class="row items-center" style="width: 100%">
231
+ <div class="row items-end">
232
+ <q-icon
233
+ class="q-mr-sm"
234
+ :name="state.tag == tag.name ? 'folder' : 'folder_open'"
235
+ ></q-icon>
236
+ <span>{{ tag.name }}</span>
237
+ </div>
238
+ </div>
239
+ </template>
240
+
241
+ <q-list separator>
242
+ <q-item
243
+ v-for="route in (state.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
244
+ :key="route.id"
245
+ clickable
246
+ v-ripple
247
+ :active="state.routeId === route.id"
248
+ active-class=""
249
+ @click="selectRoute(route.id)"
250
+ >
251
+ <q-item-section>
252
+ <span class="q-ml-lg" style="white-space: nowrap">
253
+ <q-icon class="q-mr-sm" name="data_object"></q-icon>
254
+ {{ route.name }}
255
+ </span>
256
+ </q-item-section>
257
+ </q-item>
258
+ <q-item v-if="!tag.routes || tag.routes.length === 0" dense>
259
+ <q-item-section class="text-grey-6"
260
+ >No routes</q-item-section
261
+ >
262
+ </q-item>
263
+ </q-list>
264
+ </q-expansion-item>
219
265
  </q-list>
220
- </q-expansion-item>
221
- </q-list>
222
- </q-scroll-area>
223
- </div>
224
- <div id="graph"></div>
266
+ </q-scroll-area>
267
+ </div>
268
+ </template>
269
+
270
+ <template #after>
271
+ <div id="graph" class="fit"></div>
272
+ </template>
273
+ </q-splitter>
225
274
  </div>
226
275
 
227
276
  <!-- Detail Dialog -->
@@ -29,6 +29,8 @@ const app = createApp({
29
29
  rawSchemas: [], // [{ name, fullname }]
30
30
  rawSchemasFull: [], // full objects with source_code & fields
31
31
  initializing: true,
32
+ // Splitter size (left panel width in px)
33
+ splitter: 300,
32
34
  });
33
35
  const showDetail = ref(false);
34
36
  const showSchemaFieldFilter = ref(false);
@@ -115,7 +117,7 @@ const app = createApp({
115
117
  }
116
118
  }
117
119
 
118
- async function onGenerate() {
120
+ async function onGenerate(resetZoom=true) {
119
121
  state.generating = true;
120
122
  try {
121
123
  const payload = {
@@ -157,7 +159,7 @@ const app = createApp({
157
159
  },
158
160
  });
159
161
 
160
- await graphUI.render(dotText);
162
+ await graphUI.render(dotText, resetZoom);
161
163
  } catch (e) {
162
164
  console.error("Generate failed", e);
163
165
  } finally {
@@ -231,15 +233,16 @@ const app = createApp({
231
233
  state.tag = null;
232
234
  state.routeId = "";
233
235
  state.schemaFullname = null;
234
- state.showFields = "object";
236
+ // state.showFields = "object";
235
237
  state.brief = false;
236
238
  onGenerate()
237
- // await loadInitial();
238
239
  }
239
240
 
240
241
  function toggleTag(tagName, expanded = null) {
241
242
  if (expanded === true) {
242
243
  state.tag = tagName;
244
+ state.routeId = ''
245
+ onGenerate();
243
246
  return;
244
247
  }
245
248
  }
@@ -253,43 +256,20 @@ const app = createApp({
253
256
  onGenerate()
254
257
  }
255
258
 
256
- // react to tag changes to rebuild routes
257
- watch(
258
- () => state.tag,
259
- (val) => {
260
- if (!state.initializing) {
261
- state.routeId = ''
262
- onGenerate();
263
- }
264
- }
265
- );
266
-
267
- watch(
268
- () => state.showFields,
269
- () => {
270
- if (!state.initializing) {
271
- onGenerate();
272
- }
273
- }
274
- )
275
-
276
- watch(
277
- () => state.brief,
278
- () => {
279
- if (!state.initializing) {
280
- onGenerate();
281
- }
282
- }
283
- );
259
+ function toggleShowField(field) {
260
+ state.showFields = field;
261
+ onGenerate(false)
262
+ }
284
263
 
285
- watch(
286
- () => state.hidePrimitiveRoute,
287
- () => {
288
- if (!state.initializing) {
289
- onGenerate();
290
- }
291
- }
292
- );
264
+ function toggleBrief(val) {
265
+ state.brief = val;
266
+ onGenerate()
267
+ }
268
+
269
+ function toggleHidePrimitiveRoute(val) {
270
+ state.hidePrimitiveRoute = val;
271
+ onGenerate(false)
272
+ }
293
273
 
294
274
  onMounted(async () => {
295
275
  await loadInitial();
@@ -298,6 +278,8 @@ const app = createApp({
298
278
  return {
299
279
  state,
300
280
  toggleTag,
281
+ toggleBrief,
282
+ toggleHidePrimitiveRoute,
301
283
  selectRoute,
302
284
  onFilterTags,
303
285
  onFilterSchemas,
@@ -326,10 +308,15 @@ const app = createApp({
326
308
  // render graph dialog
327
309
  showRenderGraph,
328
310
  renderCoreData,
311
+ toggleShowField
329
312
  };
330
313
  },
331
314
  });
332
315
  app.use(window.Quasar);
316
+ // Set Quasar primary theme color to green
317
+ if (window.Quasar && typeof window.Quasar.setCssVar === 'function') {
318
+ window.Quasar.setCssVar('primary', '#009485');
319
+ }
333
320
  app.component("schema-field-filter", SchemaFieldFilter);
334
321
  app.component("schema-code-display", SchemaCodeDisplay);
335
322
  app.component("route-code-display", RouteCodeDisplay);
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.8.1
3
+ Version: 0.8.3
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
@@ -226,6 +226,8 @@ TODO: ...
226
226
  ## Changelog
227
227
 
228
228
  - 0.8:
229
+ - 0.8.2
230
+ - fix silly typo.
229
231
  - 0.8.1
230
232
  - add feature: hide primitive routes
231
233
  - 0.7:
@@ -3,18 +3,18 @@ fastapi_voyager/cli.py,sha256=2eixX7mtPsZvukc4vrwQOt6XTPJgHUKIGLBy3IIC2jE,11127
3
3
  fastapi_voyager/filter.py,sha256=2Yt37o8mhqSqleafO4YRrumh_ExYUqzXFOxQRPuTbAc,8078
4
4
  fastapi_voyager/module.py,sha256=Z2QHNmiLk6ZAJlm2nSmO875Q33TweSg8UxZSzIpU9zY,3499
5
5
  fastapi_voyager/render.py,sha256=qy3g1Rz1s8XkuR_6n1Q1YPwy_oMOjWjNswTHQjdz4N0,7765
6
- fastapi_voyager/server.py,sha256=t0Qby5No2XIVPPOn_wcJDOasJ05V7pQ4xtTDI8lgPSQ,4093
6
+ fastapi_voyager/server.py,sha256=Q9-f0frKHC4d0vN8ZasZyw6AsWKwLRB0P7z8dZ0lzjQ,4108
7
7
  fastapi_voyager/type.py,sha256=k62cDofqmy-2q5rInW5LydLaRuDpKLsdbapps8Osqys,1838
8
8
  fastapi_voyager/type_helper.py,sha256=hjBC4E0tgBpQDlYxGg74uK07SXjsrAgictEETJfIpYM,9231
9
- fastapi_voyager/version.py,sha256=_cyxd8_oDXTOvUSRCStr2n0IhvzG9mtX5ww-UZQFRbg,48
10
- fastapi_voyager/voyager.py,sha256=sy2chniANvZ5e4CjZzANTrA9RJcvr4aNoNygvusb5wc,11262
11
- fastapi_voyager/web/graph-ui.js,sha256=eEjDnJVMvk35LdRoxcqX_fZxLFS9_bUrGAZL6K2O5C0,4176
9
+ fastapi_voyager/version.py,sha256=oFsY5N35bJE0AakSBQ3J7JuwVWsgL4KEN-zNDsKGJ-Q,48
10
+ fastapi_voyager/voyager.py,sha256=Tz-cJW1Pg9Ei6zX2CPCdAnkTqErp2OIIhhxeeDd6Nss,11221
11
+ fastapi_voyager/web/graph-ui.js,sha256=0hqMCzsPJfhgWDuwiXVXaGQL-_7urT_zryo4sXMN8jQ,4209
12
12
  fastapi_voyager/web/graphviz.svg.css,sha256=zDCjjpT0Idufu5YOiZI76PL70-avP3vTyzGPh9M85Do,1563
13
13
  fastapi_voyager/web/graphviz.svg.js,sha256=lvAdbjHc-lMSk4GQp-iqYA2PCFX4RKnW7dFaoe0LUHs,16005
14
- fastapi_voyager/web/index.html,sha256=iv4Fd0RsX854ZWrfSnVn-369_ky9ubFlK36vLiAbd0w,12760
14
+ fastapi_voyager/web/index.html,sha256=AnsqXfzDrUPO12EWtiT_XJdJ6Kx3qBsRn1IfX393G48,14298
15
15
  fastapi_voyager/web/quasar.min.css,sha256=F5jQe7X2XT54VlvAaa2V3GsBFdVD-vxDZeaPLf6U9CU,203145
16
16
  fastapi_voyager/web/quasar.min.js,sha256=h0ftyPMW_CRiyzeVfQqiup0vrVt4_QWojpqmpnpn07E,502974
17
- fastapi_voyager/web/vue-main.js,sha256=f4re2Hys0FOli3R_AZ_byUd08YLScDZ01xf1hXeoHCA,9529
17
+ fastapi_voyager/web/vue-main.js,sha256=F-JUjwsN0Mdu5KWKNjqIEAzoucVQ9Zu-zE61fMDTdME,9551
18
18
  fastapi_voyager/web/component/render-graph.js,sha256=e8Xgh2Kl-nYU0P1gstEmAepCgFnk2J6UdxW8TlMafGs,2322
19
19
  fastapi_voyager/web/component/route-code-display.js,sha256=NECC1OGcPCdDfbghtRJEnmFM6HmH5J3win2ibapWPeA,2649
20
20
  fastapi_voyager/web/component/schema-code-display.js,sha256=oOusgTvCaWGnoKb-NBwu0SXqJJf2PTUtp3lUczokTBM,5515
@@ -26,8 +26,8 @@ fastapi_voyager/web/icon/favicon-16x16.png,sha256=JC07jEzfIYxBIoQn_FHXvyHuxESdhW
26
26
  fastapi_voyager/web/icon/favicon-32x32.png,sha256=C7v1h58cfWOsiLp9yOIZtlx-dLasBcq3NqpHVGRmpt4,1859
27
27
  fastapi_voyager/web/icon/favicon.ico,sha256=tZolYIXkkBcFiYl1A8ksaXN2VjGamzcSdes838dLvNc,15406
28
28
  fastapi_voyager/web/icon/site.webmanifest,sha256=ep4Hzh9zhmiZF2At3Fp1dQrYQuYF_3ZPZxc1KcGBvwQ,263
29
- fastapi_voyager-0.8.1.dist-info/METADATA,sha256=1t2J9aFVGAkBjY9dB_mnHsK8BUQJ2dnL6kycUX_PDhI,8044
30
- fastapi_voyager-0.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- fastapi_voyager-0.8.1.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
- fastapi_voyager-0.8.1.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
- fastapi_voyager-0.8.1.dist-info/RECORD,,
29
+ fastapi_voyager-0.8.3.dist-info/METADATA,sha256=bA7QuzvsXCjTX3vqS31SFzKrquWrad7NKHot6pXFRvw,8082
30
+ fastapi_voyager-0.8.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ fastapi_voyager-0.8.3.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
32
+ fastapi_voyager-0.8.3.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
33
+ fastapi_voyager-0.8.3.dist-info/RECORD,,