fastapi-voyager 0.12.4__py3-none-any.whl → 0.12.6__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/version.py +1 -1
- fastapi_voyager/web/component/demo.js +1 -1
- fastapi_voyager/web/component/schema-field-filter.js +0 -1
- fastapi_voyager/web/graph-ui.js +41 -21
- fastapi_voyager/web/graphviz.svg.js +82 -0
- fastapi_voyager/web/index.html +32 -113
- fastapi_voyager/web/store.js +87 -3
- fastapi_voyager/web/vue-main.js +86 -212
- {fastapi_voyager-0.12.4.dist-info → fastapi_voyager-0.12.6.dist-info}/METADATA +1 -1
- {fastapi_voyager-0.12.4.dist-info → fastapi_voyager-0.12.6.dist-info}/RECORD +13 -13
- {fastapi_voyager-0.12.4.dist-info → fastapi_voyager-0.12.6.dist-info}/WHEEL +0 -0
- {fastapi_voyager-0.12.4.dist-info → fastapi_voyager-0.12.6.dist-info}/entry_points.txt +0 -0
- {fastapi_voyager-0.12.4.dist-info → fastapi_voyager-0.12.6.dist-info}/licenses/LICENSE +0 -0
fastapi_voyager/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "0.12.
|
|
2
|
+
__version__ = "0.12.6"
|
|
@@ -14,7 +14,6 @@ export default defineComponent({
|
|
|
14
14
|
name: "SchemaFieldFilter",
|
|
15
15
|
props: {
|
|
16
16
|
schemaName: { type: String, default: null }, // external injection triggers auto-query
|
|
17
|
-
// externally provided schemas dict (state.rawSchemasFull): { [id]: schema }
|
|
18
17
|
schemas: { type: Object, default: () => ({}) },
|
|
19
18
|
},
|
|
20
19
|
emits: ["queried", "close"],
|
fastapi_voyager/web/graph-ui.js
CHANGED
|
@@ -9,14 +9,31 @@ export class GraphUI {
|
|
|
9
9
|
this._init();
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
_highlight() {
|
|
12
|
+
_highlight(mode = "bidirectional") {
|
|
13
13
|
let highlightedNodes = $();
|
|
14
14
|
for (const selection of this.currentSelection) {
|
|
15
|
-
const nodes = this._getAffectedNodes(selection.set,
|
|
15
|
+
const nodes = this._getAffectedNodes(selection.set, mode);
|
|
16
16
|
highlightedNodes = highlightedNodes.add(nodes);
|
|
17
17
|
}
|
|
18
18
|
if (this.gv) {
|
|
19
19
|
this.gv.highlight(highlightedNodes, true);
|
|
20
|
+
this.gv.bringToFront(highlightedNodes);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_highlightEdgeNodes() {
|
|
25
|
+
let highlightedNodes = $();
|
|
26
|
+
const [up, down, edge] = this.currentSelection
|
|
27
|
+
highlightedNodes = highlightedNodes.add(
|
|
28
|
+
this._getAffectedNodes(up.set, up.direction)
|
|
29
|
+
);
|
|
30
|
+
highlightedNodes = highlightedNodes.add(
|
|
31
|
+
this._getAffectedNodes(down.set, down.direction)
|
|
32
|
+
);
|
|
33
|
+
highlightedNodes = highlightedNodes.add(edge.set)
|
|
34
|
+
if (this.gv) {
|
|
35
|
+
this.gv.highlight(highlightedNodes, true);
|
|
36
|
+
this.gv.bringToFront(highlightedNodes);
|
|
20
37
|
}
|
|
21
38
|
}
|
|
22
39
|
|
|
@@ -65,6 +82,7 @@ export class GraphUI {
|
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
84
|
|
|
85
|
+
|
|
68
86
|
_init() {
|
|
69
87
|
const self = this;
|
|
70
88
|
$(this.selector).graphviz({
|
|
@@ -82,9 +100,7 @@ export class GraphUI {
|
|
|
82
100
|
}
|
|
83
101
|
const set = $();
|
|
84
102
|
set.push(this);
|
|
85
|
-
// const obj = { set, direction: "bidirectional" };
|
|
86
103
|
const schemaName = event.currentTarget.dataset.name;
|
|
87
|
-
// self.currentSelection = [obj];
|
|
88
104
|
if (schemaName) {
|
|
89
105
|
try {
|
|
90
106
|
self.options.onSchemaClick(schemaName);
|
|
@@ -93,6 +109,24 @@ export class GraphUI {
|
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
});
|
|
112
|
+
|
|
113
|
+
self.gv.edges().click(function (event) {
|
|
114
|
+
const up = $();
|
|
115
|
+
const down = $();
|
|
116
|
+
const edge = $();
|
|
117
|
+
const [upStreamNode, downStreamNode] = event.currentTarget.dataset.name.split("->");
|
|
118
|
+
const nodes = self.gv.nodesByName();
|
|
119
|
+
up.push(nodes[upStreamNode]);
|
|
120
|
+
down.push(nodes[downStreamNode]);
|
|
121
|
+
edge.push(this)
|
|
122
|
+
const upObj = { set: up, direction: "upstream" };
|
|
123
|
+
const downObj = { set: down, direction: "downstream" };
|
|
124
|
+
const edgeOjb = { set: edge, direction: "single"};
|
|
125
|
+
self.currentSelection = [upObj, downObj, edgeOjb];
|
|
126
|
+
|
|
127
|
+
self._highlightEdgeNodes();
|
|
128
|
+
})
|
|
129
|
+
|
|
96
130
|
self.gv.nodes().click(function (event) {
|
|
97
131
|
const set = $();
|
|
98
132
|
set.push(this);
|
|
@@ -100,7 +134,6 @@ export class GraphUI {
|
|
|
100
134
|
|
|
101
135
|
const schemaName = event.currentTarget.dataset.name;
|
|
102
136
|
if (event.shiftKey && self.options.onSchemaClick) {
|
|
103
|
-
// try data-name or title text
|
|
104
137
|
if (schemaName) {
|
|
105
138
|
try {
|
|
106
139
|
self.options.onSchemaShiftClick(schemaName);
|
|
@@ -119,23 +152,10 @@ export class GraphUI {
|
|
|
119
152
|
}
|
|
120
153
|
});
|
|
121
154
|
|
|
122
|
-
self.gv.clusters().click(function (event) {
|
|
123
|
-
const set = $();
|
|
124
|
-
set.push(this);
|
|
125
|
-
const obj = { set, direction: "single" };
|
|
126
|
-
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
127
|
-
self.currentSelection.push(obj);
|
|
128
|
-
} else {
|
|
129
|
-
self.currentSelection = [obj];
|
|
130
|
-
}
|
|
131
|
-
self._highlight();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// svg 背景点击高亮清空
|
|
135
155
|
$(document)
|
|
136
156
|
.off("click.graphui")
|
|
137
157
|
.on("click.graphui", function (evt) {
|
|
138
|
-
//
|
|
158
|
+
// if outside container, do nothing
|
|
139
159
|
const graphContainer = $(self.selector)[0];
|
|
140
160
|
if (
|
|
141
161
|
!graphContainer ||
|
|
@@ -146,9 +166,9 @@ export class GraphUI {
|
|
|
146
166
|
}
|
|
147
167
|
|
|
148
168
|
let isNode = false;
|
|
149
|
-
const $
|
|
169
|
+
const $everything = self.gv.$nodes.add(self.gv.$edges).add(self.gv.$clusters);
|
|
150
170
|
const node = evt.target.parentNode;
|
|
151
|
-
$
|
|
171
|
+
$everything.each(function () {
|
|
152
172
|
if (this === node) {
|
|
153
173
|
isNode = true;
|
|
154
174
|
}
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
url: null,
|
|
22
22
|
svg: null,
|
|
23
23
|
shrink: "0.125pt",
|
|
24
|
+
edgeHitPadding: 12,
|
|
25
|
+
pointerCursor: true,
|
|
24
26
|
tooltips: {
|
|
25
27
|
init: function ($graph) {
|
|
26
28
|
var $a = $(this);
|
|
@@ -168,9 +170,20 @@
|
|
|
168
170
|
var that = this;
|
|
169
171
|
var options = this.options;
|
|
170
172
|
|
|
173
|
+
if (type === "edge" && options.edgeHitPadding) {
|
|
174
|
+
this.ensureEdgeHitArea($el, options.edgeHitPadding);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (options.pointerCursor && (type === "edge" || type === "node")) {
|
|
178
|
+
this.setInteractiveCursor($el, type === "edge");
|
|
179
|
+
}
|
|
180
|
+
|
|
171
181
|
// save the colors of the paths, ellipses and polygons
|
|
172
182
|
$el.find("polygon, ellipse, path").each(function () {
|
|
173
183
|
var $this = $(this);
|
|
184
|
+
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
174
187
|
// save original colors
|
|
175
188
|
$this.data("graphviz.svg.color", {
|
|
176
189
|
fill: $this.attr("fill"),
|
|
@@ -314,6 +327,69 @@
|
|
|
314
327
|
}
|
|
315
328
|
};
|
|
316
329
|
|
|
330
|
+
GraphvizSvg.prototype.ensureEdgeHitArea = function ($edge, padding) {
|
|
331
|
+
var width = parseFloat(padding);
|
|
332
|
+
if (!isFinite(width) || width <= 0) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
var $paths = $edge
|
|
336
|
+
.children("path")
|
|
337
|
+
.filter(function () {
|
|
338
|
+
return $(this).attr("data-graphviz-hitbox") !== "true";
|
|
339
|
+
});
|
|
340
|
+
if (!$paths.length) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
$paths.each(function () {
|
|
344
|
+
var $path = $(this);
|
|
345
|
+
var $existing = $path.prev('[data-graphviz-hitbox="true"]');
|
|
346
|
+
if ($existing.length) {
|
|
347
|
+
$existing.attr("stroke-width", width);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
var clone = this.cloneNode(false);
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* gtp-5-codex:
|
|
354
|
+
* Cloning the edge paths without copying D3’s data binding caused those Cannot
|
|
355
|
+
* read properties of undefined (reading 'key') errors when d3-graphviz re-rendered.
|
|
356
|
+
* I now copy the original path’s bound datum (__data__) onto the transparent hitbox
|
|
357
|
+
* clone inside ensureEdgeHitArea, so D3 still finds the expected metadata.
|
|
358
|
+
*/
|
|
359
|
+
if (this.__data__) {
|
|
360
|
+
clone.__data__ = this.__data__;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
var $clone = $(clone);
|
|
364
|
+
$clone.attr({
|
|
365
|
+
"data-graphviz-hitbox": "true",
|
|
366
|
+
stroke: "transparent",
|
|
367
|
+
fill: "none",
|
|
368
|
+
"stroke-width": width,
|
|
369
|
+
});
|
|
370
|
+
$clone.attr("pointer-events", "stroke");
|
|
371
|
+
$clone.css("pointer-events", "stroke");
|
|
372
|
+
if (!$clone.attr("stroke-linecap")) {
|
|
373
|
+
$clone.attr("stroke-linecap", $path.attr("stroke-linecap") || "round");
|
|
374
|
+
}
|
|
375
|
+
$clone.insertBefore($path);
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
GraphvizSvg.prototype.setInteractiveCursor = function ($el, isEdge) {
|
|
380
|
+
$el.css("cursor", "pointer");
|
|
381
|
+
var selectors = "path, polygon, ellipse, rect, text";
|
|
382
|
+
$el.find(selectors).each(function () {
|
|
383
|
+
$(this).css("cursor", "pointer");
|
|
384
|
+
});
|
|
385
|
+
if (isEdge) {
|
|
386
|
+
$el.children('[data-graphviz-hitbox="true"]').css("cursor", "pointer");
|
|
387
|
+
}
|
|
388
|
+
$el.find("a").each(function () {
|
|
389
|
+
$(this).css("cursor", "pointer");
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
|
|
317
393
|
GraphvizSvg.prototype.convertToPx = function (val) {
|
|
318
394
|
var retval = val;
|
|
319
395
|
if (typeof val == "string") {
|
|
@@ -372,6 +448,9 @@
|
|
|
372
448
|
var bg = this.$element.css("background");
|
|
373
449
|
$el.find("polygon, ellipse, path").each(function () {
|
|
374
450
|
var $this = $(this);
|
|
451
|
+
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
375
454
|
var color = $this.data("graphviz.svg.color");
|
|
376
455
|
if (color.fill && color.fill != "none") {
|
|
377
456
|
$this.attr("fill", getColor(color.fill, bg)); // don't set fill if it's a path
|
|
@@ -386,6 +465,9 @@
|
|
|
386
465
|
GraphvizSvg.prototype.restoreElement = function ($el) {
|
|
387
466
|
$el.find("polygon, ellipse, path").each(function () {
|
|
388
467
|
var $this = $(this);
|
|
468
|
+
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
389
471
|
var color = $this.data("graphviz.svg.color");
|
|
390
472
|
if (color.fill && color.fill != "none") {
|
|
391
473
|
$this.attr("fill", color.fill); // don't set fill if it's a path
|
fastapi_voyager/web/index.html
CHANGED
|
@@ -105,13 +105,13 @@
|
|
|
105
105
|
>
|
|
106
106
|
<q-icon class="q-mr-sm" name="satellite_alt"></q-icon>
|
|
107
107
|
<span> FastAPI Voyager </span>
|
|
108
|
-
<span v-if="state.version" style="font-size: 12px; margin-left: 8px; font-weight: normal;">{{ state.version }}</span>
|
|
108
|
+
<span v-if="store.state.version" style="font-size: 12px; margin-left: 8px; font-weight: normal;">{{ store.state.version }}</span>
|
|
109
109
|
</div>
|
|
110
110
|
<div class="col-auto" style="font-size: 16px">
|
|
111
111
|
<q-option-group
|
|
112
112
|
style="margin-left: 80px"
|
|
113
|
-
v-model="state.showFields"
|
|
114
|
-
:options="state.fieldOptions"
|
|
113
|
+
v-model="store.state.filter.showFields"
|
|
114
|
+
:options="store.state.fieldOptions"
|
|
115
115
|
@update:model-value="(val) => toggleShowField(val)"
|
|
116
116
|
color="primary"
|
|
117
117
|
type="radio"
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
flat
|
|
138
138
|
label="Search"
|
|
139
139
|
class="q-mr-md"
|
|
140
|
-
@click="
|
|
140
|
+
@click="showSearchDialog()"
|
|
141
141
|
/>
|
|
142
142
|
</div>
|
|
143
143
|
<div class="col-auto">
|
|
@@ -176,8 +176,8 @@
|
|
|
176
176
|
</q-header>
|
|
177
177
|
|
|
178
178
|
<q-drawer
|
|
179
|
-
v-model="state.
|
|
180
|
-
:width="state.
|
|
179
|
+
v-model="store.state.rightDrawer.drawer"
|
|
180
|
+
:width="store.state.rightDrawer.width"
|
|
181
181
|
side="right"
|
|
182
182
|
style="border-left: 1px solid #888;"
|
|
183
183
|
bordered
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
|
|
202
202
|
<div style="z-index: 11; position: absolute; left: -17px; top: 9px">
|
|
203
203
|
<q-btn
|
|
204
|
-
@click="state.
|
|
204
|
+
@click="store.state.rightDrawer.drawer = !store.state.rightDrawer.drawer"
|
|
205
205
|
round
|
|
206
206
|
unelevated
|
|
207
207
|
color="primary"
|
|
@@ -210,14 +210,14 @@
|
|
|
210
210
|
/>
|
|
211
211
|
</div>
|
|
212
212
|
<schema-code-display
|
|
213
|
-
:schema-name="schemaCodeName"
|
|
214
|
-
:schemas="state.
|
|
213
|
+
:schema-name="store.state.schemaDetail.schemaCodeName"
|
|
214
|
+
:schemas="store.state.graph.schemaMap"
|
|
215
215
|
/>
|
|
216
216
|
</q-drawer>
|
|
217
217
|
|
|
218
218
|
<q-page-container>
|
|
219
219
|
<q-splitter
|
|
220
|
-
v-model="state.
|
|
220
|
+
v-model="store.state.leftPanel.width"
|
|
221
221
|
unit="px"
|
|
222
222
|
:limits="[200, 800]"
|
|
223
223
|
class="adjust-fit"
|
|
@@ -236,12 +236,12 @@
|
|
|
236
236
|
<q-scroll-area class="fit">
|
|
237
237
|
<q-list dense separator>
|
|
238
238
|
<q-expansion-item
|
|
239
|
-
v-for="tag in state.
|
|
239
|
+
v-for="tag in store.state.leftPanel.tags"
|
|
240
240
|
:key="tag.name"
|
|
241
241
|
expand-separator
|
|
242
|
-
:model-value="state._tag === tag.name"
|
|
242
|
+
:model-value="store.state.leftPanel._tag === tag.name"
|
|
243
243
|
@update:model-value="(val) => toggleTag(tag.name, val)"
|
|
244
|
-
:header-class="state.tag === tag.name ? 'text-primary text-bold' : ''"
|
|
244
|
+
:header-class="store.state.leftPanel.tag === tag.name ? 'text-primary text-bold' : ''"
|
|
245
245
|
content-class="q-pa-none"
|
|
246
246
|
>
|
|
247
247
|
<template #header>
|
|
@@ -249,21 +249,21 @@
|
|
|
249
249
|
<q-icon
|
|
250
250
|
style="vertical-align: top;"
|
|
251
251
|
class="q-mr-sm"
|
|
252
|
-
:name="state.tag == tag.name ? 'folder' : 'folder_open'"
|
|
252
|
+
:name="store.state.leftPanel.tag == tag.name ? 'folder' : 'folder_open'"
|
|
253
253
|
></q-icon>
|
|
254
254
|
<span>{{ tag.name }} <q-chip style="position:relative; top: -1px;" class="q-ml-md" dense>{{ tag.routes.length }}</q-chip></span>
|
|
255
|
-
<a v-if="state._tag == tag.name" target="_blank" class="q-ml-sm" v-if="state.
|
|
255
|
+
<a v-if="store.state.leftPanel._tag == tag.name" target="_blank" class="q-ml-sm" v-if="store.state.swagger.url" :href="store.state.swagger.url + '#/' + tag.name">
|
|
256
256
|
<q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
|
|
257
257
|
</a>
|
|
258
258
|
</div>
|
|
259
259
|
</template>
|
|
260
260
|
<q-list separator style="overflow: auto; max-height: 60vh;">
|
|
261
261
|
<q-item
|
|
262
|
-
v-for="route in (state.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
|
|
262
|
+
v-for="route in (store.state.filter.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
|
|
263
263
|
:key="route.id"
|
|
264
264
|
clickable
|
|
265
265
|
v-ripple
|
|
266
|
-
:active="state.routeId === route.id"
|
|
266
|
+
:active="store.state.leftPanel.routeId === route.id"
|
|
267
267
|
active-class=""
|
|
268
268
|
@click="selectRoute(route.id)"
|
|
269
269
|
>
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
name="data_object"
|
|
275
275
|
></q-icon>
|
|
276
276
|
{{ route.name }}
|
|
277
|
-
<a v-if="state.routeId == route.id" target="_blank" class="q-ml-md" v-if="state.
|
|
277
|
+
<a v-if="store.state.leftPanel.routeId == route.id" target="_blank" class="q-ml-md" v-if="store.state.swagger.url" :href="store.state.swagger.url + '#/' + tag.name + '/' + route.unique_id">
|
|
278
278
|
<q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
|
|
279
279
|
</a>
|
|
280
280
|
</span>
|
|
@@ -301,19 +301,9 @@
|
|
|
301
301
|
<div style="position: absolute; left: 8px; top: 8px; z-index: 10; background: rgba(255,255,255,0.85); border-radius: 4px; padding: 2px 8px;">
|
|
302
302
|
<div class="q-mt-sm">
|
|
303
303
|
<q-toggle
|
|
304
|
-
v-
|
|
305
|
-
v-show="schemaCodeName"
|
|
306
|
-
@update:model-value="val => onFocusChange(val)"
|
|
307
|
-
label="Focus"
|
|
304
|
+
v-if="store.state.modeControl.briefModeEnabled"
|
|
308
305
|
dense
|
|
309
|
-
|
|
310
|
-
/>
|
|
311
|
-
</div>
|
|
312
|
-
<div class="q-mt-sm">
|
|
313
|
-
<q-toggle
|
|
314
|
-
v-if="state.enableBriefMode"
|
|
315
|
-
dense
|
|
316
|
-
v-model="state.brief"
|
|
306
|
+
v-model="store.state.filter.brief"
|
|
317
307
|
label="Brief Mode"
|
|
318
308
|
@update:model-value="(val) => toggleBrief(val)"
|
|
319
309
|
title="skip middle classes, config module_prefix to enable it"
|
|
@@ -321,7 +311,7 @@
|
|
|
321
311
|
</div>
|
|
322
312
|
<div class="q-mt-sm">
|
|
323
313
|
<q-toggle
|
|
324
|
-
v-model="state.hidePrimitiveRoute"
|
|
314
|
+
v-model="store.state.filter.hidePrimitiveRoute"
|
|
325
315
|
@update:model-value="(val) => toggleHidePrimitiveRoute(val)"
|
|
326
316
|
label="Hide Primitive"
|
|
327
317
|
dense
|
|
@@ -330,7 +320,7 @@
|
|
|
330
320
|
</div>
|
|
331
321
|
<div class="q-mt-sm">
|
|
332
322
|
<q-toggle
|
|
333
|
-
v-model="state.showModule"
|
|
323
|
+
v-model="store.state.filter.showModule"
|
|
334
324
|
@update:model-value="(val) => toggleShowModule(val)"
|
|
335
325
|
label="Show Module Cluster"
|
|
336
326
|
dense
|
|
@@ -339,17 +329,13 @@
|
|
|
339
329
|
</div>
|
|
340
330
|
<div class="q-mt-sm">
|
|
341
331
|
<q-toggle
|
|
342
|
-
v-model="state.focus"
|
|
343
|
-
v-show="schemaCodeName"
|
|
332
|
+
v-model="store.state.modeControl.focus"
|
|
333
|
+
v-show="store.state.schemaDetail.schemaCodeName"
|
|
344
334
|
@update:model-value="val => onFocusChange(val)"
|
|
345
335
|
label="Focus"
|
|
346
336
|
dense
|
|
347
337
|
title="pick a schema and toggle focus on to display related nodes only"
|
|
348
338
|
/>
|
|
349
|
-
</div>
|
|
350
|
-
<!-- <div class="q-mt-sm">
|
|
351
|
-
<demo-component></demo-component>
|
|
352
|
-
</div> -->
|
|
353
339
|
</div>
|
|
354
340
|
</div>
|
|
355
341
|
</template>
|
|
@@ -359,95 +345,28 @@
|
|
|
359
345
|
|
|
360
346
|
<!-- Schema Field Filter Dialog -->
|
|
361
347
|
<q-dialog
|
|
362
|
-
v-model="
|
|
348
|
+
v-model="store.state.searchDialog.show"
|
|
363
349
|
:persistent="true"
|
|
364
350
|
:maximized="true"
|
|
365
351
|
>
|
|
366
352
|
<schema-field-filter
|
|
367
|
-
:schemas="state.
|
|
368
|
-
:schema-name="
|
|
369
|
-
@close="
|
|
353
|
+
:schemas="store.state.graph.schemaMap"
|
|
354
|
+
:schema-name="store.state.searchDialog.schema"
|
|
355
|
+
@close="store.state.searchDialog.show = false"
|
|
370
356
|
/>
|
|
371
357
|
</q-dialog>
|
|
372
358
|
|
|
373
|
-
<q-dialog v-model="
|
|
359
|
+
<q-dialog v-model="store.state.routeDetail.show" seamless position="bottom">
|
|
374
360
|
<q-card style="width: 1100px; max-width: 1100px; max-height: 40vh">
|
|
375
361
|
<route-code-display
|
|
376
|
-
:route-id="routeCodeId"
|
|
377
|
-
@close="
|
|
362
|
+
:route-id="store.state.routeDetail.routeCodeId"
|
|
363
|
+
@close="store.state.routeDetail.show = false"
|
|
378
364
|
/>
|
|
379
365
|
</q-card>
|
|
380
366
|
</q-dialog>
|
|
381
367
|
|
|
382
|
-
<!-- Dump Core Data Dialog -->
|
|
383
|
-
<q-dialog v-model="showDumpDialog" :maximized="true" :persistent="false">
|
|
384
|
-
<div style="height: 100%; position: relative; background: #fff">
|
|
385
|
-
<q-btn
|
|
386
|
-
flat
|
|
387
|
-
dense
|
|
388
|
-
round
|
|
389
|
-
icon="content_copy"
|
|
390
|
-
aria-label="Copy"
|
|
391
|
-
@click="copyDumpJson"
|
|
392
|
-
style="
|
|
393
|
-
position: absolute;
|
|
394
|
-
top: 6px;
|
|
395
|
-
right: 62px;
|
|
396
|
-
z-index: 11;
|
|
397
|
-
background: rgba(255, 255, 255, 0.85);
|
|
398
|
-
"
|
|
399
|
-
></q-btn>
|
|
400
|
-
<q-btn
|
|
401
|
-
flat
|
|
402
|
-
dense
|
|
403
|
-
round
|
|
404
|
-
icon="close"
|
|
405
|
-
aria-label="Close"
|
|
406
|
-
@click="showDumpDialog = false"
|
|
407
|
-
style="
|
|
408
|
-
position: absolute;
|
|
409
|
-
top: 6px;
|
|
410
|
-
right: 6px;
|
|
411
|
-
z-index: 11;
|
|
412
|
-
background: rgba(255, 255, 255, 0.85);
|
|
413
|
-
"
|
|
414
|
-
></q-btn>
|
|
415
|
-
<div>
|
|
416
|
-
<pre
|
|
417
|
-
style="padding: 20px; overflow: auto"
|
|
418
|
-
><code>{{ dumpJson }}</code></pre>
|
|
419
|
-
</div>
|
|
420
|
-
</div>
|
|
421
|
-
</q-dialog>
|
|
422
|
-
|
|
423
|
-
<!-- Import Core Data Dialog -->
|
|
424
|
-
<q-dialog v-model="showImportDialog" :persistent="true">
|
|
425
|
-
<q-card style="min-width: 70vw; max-width: 90vw">
|
|
426
|
-
<q-card-section class="text-h6">Import core data JSON</q-card-section>
|
|
427
|
-
<q-card-section>
|
|
428
|
-
<q-btn color="primary" label="Render" @click="onImportConfirm" />
|
|
429
|
-
</q-card-section>
|
|
430
|
-
<q-card-section>
|
|
431
|
-
<q-input
|
|
432
|
-
v-model="importJsonText"
|
|
433
|
-
type="textarea"
|
|
434
|
-
autogrow
|
|
435
|
-
filled
|
|
436
|
-
label="Paste JSON here"
|
|
437
|
-
/>
|
|
438
|
-
</q-card-section>
|
|
439
|
-
</q-card>
|
|
440
|
-
</q-dialog>
|
|
441
|
-
|
|
442
|
-
<!-- Render Graph Dialog (from imported core data) -->
|
|
443
|
-
<q-dialog v-model="showRenderGraph" :maximized="true" :persistent="false">
|
|
444
|
-
<render-graph
|
|
445
|
-
:core-data="renderCoreData"
|
|
446
|
-
@close="showRenderGraph = false"
|
|
447
|
-
/>
|
|
448
|
-
</q-dialog>
|
|
449
368
|
</div>
|
|
450
|
-
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
369
|
+
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
|
451
370
|
<script src="fastapi-voyager-static/quasar.min.js"></script>
|
|
452
371
|
<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>
|
|
453
372
|
<script
|
fastapi_voyager/web/store.js
CHANGED
|
@@ -1,12 +1,96 @@
|
|
|
1
|
-
const { reactive
|
|
1
|
+
const { reactive } = window.Vue;
|
|
2
2
|
|
|
3
3
|
const state = reactive({
|
|
4
|
-
|
|
4
|
+
item: {
|
|
5
|
+
count: 0
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
version: '',
|
|
9
|
+
|
|
10
|
+
swagger: {
|
|
11
|
+
url: ''
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
rightDrawer: {
|
|
15
|
+
drawer: false,
|
|
16
|
+
width: 300
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
fieldOptions: [
|
|
20
|
+
{ label: "No field", value: "single" },
|
|
21
|
+
{ label: "Object fields", value: "object" },
|
|
22
|
+
{ label: "All fields", value: "all" },
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
// tags and routes
|
|
26
|
+
leftPanel: {
|
|
27
|
+
width: 300,
|
|
28
|
+
tags: null,
|
|
29
|
+
tag: null,
|
|
30
|
+
_tag: null,
|
|
31
|
+
routeId: null,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
graph: {
|
|
35
|
+
schemaId: null,
|
|
36
|
+
schemaKeys: new Set(),
|
|
37
|
+
schemaMap: {},
|
|
38
|
+
routeItems: []
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
leftPanelFiltered: {
|
|
42
|
+
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// schema options, schema, fields
|
|
46
|
+
search: {
|
|
47
|
+
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// route information
|
|
52
|
+
routeDetail: {
|
|
53
|
+
show: false,
|
|
54
|
+
routeCodeId: ''
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// schema information
|
|
58
|
+
schemaDetail: {
|
|
59
|
+
show: false,
|
|
60
|
+
schemaCodeName: '',
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
searchDialog: {
|
|
64
|
+
show: false,
|
|
65
|
+
schema: null
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// global status
|
|
69
|
+
status: {
|
|
70
|
+
generating: false,
|
|
71
|
+
loading: false,
|
|
72
|
+
initializing: true,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// brief, hide primitive ...
|
|
76
|
+
modeControl: {
|
|
77
|
+
focus: false, // control the schema param
|
|
78
|
+
briefModeEnabled: false, // show brief mode toggle
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// api filters
|
|
82
|
+
filter: {
|
|
83
|
+
hidePrimitiveRoute: false,
|
|
84
|
+
showFields: 'object',
|
|
85
|
+
brief: false,
|
|
86
|
+
showModule: true,
|
|
87
|
+
}
|
|
88
|
+
|
|
5
89
|
})
|
|
6
90
|
|
|
7
91
|
const mutations = {
|
|
8
92
|
increment() {
|
|
9
|
-
state.count += 1
|
|
93
|
+
state.item.count += 1
|
|
10
94
|
}
|
|
11
95
|
}
|
|
12
96
|
|
fastapi_voyager/web/vue-main.js
CHANGED
|
@@ -4,67 +4,14 @@ import RouteCodeDisplay from "./component/route-code-display.js";
|
|
|
4
4
|
import Demo from './component/demo.js'
|
|
5
5
|
import RenderGraph from "./component/render-graph.js";
|
|
6
6
|
import { GraphUI } from "./graph-ui.js";
|
|
7
|
-
|
|
7
|
+
import { store } from './store.js'
|
|
8
|
+
|
|
9
|
+
const { createApp, onMounted, ref } = window.Vue;
|
|
8
10
|
|
|
9
11
|
const app = createApp({
|
|
10
12
|
setup() {
|
|
11
|
-
const state = reactive({
|
|
12
|
-
// options and selections
|
|
13
|
-
tag: null, // picked tag
|
|
14
|
-
_tag: null, // display tag
|
|
15
|
-
routeId: null, // picked route
|
|
16
|
-
schemaId: null, // picked schema
|
|
17
|
-
showFields: "object",
|
|
18
|
-
fieldOptions: [
|
|
19
|
-
{ label: "No field", value: "single" },
|
|
20
|
-
{ label: "Object fields", value: "object" },
|
|
21
|
-
{ label: "All fields", value: "all" },
|
|
22
|
-
],
|
|
23
|
-
enableBriefMode: false,
|
|
24
|
-
brief: false,
|
|
25
|
-
focus: false,
|
|
26
|
-
hidePrimitiveRoute: false,
|
|
27
|
-
generating: false,
|
|
28
|
-
swaggerUrl: null,
|
|
29
|
-
rawTags: [], // [{ name, routes: [{ id, name }] }]
|
|
30
|
-
rawSchemas: new Set(), // [{ name, id }]
|
|
31
|
-
rawSchemasFull: {}, // full schemas dict: { [schema.id]: schema }
|
|
32
|
-
initializing: true,
|
|
33
|
-
// Splitter size (left panel width in px)
|
|
34
|
-
splitter: 300,
|
|
35
|
-
detailDrawer: false,
|
|
36
|
-
drawerWidth: 300, // drawer 宽度
|
|
37
|
-
version: "", // version from backend
|
|
38
|
-
showModule: true,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const showDetail = ref(false);
|
|
42
|
-
const showSchemaFieldFilter = ref(false);
|
|
43
|
-
|
|
44
|
-
const showDumpDialog = ref(false);
|
|
45
|
-
const dumpJson = ref("");
|
|
46
|
-
const showImportDialog = ref(false);
|
|
47
|
-
const importJsonText = ref("");
|
|
48
|
-
|
|
49
|
-
const showRenderGraph = ref(false);
|
|
50
|
-
|
|
51
|
-
const renderCoreData = ref(null);
|
|
52
|
-
|
|
53
|
-
const schemaName = ref(""); // used by detail dialog
|
|
54
|
-
const schemaFieldFilterSchema = ref(null); // external schemaName for schema-field-filter
|
|
55
|
-
const schemaCodeName = ref("");
|
|
56
|
-
const routeCodeId = ref("");
|
|
57
|
-
const showRouteDetail = ref(false);
|
|
58
|
-
|
|
59
13
|
let graphUI = null;
|
|
60
14
|
|
|
61
|
-
function openDetail() {
|
|
62
|
-
showDetail.value = true;
|
|
63
|
-
}
|
|
64
|
-
function closeDetail() {
|
|
65
|
-
showDetail.value = false;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
15
|
function readQuerySelection() {
|
|
69
16
|
if (typeof window === "undefined") {
|
|
70
17
|
return { tag: null, route: null };
|
|
@@ -78,7 +25,7 @@ const app = createApp({
|
|
|
78
25
|
|
|
79
26
|
function findTagByRoute(routeId) {
|
|
80
27
|
return (
|
|
81
|
-
state.
|
|
28
|
+
store.state.leftPanel.tags.find((tag) =>
|
|
82
29
|
(tag.routes || []).some((route) => route.id === routeId)
|
|
83
30
|
)?.name || null
|
|
84
31
|
);
|
|
@@ -89,13 +36,13 @@ const app = createApp({
|
|
|
89
36
|
return;
|
|
90
37
|
}
|
|
91
38
|
const params = new URLSearchParams(window.location.search);
|
|
92
|
-
if (state.tag) {
|
|
93
|
-
params.set("tag", state.tag);
|
|
39
|
+
if (store.state.leftPanel.tag) {
|
|
40
|
+
params.set("tag", store.state.leftPanel.tag);
|
|
94
41
|
} else {
|
|
95
42
|
params.delete("tag");
|
|
96
43
|
}
|
|
97
|
-
if (state.routeId) {
|
|
98
|
-
params.set("route", state.routeId);
|
|
44
|
+
if (store.state.leftPanel.routeId) {
|
|
45
|
+
params.set("route", store.state.leftPanel.routeId);
|
|
99
46
|
} else {
|
|
100
47
|
params.delete("route");
|
|
101
48
|
}
|
|
@@ -108,45 +55,47 @@ const app = createApp({
|
|
|
108
55
|
|
|
109
56
|
function applySelectionFromQuery(selection) {
|
|
110
57
|
let applied = false;
|
|
111
|
-
if (selection.tag && state.
|
|
112
|
-
state.tag = selection.tag;
|
|
113
|
-
state._tag = selection.tag;
|
|
58
|
+
if (selection.tag && store.state.leftPanel.tags.some((tag) => tag.name === selection.tag)) {
|
|
59
|
+
store.state.leftPanel.tag = selection.tag;
|
|
60
|
+
store.state.leftPanel._tag = selection.tag;
|
|
114
61
|
applied = true;
|
|
115
62
|
}
|
|
116
|
-
if (selection.route && state.routeItems?.[selection.route]) {
|
|
117
|
-
state.routeId = selection.route;
|
|
63
|
+
if (selection.route && store.state.graph.routeItems?.[selection.route]) {
|
|
64
|
+
store.state.leftPanel.routeId = selection.route;
|
|
118
65
|
applied = true;
|
|
119
66
|
const inferredTag = findTagByRoute(selection.route);
|
|
120
67
|
if (inferredTag) {
|
|
121
|
-
state.tag = inferredTag;
|
|
122
|
-
state._tag = inferredTag;
|
|
68
|
+
store.state.leftPanel.tag = inferredTag;
|
|
69
|
+
store.state.leftPanel._tag = inferredTag;
|
|
123
70
|
}
|
|
124
71
|
}
|
|
125
72
|
return applied;
|
|
126
73
|
}
|
|
127
74
|
|
|
128
75
|
async function loadInitial() {
|
|
129
|
-
state.initializing = true;
|
|
76
|
+
store.state.initializing = true;
|
|
130
77
|
try {
|
|
131
78
|
const res = await fetch("dot");
|
|
132
79
|
const data = await res.json();
|
|
133
|
-
state.
|
|
80
|
+
store.state.leftPanel.tags = Array.isArray(data.tags) ? data.tags : [];
|
|
81
|
+
|
|
134
82
|
const schemasArr = Array.isArray(data.schemas) ? data.schemas : [];
|
|
135
83
|
// Build dict keyed by id for faster lookups and simpler prop passing
|
|
136
|
-
|
|
84
|
+
const schemaMap = Object.fromEntries(
|
|
137
85
|
schemasArr.map((s) => [s.id, s])
|
|
138
86
|
);
|
|
139
|
-
state.
|
|
140
|
-
state.
|
|
87
|
+
store.state.graph.schemaMap = schemaMap
|
|
88
|
+
store.state.graph.schemaKeys = new Set(Object.keys(schemaMap));
|
|
89
|
+
store.state.graph.routeItems = data.tags
|
|
141
90
|
.map((t) => t.routes)
|
|
142
91
|
.flat()
|
|
143
92
|
.reduce((acc, r) => {
|
|
144
93
|
acc[r.id] = r;
|
|
145
94
|
return acc;
|
|
146
95
|
}, {});
|
|
147
|
-
state.
|
|
148
|
-
state.version = data.version || "";
|
|
149
|
-
state.
|
|
96
|
+
store.state.modeControl.briefModeEnabled = data.enable_brief_mode || false;
|
|
97
|
+
store.state.version = data.version || "";
|
|
98
|
+
store.state.swagger.url = data.swagger_url || null
|
|
150
99
|
|
|
151
100
|
const querySelection = readQuerySelection();
|
|
152
101
|
const restoredFromQuery = applySelectionFromQuery(querySelection);
|
|
@@ -163,8 +112,8 @@ const app = createApp({
|
|
|
163
112
|
case "empty":
|
|
164
113
|
return
|
|
165
114
|
case "first":
|
|
166
|
-
state.tag = state.
|
|
167
|
-
state._tag = state.tag;
|
|
115
|
+
store.state.leftPanel.tag = store.state.leftPanel.tags.length > 0 ? store.state.leftPanel.tags[0].name : null;
|
|
116
|
+
store.state.leftPanel._tag = store.state.leftPanel.tag;
|
|
168
117
|
onGenerate();
|
|
169
118
|
return
|
|
170
119
|
}
|
|
@@ -173,7 +122,7 @@ const app = createApp({
|
|
|
173
122
|
} catch (e) {
|
|
174
123
|
console.error("Initial load failed", e);
|
|
175
124
|
} finally {
|
|
176
|
-
state.initializing = false;
|
|
125
|
+
store.state.initializing = false;
|
|
177
126
|
}
|
|
178
127
|
}
|
|
179
128
|
|
|
@@ -183,24 +132,24 @@ const app = createApp({
|
|
|
183
132
|
} else {
|
|
184
133
|
await onGenerate(false);
|
|
185
134
|
setTimeout(() => {
|
|
186
|
-
const ele = $(`[data-name='${schemaCodeName
|
|
135
|
+
const ele = $(`[data-name='${store.state.schemaDetail.schemaCodeName}'] polygon`);
|
|
187
136
|
ele.dblclick();
|
|
188
137
|
}, 1);
|
|
189
138
|
}
|
|
190
139
|
}
|
|
191
140
|
|
|
192
141
|
async function onGenerate(resetZoom = true) {
|
|
193
|
-
const schema_name = state.focus ? schemaCodeName
|
|
194
|
-
state.generating = true;
|
|
142
|
+
const schema_name = store.state.modeControl.focus ? store.state.schemaDetail.schemaCodeName : null;
|
|
143
|
+
store.state.generating = true;
|
|
195
144
|
try {
|
|
196
145
|
const payload = {
|
|
197
|
-
tags: state.tag ? [state.tag] : null,
|
|
146
|
+
tags: store.state.leftPanel.tag ? [store.state.leftPanel.tag] : null,
|
|
198
147
|
schema_name: schema_name || null,
|
|
199
|
-
route_name: state.routeId || null,
|
|
200
|
-
show_fields: state.showFields,
|
|
201
|
-
brief: state.brief,
|
|
202
|
-
hide_primitive_route: state.hidePrimitiveRoute,
|
|
203
|
-
show_module: state.showModule,
|
|
148
|
+
route_name: store.state.leftPanel.routeId || null,
|
|
149
|
+
show_fields: store.state.filter.showFields,
|
|
150
|
+
brief: store.state.modeControl.brief,
|
|
151
|
+
hide_primitive_route: store.state.filter.hidePrimitiveRoute,
|
|
152
|
+
show_module: store.state.filter.showModule,
|
|
204
153
|
};
|
|
205
154
|
const res = await fetch("dot", {
|
|
206
155
|
method: "POST",
|
|
@@ -213,21 +162,21 @@ const app = createApp({
|
|
|
213
162
|
if (!graphUI) {
|
|
214
163
|
graphUI = new GraphUI("#graph", {
|
|
215
164
|
onSchemaShiftClick: (id) => {
|
|
216
|
-
if (state.
|
|
165
|
+
if (store.state.graph.schemaKeys.has(id)) {
|
|
217
166
|
resetDetailPanels();
|
|
218
|
-
|
|
219
|
-
|
|
167
|
+
store.state.searchDialog.show = true;
|
|
168
|
+
store.state.searchDialog.schema = id;
|
|
220
169
|
}
|
|
221
170
|
},
|
|
222
171
|
onSchemaClick: (id) => {
|
|
223
172
|
resetDetailPanels();
|
|
224
|
-
if (state.
|
|
225
|
-
schemaCodeName
|
|
226
|
-
state.
|
|
173
|
+
if (store.state.graph.schemaKeys.has(id)) {
|
|
174
|
+
store.state.schemaDetail.schemaCodeName = id;
|
|
175
|
+
store.state.rightDrawer.drawer = true;
|
|
227
176
|
}
|
|
228
|
-
if (id in state.routeItems) {
|
|
229
|
-
routeCodeId
|
|
230
|
-
|
|
177
|
+
if (id in store.state.graph.routeItems) {
|
|
178
|
+
store.state.routeDetail.routeCodeId = id;
|
|
179
|
+
store.state.routeDetail.show = true;
|
|
231
180
|
}
|
|
232
181
|
},
|
|
233
182
|
resetCb: () => {
|
|
@@ -239,149 +188,95 @@ const app = createApp({
|
|
|
239
188
|
} catch (e) {
|
|
240
189
|
console.error("Generate failed", e);
|
|
241
190
|
} finally {
|
|
242
|
-
state.generating = false;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async function onDumpData() {
|
|
247
|
-
try {
|
|
248
|
-
const payload = {
|
|
249
|
-
tags: state.tag ? [state.tag] : null,
|
|
250
|
-
schema_name: state.schemaId || null,
|
|
251
|
-
route_name: state.routeId || null,
|
|
252
|
-
show_fields: state.showFields,
|
|
253
|
-
brief: state.brief,
|
|
254
|
-
};
|
|
255
|
-
const res = await fetch("dot-core-data", {
|
|
256
|
-
method: "POST",
|
|
257
|
-
headers: { "Content-Type": "application/json" },
|
|
258
|
-
body: JSON.stringify(payload),
|
|
259
|
-
});
|
|
260
|
-
const json = await res.json();
|
|
261
|
-
dumpJson.value = JSON.stringify(json, null, 2);
|
|
262
|
-
showDumpDialog.value = true;
|
|
263
|
-
} catch (e) {
|
|
264
|
-
console.error("Dump data failed", e);
|
|
191
|
+
store.state.generating = false;
|
|
265
192
|
}
|
|
266
193
|
}
|
|
267
194
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (window.Quasar?.Notify) {
|
|
272
|
-
window.Quasar.Notify.create({ type: "positive", message: "Copied" });
|
|
273
|
-
}
|
|
274
|
-
} catch (e) {
|
|
275
|
-
console.error("Copy failed", e);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function openImportDialog() {
|
|
280
|
-
importJsonText.value = "";
|
|
281
|
-
showImportDialog.value = true;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
async function onImportConfirm() {
|
|
285
|
-
let payloadObj = null;
|
|
286
|
-
try {
|
|
287
|
-
payloadObj = JSON.parse(importJsonText.value || "{}");
|
|
288
|
-
} catch (e) {
|
|
289
|
-
if (window.Quasar?.Notify) {
|
|
290
|
-
window.Quasar.Notify.create({
|
|
291
|
-
type: "negative",
|
|
292
|
-
message: "Invalid JSON",
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
// Move the request into RenderGraph component: pass the parsed object and let the component call /dot-render-core-data
|
|
298
|
-
renderCoreData.value = payloadObj;
|
|
299
|
-
showRenderGraph.value = true;
|
|
300
|
-
showImportDialog.value = false;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function showDialog() {
|
|
304
|
-
schemaFieldFilterSchema.value = null;
|
|
305
|
-
showSchemaFieldFilter.value = true;
|
|
195
|
+
function showSearchDialog() {
|
|
196
|
+
store.state.searchDialog.show = true;
|
|
197
|
+
store.state.searchDialog.schema = null;
|
|
306
198
|
}
|
|
307
199
|
|
|
308
200
|
function resetDetailPanels() {
|
|
309
|
-
state.
|
|
310
|
-
|
|
311
|
-
schemaCodeName
|
|
201
|
+
store.state.rightDrawer.drawer = false;
|
|
202
|
+
store.state.routeDetail.show = false
|
|
203
|
+
store.state.schemaDetail.schemaCodeName = "";
|
|
312
204
|
}
|
|
313
205
|
|
|
314
206
|
async function onReset() {
|
|
315
|
-
state.tag = null;
|
|
316
|
-
state._tag = null;
|
|
317
|
-
state.routeId =
|
|
318
|
-
|
|
207
|
+
store.state.leftPanel.tag = null;
|
|
208
|
+
store.state.leftPanel._tag = null;
|
|
209
|
+
store.state.leftPanel.routeId = null;
|
|
210
|
+
|
|
211
|
+
store.state.graph.schemaId = null;
|
|
212
|
+
|
|
319
213
|
// state.showFields = "object";
|
|
320
|
-
state.focus = false;
|
|
321
|
-
schemaCodeName
|
|
214
|
+
store.state.modeControl.focus = false;
|
|
215
|
+
store.state.schemaDetail.schemaCodeName = "";
|
|
322
216
|
onGenerate();
|
|
323
217
|
syncSelectionToUrl();
|
|
324
218
|
}
|
|
325
219
|
|
|
326
220
|
function toggleTag(tagName, expanded = null) {
|
|
327
221
|
if (expanded === true) {
|
|
328
|
-
state._tag = tagName;
|
|
329
|
-
state.tag = tagName;
|
|
330
|
-
state.routeId = "";
|
|
331
|
-
|
|
332
|
-
|
|
222
|
+
store.state.leftPanel._tag = tagName;
|
|
223
|
+
store.state.leftPanel.tag = tagName;
|
|
224
|
+
store.state.leftPanel.routeId = "";
|
|
225
|
+
|
|
226
|
+
store.state.modeControl.focus = false;
|
|
227
|
+
store.state.schemaDetail.schemaCodeName = "";
|
|
333
228
|
onGenerate();
|
|
334
229
|
} else {
|
|
335
|
-
state._tag = null;
|
|
230
|
+
store.state.leftPanel._tag = null;
|
|
336
231
|
}
|
|
337
232
|
|
|
338
|
-
state.
|
|
339
|
-
|
|
233
|
+
store.state.rightDrawer.drawer = false;
|
|
234
|
+
store.state.routeDetail.show = false
|
|
340
235
|
syncSelectionToUrl();
|
|
341
236
|
}
|
|
342
237
|
|
|
343
238
|
function selectRoute(routeId) {
|
|
344
|
-
if (state.routeId === routeId) {
|
|
345
|
-
state.routeId = "";
|
|
239
|
+
if (store.state.leftPanel.routeId === routeId) {
|
|
240
|
+
store.state.leftPanel.routeId = "";
|
|
346
241
|
} else {
|
|
347
|
-
state.routeId = routeId;
|
|
242
|
+
store.state.leftPanel.routeId = routeId;
|
|
348
243
|
}
|
|
349
|
-
state.
|
|
350
|
-
|
|
351
|
-
state.focus = false;
|
|
352
|
-
schemaCodeName
|
|
244
|
+
store.state.rightDrawer.drawer = false;
|
|
245
|
+
store.state.routeDetail.show = false
|
|
246
|
+
store.state.modeControl.focus = false;
|
|
247
|
+
store.state.schemaDetail.schemaCodeName = "";
|
|
353
248
|
onGenerate();
|
|
354
249
|
syncSelectionToUrl();
|
|
355
250
|
}
|
|
356
251
|
|
|
357
252
|
function toggleShowModule(val) {
|
|
358
|
-
state.showModule = val;
|
|
253
|
+
store.state.filter.showModule = val;
|
|
359
254
|
onGenerate()
|
|
360
255
|
}
|
|
361
256
|
|
|
362
257
|
function toggleShowField(field) {
|
|
363
|
-
state.showFields = field;
|
|
258
|
+
store.state.filter.showFields = field;
|
|
364
259
|
onGenerate(false);
|
|
365
260
|
}
|
|
366
261
|
|
|
367
262
|
function toggleBrief(val) {
|
|
368
|
-
state.brief = val;
|
|
263
|
+
store.state.modeControl.brief = val;
|
|
369
264
|
onGenerate();
|
|
370
265
|
}
|
|
371
266
|
|
|
372
267
|
function toggleHidePrimitiveRoute(val) {
|
|
373
|
-
state.hidePrimitiveRoute = val;
|
|
268
|
+
store.state.filter.hidePrimitiveRoute = val;
|
|
374
269
|
onGenerate(false);
|
|
375
270
|
}
|
|
376
271
|
|
|
377
272
|
function startDragDrawer(e) {
|
|
378
273
|
const startX = e.clientX;
|
|
379
|
-
const startWidth = state.
|
|
274
|
+
const startWidth = store.state.rightDrawer.width;
|
|
380
275
|
|
|
381
276
|
function onMouseMove(moveEvent) {
|
|
382
277
|
const deltaX = startX - moveEvent.clientX;
|
|
383
278
|
const newWidth = Math.max(300, Math.min(800, startWidth + deltaX));
|
|
384
|
-
state.
|
|
279
|
+
store.state.rightDrawer.width = newWidth;
|
|
385
280
|
}
|
|
386
281
|
|
|
387
282
|
function onMouseUp() {
|
|
@@ -405,39 +300,18 @@ const app = createApp({
|
|
|
405
300
|
});
|
|
406
301
|
|
|
407
302
|
return {
|
|
408
|
-
|
|
303
|
+
store,
|
|
409
304
|
toggleTag,
|
|
410
305
|
toggleBrief,
|
|
411
306
|
toggleHidePrimitiveRoute,
|
|
412
307
|
selectRoute,
|
|
413
308
|
onGenerate,
|
|
414
309
|
onReset,
|
|
415
|
-
|
|
416
|
-
showRouteDetail,
|
|
417
|
-
openDetail,
|
|
418
|
-
closeDetail,
|
|
419
|
-
schemaName,
|
|
420
|
-
showSchemaFieldFilter,
|
|
421
|
-
schemaFieldFilterSchema,
|
|
422
|
-
showDialog,
|
|
423
|
-
schemaCodeName,
|
|
424
|
-
routeCodeId,
|
|
425
|
-
// dump/import
|
|
426
|
-
showDumpDialog,
|
|
427
|
-
dumpJson,
|
|
428
|
-
copyDumpJson,
|
|
429
|
-
onDumpData,
|
|
430
|
-
showImportDialog,
|
|
431
|
-
importJsonText,
|
|
432
|
-
openImportDialog,
|
|
433
|
-
onImportConfirm,
|
|
434
|
-
// render graph dialog
|
|
435
|
-
showRenderGraph,
|
|
436
|
-
renderCoreData,
|
|
310
|
+
showSearchDialog,
|
|
437
311
|
toggleShowField,
|
|
438
312
|
startDragDrawer,
|
|
439
313
|
onFocusChange,
|
|
440
|
-
toggleShowModule
|
|
314
|
+
toggleShowModule,
|
|
441
315
|
};
|
|
442
316
|
},
|
|
443
317
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-voyager
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.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
|
|
@@ -6,21 +6,21 @@ fastapi_voyager/render.py,sha256=7jSChISqTV2agaO55thhwyrOhqVOMux4x7k8rSQROnU,996
|
|
|
6
6
|
fastapi_voyager/server.py,sha256=MZNRpcXor2q8Rj3OSf6EH8NkgDChxfzUtnIY8ilRkaY,7053
|
|
7
7
|
fastapi_voyager/type.py,sha256=7EL1zaIwKVRGpLig7fqaOrZGN5k0Rm31C9COfck3CSs,1750
|
|
8
8
|
fastapi_voyager/type_helper.py,sha256=JXD_OE_xTARkGjWDsnO_xfvyZ0vcwViYyqCp6oEHBTM,9719
|
|
9
|
-
fastapi_voyager/version.py,sha256=
|
|
9
|
+
fastapi_voyager/version.py,sha256=gCsZjglIeKj6Gr4eowqOBTgIdgKANz1jfSVP3qdkSn4,49
|
|
10
10
|
fastapi_voyager/voyager.py,sha256=LiRUb0ZG2cfnyY_pwRqoeZjxb6Pu6xy_lqPiMupxoKM,13510
|
|
11
|
-
fastapi_voyager/web/graph-ui.js,sha256=
|
|
11
|
+
fastapi_voyager/web/graph-ui.js,sha256=wxKjmVEpaMJZXMTW7tJ4BiaACCI1oVN6cx7hSMI0K5U,6428
|
|
12
12
|
fastapi_voyager/web/graphviz.svg.css,sha256=zDCjjpT0Idufu5YOiZI76PL70-avP3vTyzGPh9M85Do,1563
|
|
13
|
-
fastapi_voyager/web/graphviz.svg.js,sha256=
|
|
14
|
-
fastapi_voyager/web/index.html,sha256=
|
|
13
|
+
fastapi_voyager/web/graphviz.svg.js,sha256=wZwz_lBztoXmujEN21P0w-HMpdmbqPwTQQ6Ebxd9rGo,18569
|
|
14
|
+
fastapi_voyager/web/index.html,sha256=3HixCgVF9VtTx89G3usDXpEh7NZnLk_p9siz4OUVUHE,17444
|
|
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/store.js,sha256=
|
|
18
|
-
fastapi_voyager/web/vue-main.js,sha256=
|
|
19
|
-
fastapi_voyager/web/component/demo.js,sha256=
|
|
17
|
+
fastapi_voyager/web/store.js,sha256=fW-3uUwWNUsW8vXbTqltHvvlIroBeZTJvFkMSjuWdVg,1630
|
|
18
|
+
fastapi_voyager/web/vue-main.js,sha256=H50LbB-g3jWaz3Xv2O8RgajlibjtoiHu1HDTumjf7sY,10766
|
|
19
|
+
fastapi_voyager/web/component/demo.js,sha256=bQb16Un4XZ3Mf8qL6gvyrXe_mmA3V3mSIRMQAWg2MNk,352
|
|
20
20
|
fastapi_voyager/web/component/render-graph.js,sha256=e8Xgh2Kl-nYU0P1gstEmAepCgFnk2J6UdxW8TlMafGs,2322
|
|
21
21
|
fastapi_voyager/web/component/route-code-display.js,sha256=8NJPPjNRUC21gjpY8XYEQs4RBbhX1pCiqEhJp39ku6k,3678
|
|
22
22
|
fastapi_voyager/web/component/schema-code-display.js,sha256=qKUMV2RFQzR8deof2iC4vyp65UaWadtVsDAXjY-i3vE,7042
|
|
23
|
-
fastapi_voyager/web/component/schema-field-filter.js,sha256=
|
|
23
|
+
fastapi_voyager/web/component/schema-field-filter.js,sha256=i6Zp02wfSBWQb4AJ7H_Q9vgCVzLaVnH1I2JIot0sV-0,6172
|
|
24
24
|
fastapi_voyager/web/icon/android-chrome-192x192.png,sha256=35sBy6jmUFJCcquStaafHH1qClZIbd-X3PIKSeLkrNo,37285
|
|
25
25
|
fastapi_voyager/web/icon/android-chrome-512x512.png,sha256=eb2eDjCwIruc05029_0L9hcrkVkv8KceLn1DJMYU0zY,210789
|
|
26
26
|
fastapi_voyager/web/icon/apple-touch-icon.png,sha256=gnWK46tPnvSw1-oYZjgI02wpoO4OrIzsVzGHC5oKWO0,33187
|
|
@@ -28,8 +28,8 @@ fastapi_voyager/web/icon/favicon-16x16.png,sha256=JC07jEzfIYxBIoQn_FHXvyHuxESdhW
|
|
|
28
28
|
fastapi_voyager/web/icon/favicon-32x32.png,sha256=C7v1h58cfWOsiLp9yOIZtlx-dLasBcq3NqpHVGRmpt4,1859
|
|
29
29
|
fastapi_voyager/web/icon/favicon.ico,sha256=tZolYIXkkBcFiYl1A8ksaXN2VjGamzcSdes838dLvNc,15406
|
|
30
30
|
fastapi_voyager/web/icon/site.webmanifest,sha256=ep4Hzh9zhmiZF2At3Fp1dQrYQuYF_3ZPZxc1KcGBvwQ,263
|
|
31
|
-
fastapi_voyager-0.12.
|
|
32
|
-
fastapi_voyager-0.12.
|
|
33
|
-
fastapi_voyager-0.12.
|
|
34
|
-
fastapi_voyager-0.12.
|
|
35
|
-
fastapi_voyager-0.12.
|
|
31
|
+
fastapi_voyager-0.12.6.dist-info/METADATA,sha256=sPfeuEuiQ4Wf_lOwdJL5BMTBIZXzT6Yk4zm175J_Pi4,6523
|
|
32
|
+
fastapi_voyager-0.12.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
33
|
+
fastapi_voyager-0.12.6.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
|
|
34
|
+
fastapi_voyager-0.12.6.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
|
|
35
|
+
fastapi_voyager-0.12.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|