next-arch-map 0.1.13 → 0.1.15
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.
- package/dist/analyzers/endpointsToDb.js +50 -33
- package/dist/analyzers/pagesToEndpoints.js +69 -53
- package/dist/analyzers/pagesToUi.js +20 -14
- package/dist/diff.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/merge.js +4 -1
- package/dist/serve.js +1 -1
- package/dist/utils.js +1 -2
- package/package.json +9 -1
- package/viewer/src/App.tsx +1 -1
|
@@ -17,41 +17,49 @@ export async function analyzeEndpointsToDb(options) {
|
|
|
17
17
|
const seenRouteFiles = new Set();
|
|
18
18
|
for (const scanRoot of scanRoots) {
|
|
19
19
|
for (const filePath of walkDirectory(scanRoot)) {
|
|
20
|
-
if (seenRouteFiles.has(filePath) ||
|
|
20
|
+
if (seenRouteFiles.has(filePath) ||
|
|
21
|
+
isIgnoredSourceFile(filePath) ||
|
|
22
|
+
!isRouteHandlerFile(filePath)) {
|
|
21
23
|
continue;
|
|
22
24
|
}
|
|
23
25
|
seenRouteFiles.add(filePath);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
try {
|
|
27
|
+
const endpointPath = getEndpointRouteFromFile(scanRoot, filePath);
|
|
28
|
+
const { availableMethods, dbUsageByModel } = analyzeEndpoint(filePath, projectRoot, moduleCache, sourceFileCache, dbClientIdentifiers);
|
|
29
|
+
const endpointNode = ensureNode(nodes, nodeIds, buildEndpointNode(endpointPath, filePath));
|
|
30
|
+
const handlerMethods = availableMethods.size > 0 ? [...availableMethods] : [undefined];
|
|
31
|
+
for (const methodName of handlerMethods) {
|
|
32
|
+
const handlerNode = ensureNode(nodes, nodeIds, buildHandlerNode(endpointPath, filePath, methodName));
|
|
33
|
+
const edgeKey = buildEdgeKey(endpointNode.id, handlerNode.id, "endpoint-handler");
|
|
34
|
+
if (edgeKeys.has(edgeKey)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
edgeKeys.add(edgeKey);
|
|
38
|
+
edges.push({
|
|
39
|
+
from: endpointNode.id,
|
|
40
|
+
to: handlerNode.id,
|
|
41
|
+
kind: "endpoint-handler",
|
|
42
|
+
meta: methodName ? { method: methodName } : undefined,
|
|
43
|
+
});
|
|
33
44
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
for (const [modelName, dbUsage] of dbUsageByModel) {
|
|
46
|
+
const dbNode = ensureNode(nodes, nodeIds, buildDbNode(modelName, dbUsage.filePath));
|
|
47
|
+
const edgeKey = buildEdgeKey(endpointNode.id, dbNode.id, "endpoint-db");
|
|
48
|
+
if (edgeKeys.has(edgeKey)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
edgeKeys.add(edgeKey);
|
|
52
|
+
edges.push({
|
|
53
|
+
from: endpointNode.id,
|
|
54
|
+
to: dbNode.id,
|
|
55
|
+
kind: "endpoint-db",
|
|
56
|
+
meta: dbUsage.actionName ? { action: dbUsage.actionName } : undefined,
|
|
57
|
+
});
|
|
47
58
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
kind: "endpoint-db",
|
|
53
|
-
meta: dbUsage.actionName ? { action: dbUsage.actionName } : undefined,
|
|
54
|
-
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const relative = path.relative(projectRoot, filePath);
|
|
62
|
+
console.warn(`Warning: skipping ${relative}: ${error instanceof Error ? error.message : error}`);
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
}
|
|
@@ -219,7 +227,14 @@ function getModuleInfo(filePath, state) {
|
|
|
219
227
|
}
|
|
220
228
|
const sourceFile = getSourceFile(filePath, state.sourceFileCache);
|
|
221
229
|
if (!sourceFile) {
|
|
222
|
-
|
|
230
|
+
const emptyModuleInfo = {
|
|
231
|
+
localDeclarations: new Map(),
|
|
232
|
+
importsByLocalName: new Map(),
|
|
233
|
+
exportsByName: new Map(),
|
|
234
|
+
};
|
|
235
|
+
console.warn(`Warning: could not parse ${path.relative(state.projectRoot, filePath)}, skipping.`);
|
|
236
|
+
state.moduleCache.set(filePath, emptyModuleInfo);
|
|
237
|
+
return emptyModuleInfo;
|
|
223
238
|
}
|
|
224
239
|
const localDeclarations = new Map();
|
|
225
240
|
const importsByLocalName = new Map();
|
|
@@ -341,8 +356,10 @@ function getFunctionBodyNode(node) {
|
|
|
341
356
|
return node.body;
|
|
342
357
|
}
|
|
343
358
|
function hasExportModifier(node) {
|
|
344
|
-
return ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
359
|
+
return (ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ??
|
|
360
|
+
false);
|
|
345
361
|
}
|
|
346
362
|
function hasDefaultModifier(node) {
|
|
347
|
-
return ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword) ??
|
|
363
|
+
return (ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword) ??
|
|
364
|
+
false);
|
|
348
365
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import ts from "typescript";
|
|
2
3
|
import { buildActionNode, buildEdgeKey, buildEndpointNode, buildPageNode, collectStringConstants, ensureNode, getExistingDirectories, getPageRouteFromFile, getSourceFile, getStringLiteralValue, isIgnoredSourceFile, isPageFile, resolveProjectRoot, walkDirectory, } from "../utils.js";
|
|
3
4
|
const DEFAULT_APP_DIRS = ["app", "src/app"];
|
|
@@ -25,59 +26,65 @@ export async function analyzePagesToEndpoints(options) {
|
|
|
25
26
|
if (isIgnoredSourceFile(filePath)) {
|
|
26
27
|
continue;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const httpCalls = collectHttpCalls(sourceFile, httpClientIdentifiers, httpClientMethods);
|
|
33
|
-
// Non-page files (route handlers, layouts, helpers) under app/ only
|
|
34
|
-
// contribute endpoint nodes without creating fake page flows.
|
|
35
|
-
if (!isPageFile(filePath)) {
|
|
36
|
-
for (const call of httpCalls) {
|
|
37
|
-
ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
29
|
+
try {
|
|
30
|
+
const sourceFile = getSourceFile(filePath, sourceFileCache);
|
|
31
|
+
if (!sourceFile) {
|
|
32
|
+
continue;
|
|
38
33
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const actionId = allocateActionId(route, actionContext.id, actionIdCountByRoute);
|
|
48
|
-
const pageNode = ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
49
|
-
const actionNode = ensureNode(nodes, nodeIds, buildActionNode(route, actionId, filePath, actionContext.meta));
|
|
50
|
-
const endpointNode = ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
51
|
-
const pageActionKey = buildEdgeKey(pageNode.id, actionNode.id, "page-action");
|
|
52
|
-
if (!edgeKeys.has(pageActionKey)) {
|
|
53
|
-
edgeKeys.add(pageActionKey);
|
|
54
|
-
edges.push({
|
|
55
|
-
from: pageNode.id,
|
|
56
|
-
to: actionNode.id,
|
|
57
|
-
kind: "page-action",
|
|
58
|
-
});
|
|
34
|
+
const httpCalls = collectHttpCalls(sourceFile, httpClientIdentifiers, httpClientMethods);
|
|
35
|
+
// Non-page files (route handlers, layouts, helpers) under app/ only
|
|
36
|
+
// contribute endpoint nodes without creating fake page flows.
|
|
37
|
+
if (!isPageFile(filePath)) {
|
|
38
|
+
for (const call of httpCalls) {
|
|
39
|
+
ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
59
42
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
const route = getPageRouteFromFile(appDir, filePath);
|
|
44
|
+
ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
45
|
+
for (const call of httpCalls) {
|
|
46
|
+
const nextCallIndex = (callIndexByRoute.get(route) ?? 0) + 1;
|
|
47
|
+
callIndexByRoute.set(route, nextCallIndex);
|
|
48
|
+
const actionContext = inferActionContext(call.node, sourceFile, nextCallIndex);
|
|
49
|
+
const actionId = allocateActionId(route, actionContext.id, actionIdCountByRoute);
|
|
50
|
+
const pageNode = ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
51
|
+
const actionNode = ensureNode(nodes, nodeIds, buildActionNode(route, actionId, filePath, actionContext.meta));
|
|
52
|
+
const endpointNode = ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
53
|
+
const pageActionKey = buildEdgeKey(pageNode.id, actionNode.id, "page-action");
|
|
54
|
+
if (!edgeKeys.has(pageActionKey)) {
|
|
55
|
+
edgeKeys.add(pageActionKey);
|
|
56
|
+
edges.push({
|
|
57
|
+
from: pageNode.id,
|
|
58
|
+
to: actionNode.id,
|
|
59
|
+
kind: "page-action",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const actionEndpointKey = buildEdgeKey(actionNode.id, endpointNode.id, "action-endpoint");
|
|
63
|
+
if (!edgeKeys.has(actionEndpointKey)) {
|
|
64
|
+
edgeKeys.add(actionEndpointKey);
|
|
65
|
+
edges.push({
|
|
66
|
+
from: actionNode.id,
|
|
67
|
+
to: endpointNode.id,
|
|
68
|
+
kind: "action-endpoint",
|
|
69
|
+
meta: call.method ? { method: call.method } : undefined,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const edgeKey = buildEdgeKey(pageNode.id, endpointNode.id, "page-endpoint");
|
|
73
|
+
if (edgeKeys.has(edgeKey)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
edgeKeys.add(edgeKey);
|
|
63
77
|
edges.push({
|
|
64
|
-
from:
|
|
78
|
+
from: pageNode.id,
|
|
65
79
|
to: endpointNode.id,
|
|
66
|
-
kind: "
|
|
80
|
+
kind: "page-endpoint",
|
|
67
81
|
meta: call.method ? { method: call.method } : undefined,
|
|
68
82
|
});
|
|
69
83
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
edgeKeys.add(edgeKey);
|
|
75
|
-
edges.push({
|
|
76
|
-
from: pageNode.id,
|
|
77
|
-
to: endpointNode.id,
|
|
78
|
-
kind: "page-endpoint",
|
|
79
|
-
meta: call.method ? { method: call.method } : undefined,
|
|
80
|
-
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const relative = path.relative(projectRoot, filePath);
|
|
87
|
+
console.warn(`Warning: skipping ${relative}: ${error instanceof Error ? error.message : error}`);
|
|
81
88
|
}
|
|
82
89
|
}
|
|
83
90
|
}
|
|
@@ -86,12 +93,18 @@ export async function analyzePagesToEndpoints(options) {
|
|
|
86
93
|
if (isIgnoredSourceFile(filePath)) {
|
|
87
94
|
continue;
|
|
88
95
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
try {
|
|
97
|
+
const sourceFile = getSourceFile(filePath, sourceFileCache);
|
|
98
|
+
if (!sourceFile) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
for (const call of collectHttpCalls(sourceFile, httpClientIdentifiers, httpClientMethods)) {
|
|
102
|
+
ensureNode(nodes, nodeIds, buildEndpointNode(call.endpoint, filePath));
|
|
103
|
+
}
|
|
92
104
|
}
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
catch (error) {
|
|
106
|
+
const relative = path.relative(projectRoot, filePath);
|
|
107
|
+
console.warn(`Warning: skipping ${relative}: ${error instanceof Error ? error.message : error}`);
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
}
|
|
@@ -263,12 +276,15 @@ function isTopLevelNamedFunctionLike(node, sourceFile) {
|
|
|
263
276
|
return false;
|
|
264
277
|
}
|
|
265
278
|
function getFunctionLikeName(node) {
|
|
266
|
-
if ((ts.isFunctionDeclaration(node) ||
|
|
279
|
+
if ((ts.isFunctionDeclaration(node) ||
|
|
280
|
+
ts.isFunctionExpression(node) ||
|
|
281
|
+
ts.isMethodDeclaration(node)) &&
|
|
267
282
|
node.name &&
|
|
268
283
|
ts.isIdentifier(node.name)) {
|
|
269
284
|
return node.name.text;
|
|
270
285
|
}
|
|
271
|
-
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
286
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
287
|
+
ts.isVariableDeclaration(node.parent)) {
|
|
272
288
|
return ts.isIdentifier(node.parent.name) ? node.parent.name.text : undefined;
|
|
273
289
|
}
|
|
274
290
|
return undefined;
|
|
@@ -24,21 +24,27 @@ export async function analyzePagesToUi(options) {
|
|
|
24
24
|
if (!isPageFile(filePath)) {
|
|
25
25
|
continue;
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
try {
|
|
28
|
+
const route = getPageRouteFromFile(appDir, filePath);
|
|
29
|
+
const pageNode = ensureNode(nodes, nodeIds, buildPageNode(route, filePath));
|
|
30
|
+
const components = collectUiComponentUsages(filePath, projectRoot, uiPathMatchers);
|
|
31
|
+
for (const component of components) {
|
|
32
|
+
const uiNode = ensureNode(nodes, nodeIds, buildUiNode(component.componentName, component.filePath));
|
|
33
|
+
const edgeKey = buildEdgeKey(pageNode.id, uiNode.id, "page-ui");
|
|
34
|
+
if (edgeKeys.has(edgeKey)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
edgeKeys.add(edgeKey);
|
|
38
|
+
edges.push({
|
|
39
|
+
from: pageNode.id,
|
|
40
|
+
to: uiNode.id,
|
|
41
|
+
kind: "page-ui",
|
|
42
|
+
});
|
|
35
43
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
kind: "page-ui",
|
|
41
|
-
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const relative = path.relative(projectRoot, filePath);
|
|
47
|
+
console.warn(`Warning: skipping ${relative}: ${error instanceof Error ? error.message : error}`);
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
}
|
package/dist/diff.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { buildEdgeKey } from "./utils.js";
|
|
2
2
|
function nodeEqual(a, b) {
|
|
3
|
-
return a.type === b.type && a.label === b.label && JSON.stringify(a.meta) === JSON.stringify(b.meta);
|
|
3
|
+
return (a.type === b.type && a.label === b.label && JSON.stringify(a.meta) === JSON.stringify(b.meta));
|
|
4
4
|
}
|
|
5
5
|
function edgeEqual(a, b) {
|
|
6
6
|
return JSON.stringify(a.meta) === JSON.stringify(b.meta);
|
package/dist/index.d.ts
CHANGED
|
@@ -17,4 +17,4 @@ export { analyzePagesToEndpoints } from "./analyzers/pagesToEndpoints.js";
|
|
|
17
17
|
export { analyzeEndpointsToDb } from "./analyzers/endpointsToDb.js";
|
|
18
18
|
export { analyzePagesToUi } from "./analyzers/pagesToUi.js";
|
|
19
19
|
export { mergeGraphs, mergePartial } from "./merge.js";
|
|
20
|
-
export { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel
|
|
20
|
+
export { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel } from "./query.js";
|
package/dist/index.js
CHANGED
|
@@ -27,4 +27,4 @@ export { analyzePagesToEndpoints } from "./analyzers/pagesToEndpoints.js";
|
|
|
27
27
|
export { analyzeEndpointsToDb } from "./analyzers/endpointsToDb.js";
|
|
28
28
|
export { analyzePagesToUi } from "./analyzers/pagesToUi.js";
|
|
29
29
|
export { mergeGraphs, mergePartial } from "./merge.js";
|
|
30
|
-
export { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel
|
|
30
|
+
export { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel } from "./query.js";
|
package/dist/merge.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { buildEdgeKey, mergeEdge, mergeNode } from "./utils.js";
|
|
2
2
|
export function mergeGraphs(graphs) {
|
|
3
|
-
return graphs.reduce((accumulator, graph) => mergePartial(accumulator, graph), {
|
|
3
|
+
return graphs.reduce((accumulator, graph) => mergePartial(accumulator, graph), {
|
|
4
|
+
nodes: [],
|
|
5
|
+
edges: [],
|
|
6
|
+
});
|
|
4
7
|
}
|
|
5
8
|
export function mergePartial(base, additions) {
|
|
6
9
|
const nodesById = new Map();
|
package/dist/serve.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import chokidar from "chokidar";
|
|
4
4
|
import { analyzeProject } from "./index.js";
|
|
5
5
|
import { diffGraphs } from "./diff.js";
|
|
6
|
-
import { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel
|
|
6
|
+
import { getDbModelsForPage, getEndpointsForPage, getPagesForDbModel } from "./query.js";
|
|
7
7
|
export async function serve(options) {
|
|
8
8
|
const projectRoot = path.resolve(options.projectRoot);
|
|
9
9
|
const port = options.port ?? 4321;
|
package/dist/utils.js
CHANGED
|
@@ -74,8 +74,7 @@ export function getEndpointRouteFromFile(scanRoot, filePath) {
|
|
|
74
74
|
if (!ROUTE_FILE_PATTERN.test(fileName)) {
|
|
75
75
|
return prefixedSegments.length === 0 ? "/" : `/${prefixedSegments.join("/")}`;
|
|
76
76
|
}
|
|
77
|
-
if (prefixedSegments.length > 1 &&
|
|
78
|
-
prefixedSegments[0] === prefixedSegments[1]) {
|
|
77
|
+
if (prefixedSegments.length > 1 && prefixedSegments[0] === prefixedSegments[1]) {
|
|
79
78
|
prefixedSegments.shift();
|
|
80
79
|
}
|
|
81
80
|
return prefixedSegments.length === 0 ? "/" : `/${prefixedSegments.join("/")}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-arch-map",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Static analyzer that builds a multi-layer architecture graph for Next.js-style apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"build": "tsc -p tsconfig.json",
|
|
27
27
|
"check": "tsc --noEmit -p tsconfig.json",
|
|
28
28
|
"test": "vitest run",
|
|
29
|
+
"lint": "eslint src/ tests/",
|
|
30
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
31
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
29
32
|
"dev": "node dist/cli.js dev"
|
|
30
33
|
},
|
|
31
34
|
"keywords": [
|
|
@@ -45,7 +48,12 @@
|
|
|
45
48
|
"typescript": "^5.8.2"
|
|
46
49
|
},
|
|
47
50
|
"devDependencies": {
|
|
51
|
+
"@eslint/js": "^10.0.1",
|
|
48
52
|
"@types/node": "^20.19.0",
|
|
53
|
+
"eslint": "^10.0.3",
|
|
54
|
+
"eslint-config-prettier": "^10.1.8",
|
|
55
|
+
"prettier": "^3.8.1",
|
|
56
|
+
"typescript-eslint": "^8.57.0",
|
|
49
57
|
"vitest": "^4.1.0"
|
|
50
58
|
}
|
|
51
59
|
}
|
package/viewer/src/App.tsx
CHANGED
|
@@ -98,7 +98,7 @@ function buildEdgeKey(from: string, to: string, kind: EdgeKind): string {
|
|
|
98
98
|
export function App() {
|
|
99
99
|
const [graph, setGraph] = useState<Graph | null>(null);
|
|
100
100
|
const [graphDiff, setGraphDiff] = useState<GraphDiff | null>(null);
|
|
101
|
-
const [useServer, setUseServer] = useState(
|
|
101
|
+
const [useServer, setUseServer] = useState(true);
|
|
102
102
|
const [serverUrl, setServerUrl] = useState("http://localhost:4321");
|
|
103
103
|
const [focusedPageRoute, setFocusedPageRoute] = useState<string | null>(null);
|
|
104
104
|
const [queryRoute, setQueryRoute] = useState("/dashboard");
|