@wtdlee/repomap 0.3.1 → 0.3.2
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/index.js +1 -1
- package/dist/{chunk-M6YNU536.js → chunk-4K4MGTPV.js} +27 -714
- package/dist/chunk-6F4PWJZI.js +0 -1
- package/dist/chunk-J2CM7T7U.js +1 -0
- package/dist/{chunk-3YFXZAP7.js → chunk-MOEA75XK.js} +170 -359
- package/dist/{chunk-E4WRODSI.js → chunk-SL2GMDBN.js} +35 -108
- package/dist/chunk-UJT5KTVK.js +36 -0
- package/dist/chunk-VV3A3UE3.js +1 -0
- package/dist/chunk-XWZH2RDG.js +19 -0
- package/dist/cli.js +29 -395
- package/dist/env-detector-BIWJ7OYF.js +1 -0
- package/dist/generators/assets/common.css +564 -23
- package/dist/generators/index.js +1 -2
- package/dist/index.js +1 -8
- package/dist/page-map-generator-XNZ4TDJT.js +1 -0
- package/dist/rails-TJCDGBBF.js +1 -0
- package/dist/rails-map-generator-JL5PKHYP.js +1 -0
- package/dist/server/index.js +1 -7
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3PWXDB7B.js +0 -153
- package/dist/chunk-GNBMJMET.js +0 -2519
- package/dist/chunk-OWM6WNLE.js +0 -2610
- package/dist/chunk-SSU6QFTX.js +0 -1058
- package/dist/env-detector-EEMVUEIA.js +0 -1
- package/dist/page-map-generator-6MJGPBVA.js +0 -1
- package/dist/rails-UWSDRS33.js +0 -1
- package/dist/rails-map-generator-D2URLMVJ.js +0 -2
|
@@ -1,128 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var PageMapGenerator = class {
|
|
3
|
-
graphqlOps = [];
|
|
4
|
-
apiCalls = [];
|
|
5
|
-
components = [];
|
|
6
|
-
generatePageMapHtml(report, options) {
|
|
7
|
-
const allPages = [];
|
|
8
|
-
const envResult = options?.envResult;
|
|
9
|
-
const railsAnalysis = options?.railsAnalysis;
|
|
10
|
-
const activeTab = options?.activeTab || "pages";
|
|
11
|
-
const repoName = report.repositories[0]?.displayName || report.repositories[0]?.name || "Repository";
|
|
12
|
-
for (const repoResult of report.repositories) {
|
|
13
|
-
this.graphqlOps.push(...repoResult.analysis?.graphqlOperations || []);
|
|
14
|
-
this.apiCalls.push(...repoResult.analysis?.apiCalls || []);
|
|
15
|
-
const comps = repoResult.analysis?.components || [];
|
|
16
|
-
for (const comp of comps) {
|
|
17
|
-
this.components.push({
|
|
18
|
-
name: comp.name,
|
|
19
|
-
filePath: comp.filePath,
|
|
20
|
-
type: comp.type,
|
|
21
|
-
dependencies: comp.dependencies || []
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
for (const repoResult of report.repositories) {
|
|
26
|
-
const pages = repoResult.analysis?.pages || [];
|
|
27
|
-
for (const page of pages) {
|
|
28
|
-
allPages.push({
|
|
29
|
-
...page,
|
|
30
|
-
repo: repoResult.name,
|
|
31
|
-
children: [],
|
|
32
|
-
parent: null,
|
|
33
|
-
depth: 0
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
const { rootPages, relations } = this.buildHierarchy(allPages);
|
|
38
|
-
return this.renderPageMapHtml(allPages, rootPages, relations, repoName, {
|
|
39
|
-
envResult,
|
|
40
|
-
railsAnalysis,
|
|
41
|
-
activeTab
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
buildHierarchy(pages) {
|
|
45
|
-
const pathMap = /* @__PURE__ */ new Map();
|
|
46
|
-
const relations = [];
|
|
47
|
-
for (const page of pages) {
|
|
48
|
-
pathMap.set(page.path, page);
|
|
49
|
-
}
|
|
50
|
-
for (const page of pages) {
|
|
51
|
-
const segments = page.path.split("/").filter(Boolean);
|
|
52
|
-
for (let i = segments.length - 1; i >= 1; i--) {
|
|
53
|
-
const parentPath = "/" + segments.slice(0, i).join("/");
|
|
54
|
-
const parent = pathMap.get(parentPath);
|
|
55
|
-
if (parent) {
|
|
56
|
-
page.parent = parentPath;
|
|
57
|
-
page.depth = parent.depth + 1;
|
|
58
|
-
if (!parent.children.includes(page.path)) {
|
|
59
|
-
parent.children.push(page.path);
|
|
60
|
-
}
|
|
61
|
-
relations.push({
|
|
62
|
-
from: parentPath,
|
|
63
|
-
to: page.path,
|
|
64
|
-
type: "parent-child",
|
|
65
|
-
description: `Sub-page of ${parentPath}`
|
|
66
|
-
});
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (!page.parent) {
|
|
71
|
-
page.depth = Math.max(0, segments.length - 1);
|
|
72
|
-
}
|
|
73
|
-
if (page.layout) {
|
|
74
|
-
for (const other of pages) {
|
|
75
|
-
if (other.path !== page.path && other.layout === page.layout) {
|
|
76
|
-
const existing = relations.find(
|
|
77
|
-
(r) => r.type === "same-layout" && (r.from === page.path && r.to === other.path || r.from === other.path && r.to === page.path)
|
|
78
|
-
);
|
|
79
|
-
if (!existing) {
|
|
80
|
-
relations.push({
|
|
81
|
-
from: page.path,
|
|
82
|
-
to: other.path,
|
|
83
|
-
type: "same-layout",
|
|
84
|
-
description: `Both use ${page.layout}`
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const rootPages = pages.filter((p) => !p.parent).sort((a, b) => a.path.localeCompare(b.path));
|
|
92
|
-
return { rootPages, relations };
|
|
93
|
-
}
|
|
94
|
-
renderPageMapHtml(allPages, rootPages, relations, repoName, options) {
|
|
95
|
-
const envResult = options?.envResult;
|
|
96
|
-
const railsAnalysis = options?.railsAnalysis;
|
|
97
|
-
const activeTab = options?.activeTab || "pages";
|
|
98
|
-
const graphqlOpsJson = JSON.stringify(
|
|
99
|
-
this.graphqlOps.map((op) => ({
|
|
100
|
-
name: op.name,
|
|
101
|
-
type: op.type,
|
|
102
|
-
variables: op.variables,
|
|
103
|
-
fields: op.fields,
|
|
104
|
-
returnType: op.returnType,
|
|
105
|
-
usedIn: op.usedIn
|
|
106
|
-
}))
|
|
107
|
-
);
|
|
108
|
-
const componentsJson = JSON.stringify(this.components);
|
|
109
|
-
const railsRoutesJson = railsAnalysis ? JSON.stringify(railsAnalysis.routes.routes) : "[]";
|
|
110
|
-
const railsControllersJson = railsAnalysis ? JSON.stringify(railsAnalysis.controllers.controllers) : "[]";
|
|
111
|
-
const railsModelsJson = railsAnalysis ? JSON.stringify(railsAnalysis.models.models) : "[]";
|
|
112
|
-
const railsViewsJson = railsAnalysis ? JSON.stringify(railsAnalysis.views) : '{ "views": [], "pages": [], "summary": {} }';
|
|
113
|
-
const railsReactJson = railsAnalysis ? JSON.stringify(railsAnalysis.react) : '{ "components": [], "entryPoints": [], "summary": {} }';
|
|
114
|
-
const railsGrpcJson = railsAnalysis ? JSON.stringify(railsAnalysis.grpc) : '{ "services": [] }';
|
|
115
|
-
const railsSummaryJson = railsAnalysis ? JSON.stringify(railsAnalysis.summary) : "null";
|
|
116
|
-
const hasRails = envResult?.hasRails || false;
|
|
117
|
-
const hasNextjs = envResult?.hasNextjs || false;
|
|
118
|
-
const hasReact = envResult?.hasReact || false;
|
|
119
|
-
const groups = /* @__PURE__ */ new Map();
|
|
120
|
-
for (const page of allPages) {
|
|
121
|
-
const seg = page.path.split("/").filter(Boolean)[0] || "root";
|
|
122
|
-
if (!groups.has(seg)) groups.set(seg, []);
|
|
123
|
-
groups.get(seg)?.push(page);
|
|
124
|
-
}
|
|
125
|
-
return `<!DOCTYPE html>
|
|
1
|
+
var S=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,r){let c=[],v=r?.envResult,t=r?.railsAnalysis,l=r?.activeTab||"pages",e=s.repositories[0]?.displayName||s.repositories[0]?.name||"Repository";for(let p of s.repositories){this.graphqlOps.push(...p.analysis?.graphqlOperations||[]),this.apiCalls.push(...p.analysis?.apiCalls||[]);let f=p.analysis?.components||[];for(let a of f)this.components.push({name:a.name,filePath:a.filePath,type:a.type,dependencies:a.dependencies||[]});}for(let p of s.repositories){let f=p.analysis?.pages||[];for(let a of f)c.push({...a,repo:p.name,children:[],parent:null,depth:0});}let{rootPages:i,relations:o}=this.buildHierarchy(c);return this.renderPageMapHtml(c,i,o,e,{envResult:v,railsAnalysis:t,activeTab:l})}buildHierarchy(s){let r=new Map,c=[];for(let t of s)r.set(t.path,t);for(let t of s){let l=t.path.split("/").filter(Boolean);for(let e=l.length-1;e>=1;e--){let i="/"+l.slice(0,e).join("/"),o=r.get(i);if(o){t.parent=i,t.depth=o.depth+1,o.children.includes(t.path)||o.children.push(t.path),c.push({from:i,to:t.path,type:"parent-child",description:`Sub-page of ${i}`});break}}if(t.parent||(t.depth=Math.max(0,l.length-1)),t.layout)for(let e of s)e.path!==t.path&&e.layout===t.layout&&(c.find(o=>o.type==="same-layout"&&(o.from===t.path&&o.to===e.path||o.from===e.path&&o.to===t.path))||c.push({from:t.path,to:e.path,type:"same-layout",description:`Both use ${t.layout}`}));}return {rootPages:s.filter(t=>!t.parent).sort((t,l)=>t.path.localeCompare(l.path)),relations:c}}renderPageMapHtml(s,r,c,v,t){let l=t?.envResult,e=t?.railsAnalysis,i=t?.activeTab||"pages",o=JSON.stringify(this.graphqlOps.map(d=>({name:d.name,type:d.type,variables:d.variables,fields:d.fields,returnType:d.returnType,usedIn:d.usedIn}))),p=JSON.stringify(this.components),f=e?JSON.stringify(e.routes.routes):"[]",a=e?JSON.stringify(e.controllers.controllers):"[]",m=e?JSON.stringify(e.models.models):"[]",u=e?JSON.stringify(e.views):'{ "views": [], "pages": [], "summary": {} }',h=e?JSON.stringify(e.react):'{ "components": [], "entryPoints": [], "summary": {} }',y=e?JSON.stringify(e.grpc):'{ "services": [] }',P=e?JSON.stringify(e.summary):"null",n=l?.hasRails||false,w=l?.hasNextjs||false,C=l?.hasReact||false,x=new Map;for(let d of s){let b=d.path.split("/").filter(Boolean)[0]||"root";x.has(b)||x.set(b,[]),x.get(b)?.push(d);}return `<!DOCTYPE html>
|
|
126
2
|
<html lang="en">
|
|
127
3
|
<head>
|
|
128
4
|
<meta charset="UTF-8">
|
|
@@ -133,21 +9,21 @@ var PageMapGenerator = class {
|
|
|
133
9
|
<body>
|
|
134
10
|
<header class="header">
|
|
135
11
|
<div style="display:flex;align-items:center;gap:24px">
|
|
136
|
-
<h1 style="cursor:pointer" onclick="location.href='/'">\u{1F4CA} ${
|
|
12
|
+
<h1 style="cursor:pointer" onclick="location.href='/'">\u{1F4CA} ${v}</h1>
|
|
137
13
|
<nav style="display:flex;gap:4px">
|
|
138
|
-
<a href="/page-map" class="nav-link ${
|
|
139
|
-
${
|
|
14
|
+
<a href="/page-map" class="nav-link ${i==="pages"?"active":""}">Page Map</a>
|
|
15
|
+
${n?`<a href="/rails-map" class="nav-link ${i==="rails"?"active":""}">Rails Map</a>`:""}
|
|
140
16
|
<a href="/docs" class="nav-link">Docs</a>
|
|
141
17
|
<a href="/api/report" class="nav-link" target="_blank">API</a>
|
|
142
18
|
</nav>
|
|
143
19
|
</div>
|
|
144
20
|
<div style="display:flex;gap:12px;align-items:center">
|
|
145
21
|
<!-- Environment filter badges -->
|
|
146
|
-
${
|
|
22
|
+
${n&&w?`<div class="env-filters" style="display:flex;gap:4px;margin-right:8px">
|
|
147
23
|
<button class="env-badge env-badge-active" data-env="all" onclick="filterByEnv('all')">All</button>
|
|
148
24
|
<button class="env-badge" data-env="nextjs" onclick="filterByEnv('nextjs')">\u269B\uFE0F Next.js</button>
|
|
149
25
|
<button class="env-badge" data-env="rails" onclick="filterByEnv('rails')">\u{1F6E4}\uFE0F Rails</button>
|
|
150
|
-
</div
|
|
26
|
+
</div>`:""}
|
|
151
27
|
<input class="search" type="text" placeholder="Search pages, queries..." oninput="filter(this.value)">
|
|
152
28
|
<div class="tabs">
|
|
153
29
|
<button class="tab active" onclick="setView('tree')">List</button>
|
|
@@ -182,40 +58,40 @@ var PageMapGenerator = class {
|
|
|
182
58
|
<!-- Frontend Stats -->
|
|
183
59
|
<h3 style="margin-top:16px;font-size:10px;text-transform:uppercase;color:var(--text2);letter-spacing:1px">Frontend</h3>
|
|
184
60
|
<div class="stats" id="stats-container">
|
|
185
|
-
<div class="stat" data-filter="pages"><div class="stat-val">${
|
|
186
|
-
<div class="stat" data-filter="hierarchies"><div class="stat-val">${
|
|
61
|
+
<div class="stat" data-filter="pages"><div class="stat-val">${s.length}</div><div class="stat-label">Pages</div></div>
|
|
62
|
+
<div class="stat" data-filter="hierarchies"><div class="stat-val">${c.filter(d=>d.type==="parent-child").length}</div><div class="stat-label">Hierarchies</div></div>
|
|
187
63
|
<div class="stat" data-filter="graphql"><div class="stat-val">${this.graphqlOps.length}</div><div class="stat-label">GraphQL</div></div>
|
|
188
64
|
<div class="stat" data-filter="restapi"><div class="stat-val">${this.apiCalls.length}</div><div class="stat-label">REST API</div></div>
|
|
189
65
|
</div>
|
|
190
66
|
|
|
191
|
-
${
|
|
67
|
+
${n&&e?`
|
|
192
68
|
<!-- Rails Stats -->
|
|
193
69
|
<h3 style="margin-top:16px;font-size:10px;text-transform:uppercase;color:var(--text2);letter-spacing:1px;cursor:pointer" onclick="switchToRailsTab()">Rails Backend</h3>
|
|
194
70
|
<div class="stats" id="rails-stats">
|
|
195
|
-
<div class="stat" data-filter="rails-routes" onclick="switchToRailsTab()"><div class="stat-val">${
|
|
196
|
-
<div class="stat" data-filter="rails-controllers" onclick="showRailsControllers(); this.blur();"><div class="stat-val">${
|
|
197
|
-
<div class="stat" data-filter="rails-models" onclick="showRailsModels(); this.blur();"><div class="stat-val">${
|
|
198
|
-
<div class="stat" data-filter="rails-grpc" onclick="showRailsGrpc(); this.blur();"><div class="stat-val">${
|
|
199
|
-
<div class="stat" data-filter="rails-react" onclick="showReactComponents(); this.blur();"><div class="stat-val">${
|
|
71
|
+
<div class="stat" data-filter="rails-routes" onclick="switchToRailsTab()"><div class="stat-val">${e.summary.totalRoutes}</div><div class="stat-label">Routes</div></div>
|
|
72
|
+
<div class="stat" data-filter="rails-controllers" onclick="showRailsControllers(); this.blur();"><div class="stat-val">${e.summary.totalControllers}</div><div class="stat-label">Controllers</div></div>
|
|
73
|
+
<div class="stat" data-filter="rails-models" onclick="showRailsModels(); this.blur();"><div class="stat-val">${e.summary.totalModels}</div><div class="stat-label">Models</div></div>
|
|
74
|
+
<div class="stat" data-filter="rails-grpc" onclick="showRailsGrpc(); this.blur();"><div class="stat-val">${e.summary.totalGrpcServices}</div><div class="stat-label">gRPC</div></div>
|
|
75
|
+
<div class="stat" data-filter="rails-react" onclick="showReactComponents(); this.blur();"><div class="stat-val">${e.summary.totalReactComponents}</div><div class="stat-label">\u269B React</div></div>
|
|
200
76
|
</div>
|
|
201
|
-
|
|
77
|
+
`:""}
|
|
202
78
|
</aside>
|
|
203
79
|
|
|
204
80
|
<div class="content">
|
|
205
81
|
<!-- Pages Tree View (for all screens - Next.js/React/Rails) -->
|
|
206
|
-
<div class="tree-view ${
|
|
207
|
-
${
|
|
208
|
-
<div id="page-map-react-components-section" style="${
|
|
82
|
+
<div class="tree-view ${i==="pages"?"active":""}" id="tree-view" data-tab="pages">
|
|
83
|
+
${s.length>0?this.buildTreeHtml(x,s):""}
|
|
84
|
+
<div id="page-map-react-components-section" style="${n?"margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px":""}">
|
|
209
85
|
</div>
|
|
210
|
-
<div id="page-map-rails-section" style="${
|
|
211
|
-
${
|
|
86
|
+
<div id="page-map-rails-section" style="${s.length>0&&n?"margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px":""}">
|
|
87
|
+
${n&&s.length===0?'<div class="empty-state-sm">Loading screens...</div>':""}
|
|
212
88
|
</div>
|
|
213
89
|
</div>
|
|
214
90
|
|
|
215
91
|
<!-- Rails Routes View (dedicated) -->
|
|
216
|
-
<div class="tree-view ${
|
|
92
|
+
<div class="tree-view ${i==="rails"?"active":""}" id="rails-tree-view" data-tab="rails">
|
|
217
93
|
<div id="rails-routes-container">
|
|
218
|
-
${
|
|
94
|
+
${n?'<div class="empty-state-sm">Loading Rails routes...</div>':'<div class="empty-state">No Rails environment detected</div>'}
|
|
219
95
|
</div>
|
|
220
96
|
</div>
|
|
221
97
|
|
|
@@ -257,16 +133,16 @@ var PageMapGenerator = class {
|
|
|
257
133
|
<script>
|
|
258
134
|
// Environment detection results
|
|
259
135
|
const envInfo = {
|
|
260
|
-
hasRails: ${
|
|
261
|
-
hasNextjs: ${
|
|
262
|
-
hasReact: ${
|
|
136
|
+
hasRails: ${n},
|
|
137
|
+
hasNextjs: ${w},
|
|
138
|
+
hasReact: ${C}
|
|
263
139
|
};
|
|
264
140
|
|
|
265
141
|
// Frontend data
|
|
266
|
-
const pages = ${JSON.stringify(
|
|
267
|
-
const relations = ${JSON.stringify(
|
|
268
|
-
const graphqlOps = ${
|
|
269
|
-
const components = ${
|
|
142
|
+
const pages = ${JSON.stringify(s)};
|
|
143
|
+
const relations = ${JSON.stringify(c)};
|
|
144
|
+
const graphqlOps = ${o};
|
|
145
|
+
const components = ${p};
|
|
270
146
|
const apiCallsData = ${JSON.stringify(this.apiCalls)};
|
|
271
147
|
window.apiCalls = apiCallsData;
|
|
272
148
|
const pageMap = new Map(pages.map(p => [p.path, p]));
|
|
@@ -274,16 +150,16 @@ var PageMapGenerator = class {
|
|
|
274
150
|
const compMap = new Map(components.map(c => [c.name, c]));
|
|
275
151
|
|
|
276
152
|
// Rails data (if available)
|
|
277
|
-
const railsRoutes = ${
|
|
278
|
-
const railsControllers = ${
|
|
279
|
-
const railsModels = ${
|
|
280
|
-
const railsViews = ${
|
|
281
|
-
const railsReact = ${
|
|
282
|
-
const railsGrpc = ${
|
|
283
|
-
const railsSummary = ${
|
|
153
|
+
const railsRoutes = ${f};
|
|
154
|
+
const railsControllers = ${a};
|
|
155
|
+
const railsModels = ${m};
|
|
156
|
+
const railsViews = ${u};
|
|
157
|
+
const railsReact = ${h};
|
|
158
|
+
const railsGrpc = ${y};
|
|
159
|
+
const railsSummary = ${P};
|
|
284
160
|
|
|
285
161
|
// Current active tab state
|
|
286
|
-
let currentMainTab = '${
|
|
162
|
+
let currentMainTab = '${i}';
|
|
287
163
|
|
|
288
164
|
// Modal history stack for back navigation
|
|
289
165
|
const modalHistory = [];
|
|
@@ -377,17 +253,17 @@ var PageMapGenerator = class {
|
|
|
377
253
|
routesByNamespace.get(ns).push(r);
|
|
378
254
|
});
|
|
379
255
|
|
|
380
|
-
let html = '<div
|
|
256
|
+
let html = '<div class="max-h-60vh overflow-y-auto">';
|
|
381
257
|
for (const [ns, routes] of routesByNamespace) {
|
|
382
258
|
html += '<div style="margin-bottom:16px">';
|
|
383
259
|
html += '<div style="font-weight:600;margin-bottom:8px;color:var(--accent)">\u{1F4C2} ' + ns + ' (' + routes.length + ')</div>';
|
|
384
260
|
html += '<table style="width:100%;border-collapse:collapse;font-size:12px">';
|
|
385
|
-
html += '<tr
|
|
261
|
+
html += '<tr class="bg-surface"><th class="cell">Method</th><th class="cell">Path</th><th class="cell">Controller#Action</th></tr>';
|
|
386
262
|
routes.slice(0, 20).forEach(r => {
|
|
387
263
|
const methodColor = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',PATCH:'#f59e0b',DELETE:'#ef4444'}[r.method] || '#888';
|
|
388
264
|
html += '<tr style="border-bottom:1px solid var(--border)">';
|
|
389
265
|
html += '<td style="padding:6px"><span style="background:' + methodColor + ';color:white;padding:2px 6px;border-radius:3px;font-size:10px">' + r.method + '</span></td>';
|
|
390
|
-
html += '<td style="padding:6px;font-family:monospace">' + r.path.replace(/:([a-z_]+)/g, '<span
|
|
266
|
+
html += '<td style="padding:6px;font-family:monospace">' + r.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</td>';
|
|
391
267
|
html += '<td style="padding:6px;color:var(--text2)">' + r.controller + '#' + r.action + '</td>';
|
|
392
268
|
html += '</tr>';
|
|
393
269
|
});
|
|
@@ -407,13 +283,13 @@ var PageMapGenerator = class {
|
|
|
407
283
|
return;
|
|
408
284
|
}
|
|
409
285
|
|
|
410
|
-
let html = '<div
|
|
286
|
+
let html = '<div class="max-h-60vh overflow-y-auto">';
|
|
411
287
|
railsControllers.forEach(ctrl => {
|
|
412
|
-
html += '<div
|
|
413
|
-
html += '<div
|
|
414
|
-
html += '<div
|
|
288
|
+
html += '<div class="info-box">';
|
|
289
|
+
html += '<div class="section-title">' + ctrl.className + '</div>';
|
|
290
|
+
html += '<div class="hint mb-3">extends ' + ctrl.parentClass + '</div>';
|
|
415
291
|
if (ctrl.actions && ctrl.actions.length > 0) {
|
|
416
|
-
html += '<div
|
|
292
|
+
html += '<div class="flex flex-wrap gap-1">';
|
|
417
293
|
ctrl.actions.slice(0, 10).forEach(action => {
|
|
418
294
|
const color = action.visibility === 'public' ? '#22c55e' : action.visibility === 'private' ? '#ef4444' : '#f59e0b';
|
|
419
295
|
html += '<span style="background:rgba(255,255,255,0.1);padding:2px 8px;border-radius:4px;font-size:11px;border-left:2px solid ' + color + '">' + action.name + '</span>';
|
|
@@ -434,16 +310,16 @@ var PageMapGenerator = class {
|
|
|
434
310
|
return;
|
|
435
311
|
}
|
|
436
312
|
|
|
437
|
-
let html = '<div
|
|
313
|
+
let html = '<div class="max-h-60vh overflow-y-auto">';
|
|
438
314
|
railsModels.forEach(model => {
|
|
439
|
-
html += '<div
|
|
440
|
-
html += '<div
|
|
441
|
-
html += '<div
|
|
315
|
+
html += '<div class="info-box">';
|
|
316
|
+
html += '<div class="section-title">\u{1F4E6} ' + model.className + '</div>';
|
|
317
|
+
html += '<div class="flex gap-3 hint mb-3">';
|
|
442
318
|
html += '<span>\u{1F4CE} ' + (model.associations?.length || 0) + ' associations</span>';
|
|
443
319
|
html += '<span>\u2713 ' + (model.validations?.length || 0) + ' validations</span>';
|
|
444
320
|
html += '</div>';
|
|
445
321
|
if (model.associations && model.associations.length > 0) {
|
|
446
|
-
html += '<div
|
|
322
|
+
html += '<div class="flex flex-wrap gap-1">';
|
|
447
323
|
model.associations.slice(0, 8).forEach(assoc => {
|
|
448
324
|
const typeColor = {belongs_to:'#3b82f6',has_many:'#22c55e',has_one:'#f59e0b'}[assoc.type] || '#888';
|
|
449
325
|
html += '<span style="background:rgba(255,255,255,0.1);padding:2px 8px;border-radius:4px;font-size:10px"><span style="color:' + typeColor + '">' + assoc.type + '</span> :' + assoc.name + '</span>';
|
|
@@ -469,24 +345,24 @@ var PageMapGenerator = class {
|
|
|
469
345
|
(b.usedIn?.length || 0) - (a.usedIn?.length || 0)
|
|
470
346
|
);
|
|
471
347
|
|
|
472
|
-
let html = '<div
|
|
348
|
+
let html = '<div class="max-h-60vh overflow-y-auto">';
|
|
473
349
|
|
|
474
350
|
// Stats
|
|
475
351
|
html += '<div style="display:flex;gap:16px;margin-bottom:16px;padding:12px;background:var(--bg3);border-radius:8px">';
|
|
476
|
-
html += '<div
|
|
477
|
-
html += '<div
|
|
478
|
-
html += '<div
|
|
479
|
-
html += '<div
|
|
352
|
+
html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:var(--accent)">' + railsReact.summary.totalComponents + '</div><div style="font-size:10px;color:var(--text2)">Components</div></div>';
|
|
353
|
+
html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#22c55e">' + railsReact.summary.ssrComponents + '</div><div style="font-size:10px;color:var(--text2)">SSR</div></div>';
|
|
354
|
+
html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#3b82f6">' + railsReact.summary.clientComponents + '</div><div style="font-size:10px;color:var(--text2)">Client</div></div>';
|
|
355
|
+
html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#f59e0b">' + railsReact.summary.totalEntryPoints + '</div><div style="font-size:10px;color:var(--text2)">Entry Points</div></div>';
|
|
480
356
|
html += '</div>';
|
|
481
357
|
|
|
482
358
|
sortedComponents.forEach(comp => {
|
|
483
359
|
const usageCount = comp.usedIn?.length || 0;
|
|
484
|
-
const ssrBadge = comp.ssr ? '<span
|
|
360
|
+
const ssrBadge = comp.ssr ? '<span class="badge-success">SSR</span>' : '';
|
|
485
361
|
|
|
486
362
|
html += '<div style="background:var(--bg3);padding:12px;border-radius:6px;margin-bottom:8px;cursor:pointer" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
|
|
487
363
|
html += '<div style="display:flex;align-items:center;justify-content:space-between">';
|
|
488
|
-
html += '<div style="font-weight:600;display:flex;align-items:center"><span
|
|
489
|
-
html += '<span
|
|
364
|
+
html += '<div style="font-weight:600;display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + ssrBadge + '</div>';
|
|
365
|
+
html += '<span class="hint">' + usageCount + ' usage' + (usageCount !== 1 ? 's' : '') + '</span>';
|
|
490
366
|
html += '</div>';
|
|
491
367
|
|
|
492
368
|
// Entry point info
|
|
@@ -507,7 +383,7 @@ var PageMapGenerator = class {
|
|
|
507
383
|
html += '<span style="background:rgba(255,255,255,0.1);padding:2px 6px;border-radius:3px;font-size:10px;border-left:2px solid ' + patternColor + '">' + usage.controller + '/' + usage.action + '</span>';
|
|
508
384
|
});
|
|
509
385
|
if (comp.usedIn.length > 3) {
|
|
510
|
-
html += '<span
|
|
386
|
+
html += '<span class="hint-sm">+' + (comp.usedIn.length - 3) + ' more</span>';
|
|
511
387
|
}
|
|
512
388
|
html += '</div>';
|
|
513
389
|
}
|
|
@@ -591,17 +467,17 @@ var PageMapGenerator = class {
|
|
|
591
467
|
return;
|
|
592
468
|
}
|
|
593
469
|
|
|
594
|
-
let html = '<div
|
|
470
|
+
let html = '<div class="max-h-60vh overflow-y-auto">';
|
|
595
471
|
railsGrpc.services.forEach(svc => {
|
|
596
|
-
html += '<div
|
|
597
|
-
html += '<div
|
|
472
|
+
html += '<div class="info-box">';
|
|
473
|
+
html += '<div class="section-title">\u{1F50C} ' + svc.className + '</div>';
|
|
598
474
|
if (svc.namespace) {
|
|
599
|
-
html += '<div
|
|
475
|
+
html += '<div class="hint mb-3">namespace: ' + svc.namespace + '</div>';
|
|
600
476
|
}
|
|
601
477
|
if (svc.rpcs && svc.rpcs.length > 0) {
|
|
602
|
-
html += '<div
|
|
478
|
+
html += '<div class="flex flex-wrap gap-1">';
|
|
603
479
|
svc.rpcs.slice(0, 15).forEach(rpc => {
|
|
604
|
-
html += '<span class="tag
|
|
480
|
+
html += '<span class="tag tag-rpc tag-sm">' + rpc.name + '</span>';
|
|
605
481
|
});
|
|
606
482
|
if (svc.rpcs.length > 15) html += '<span style="color:var(--text2);font-size:11px">+' + (svc.rpcs.length - 15) + ' more</span>';
|
|
607
483
|
html += '</div>';
|
|
@@ -623,7 +499,7 @@ var PageMapGenerator = class {
|
|
|
623
499
|
const routes = railsRoutes || [];
|
|
624
500
|
|
|
625
501
|
if (pages.length === 0 && routes.length === 0) {
|
|
626
|
-
container.innerHTML = '<div
|
|
502
|
+
container.innerHTML = '<div class="empty-state">No Rails pages or routes found</div>';
|
|
627
503
|
return;
|
|
628
504
|
}
|
|
629
505
|
|
|
@@ -790,7 +666,7 @@ var PageMapGenerator = class {
|
|
|
790
666
|
if (displayPath.length > 80) {
|
|
791
667
|
displayPath = displayPath.slice(0, 77) + '...';
|
|
792
668
|
}
|
|
793
|
-
const pathHighlighted = displayPath.replace(/:([a-z_]+)/g, '<span
|
|
669
|
+
const pathHighlighted = displayPath.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>');
|
|
794
670
|
|
|
795
671
|
// Indicators for view, API, and response types
|
|
796
672
|
let indicators = '';
|
|
@@ -820,7 +696,7 @@ var PageMapGenerator = class {
|
|
|
820
696
|
|
|
821
697
|
html += '<div class="page-item rails-route-item" data-path="' + searchPath + '"' + hiddenAttr + ' ' + filterAttrs.join(' ') + ' onclick="showRailsRouteDetail(\\''+encodeURIComponent(JSON.stringify(route))+'\\', true)" style="cursor:pointer;' + hiddenStyle + '">';
|
|
822
698
|
html += '<span class="page-type" style="background:' + methodColor + ';min-width:50px;text-align:center">' + route.method + '</span>';
|
|
823
|
-
html += '<span class="page-path"
|
|
699
|
+
html += '<span class="page-path">' + pathHighlighted + '</span>';
|
|
824
700
|
html += indicators;
|
|
825
701
|
html += '</div>';
|
|
826
702
|
});
|
|
@@ -906,7 +782,7 @@ var PageMapGenerator = class {
|
|
|
906
782
|
|
|
907
783
|
html += '<div class="detail-section">';
|
|
908
784
|
html += '<div class="detail-label">Path</div>';
|
|
909
|
-
html += '<div class="detail-value" style="font-family:monospace">' + route.path.replace(/:([a-z_]+)/g, '<span
|
|
785
|
+
html += '<div class="detail-value" style="font-family:monospace">' + route.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</div>';
|
|
910
786
|
html += '</div>';
|
|
911
787
|
|
|
912
788
|
html += '<div class="detail-section">';
|
|
@@ -928,14 +804,14 @@ var PageMapGenerator = class {
|
|
|
928
804
|
responseTypes.push('<span style="background:#8b5cf6;color:white;padding:2px 8px;border-radius:4px;font-size:11px;margin-right:4px">' + f.toUpperCase() + '</span>');
|
|
929
805
|
});
|
|
930
806
|
}
|
|
931
|
-
html += responseTypes.length > 0 ? responseTypes.join('') : '<span
|
|
807
|
+
html += responseTypes.length > 0 ? responseTypes.join('') : '<span class="text-muted">Unknown</span>';
|
|
932
808
|
html += '</div></div>';
|
|
933
809
|
|
|
934
810
|
// Redirect destination if exists
|
|
935
811
|
if (action.redirectsTo) {
|
|
936
812
|
html += '<div class="detail-section">';
|
|
937
813
|
html += '<div class="detail-label">\u21AA\uFE0F Redirects To</div>';
|
|
938
|
-
html += '<div class="detail-value
|
|
814
|
+
html += '<div class="detail-value-block">' + action.redirectsTo + '</div>';
|
|
939
815
|
html += '</div>';
|
|
940
816
|
}
|
|
941
817
|
}
|
|
@@ -944,9 +820,9 @@ var PageMapGenerator = class {
|
|
|
944
820
|
if (route.hasView && route.view) {
|
|
945
821
|
html += '<div class="detail-section">';
|
|
946
822
|
html += '<div class="detail-label">\u{1F4C4} View Template</div>';
|
|
947
|
-
html += '<div class="detail-value"
|
|
823
|
+
html += '<div class="detail-value">app/views/' + route.view.path + '</div>';
|
|
948
824
|
if (route.view.partials && route.view.partials.length > 0) {
|
|
949
|
-
html += '<div
|
|
825
|
+
html += '<div class="subtext">Partials: ' + route.view.partials.slice(0, 5).join(', ') + (route.view.partials.length > 5 ? '...' : '') + '</div>';
|
|
950
826
|
}
|
|
951
827
|
if (route.view.instanceVars && route.view.instanceVars.length > 0) {
|
|
952
828
|
html += '<div style="margin-top:4px;font-size:11px;color:var(--text2)">Instance vars: @' + route.view.instanceVars.slice(0, 5).join(', @') + (route.view.instanceVars.length > 5 ? '...' : '') + '</div>';
|
|
@@ -958,7 +834,7 @@ var PageMapGenerator = class {
|
|
|
958
834
|
if (ctrl && (ctrl.beforeActions.length > 0 || ctrl.afterActions.length > 0)) {
|
|
959
835
|
html += '<div class="detail-section">';
|
|
960
836
|
html += '<div class="detail-label">\u{1F512} Filters Applied to This Action</div>';
|
|
961
|
-
html += '<div
|
|
837
|
+
html += '<div class="code-block">';
|
|
962
838
|
|
|
963
839
|
// Filter before_actions that apply to this action
|
|
964
840
|
const applicableBeforeFilters = ctrl.beforeActions.filter(f => {
|
|
@@ -971,7 +847,7 @@ var PageMapGenerator = class {
|
|
|
971
847
|
html += '<div style="font-size:11px;margin-bottom:6px"><span style="color:#22c55e;font-weight:600">Before:</span></div>';
|
|
972
848
|
html += '<div class="detail-items" style="margin-left:8px">';
|
|
973
849
|
applicableBeforeFilters.forEach(f => {
|
|
974
|
-
let filterInfo = '<span class="tag
|
|
850
|
+
let filterInfo = '<span class="tag tag-before tag-sm">before</span><span class="name">' + f.name + '</span>';
|
|
975
851
|
if (f.if) filterInfo += '<span style="font-size:10px;color:var(--text2);margin-left:4px">if: ' + f.if + '</span>';
|
|
976
852
|
if (f.unless) filterInfo += '<span style="font-size:10px;color:var(--text2);margin-left:4px">unless: ' + f.unless + '</span>';
|
|
977
853
|
html += '<div class="detail-item">' + filterInfo + '</div>';
|
|
@@ -989,7 +865,7 @@ var PageMapGenerator = class {
|
|
|
989
865
|
html += '<div style="font-size:11px;margin-top:8px;margin-bottom:6px"><span style="color:#f59e0b;font-weight:600">After:</span></div>';
|
|
990
866
|
html += '<div class="detail-items" style="margin-left:8px">';
|
|
991
867
|
applicableAfterFilters.forEach(f => {
|
|
992
|
-
let filterInfo = '<span class="tag
|
|
868
|
+
let filterInfo = '<span class="tag tag-after tag-sm">after</span><span class="name">' + f.name + '</span>';
|
|
993
869
|
html += '<div class="detail-item">' + filterInfo + '</div>';
|
|
994
870
|
});
|
|
995
871
|
html += '</div>';
|
|
@@ -1008,7 +884,7 @@ var PageMapGenerator = class {
|
|
|
1008
884
|
html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
|
|
1009
885
|
html += '<div class="detail-items">';
|
|
1010
886
|
services.forEach(s => {
|
|
1011
|
-
html += '<div class="detail-item"><span class="tag
|
|
887
|
+
html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
|
|
1012
888
|
});
|
|
1013
889
|
html += '</div></div>';
|
|
1014
890
|
}
|
|
@@ -1019,7 +895,7 @@ var PageMapGenerator = class {
|
|
|
1019
895
|
html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
|
|
1020
896
|
html += '<div class="detail-items">';
|
|
1021
897
|
route.grpcCalls.forEach(g => {
|
|
1022
|
-
html += '<div class="detail-item"><span class="tag
|
|
898
|
+
html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
|
|
1023
899
|
});
|
|
1024
900
|
html += '</div></div>';
|
|
1025
901
|
}
|
|
@@ -1031,7 +907,7 @@ var PageMapGenerator = class {
|
|
|
1031
907
|
html += '<div class="detail-label">\u{1F4BE} Models Accessed</div>';
|
|
1032
908
|
html += '<div class="detail-items">';
|
|
1033
909
|
models.forEach(m => {
|
|
1034
|
-
html += '<div class="detail-item"><span class="tag
|
|
910
|
+
html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
|
|
1035
911
|
});
|
|
1036
912
|
html += '</div></div>';
|
|
1037
913
|
}
|
|
@@ -1050,13 +926,13 @@ var PageMapGenerator = class {
|
|
|
1050
926
|
html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;max-height:150px;overflow-y:auto">';
|
|
1051
927
|
html += '<div style="font-family:monospace;font-size:11px;line-height:1.6">';
|
|
1052
928
|
meaningfulCalls.forEach((call, i) => {
|
|
1053
|
-
html += '<div
|
|
929
|
+
html += '<div class="accordion-item">';
|
|
1054
930
|
html += '<span style="color:var(--text2);margin-right:8px">' + (i+1) + '.</span>';
|
|
1055
|
-
html += '<span
|
|
931
|
+
html += '<span class="text-accent">' + call + '</span>';
|
|
1056
932
|
html += '</div>';
|
|
1057
933
|
});
|
|
1058
934
|
if (action.methodCalls.length > 15) {
|
|
1059
|
-
html += '<div
|
|
935
|
+
html += '<div class="note">...and ' + (action.methodCalls.length - 15) + ' more calls</div>';
|
|
1060
936
|
}
|
|
1061
937
|
html += '</div></div></div>';
|
|
1062
938
|
}
|
|
@@ -1068,23 +944,23 @@ var PageMapGenerator = class {
|
|
|
1068
944
|
html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;font-family:monospace;font-size:11px">';
|
|
1069
945
|
|
|
1070
946
|
if (route.line > 0) {
|
|
1071
|
-
html += '<div
|
|
1072
|
-
html += '<span
|
|
1073
|
-
html += '<span>config/routes.rb:<span
|
|
947
|
+
html += '<div class="detail-item flex items-center py-1">';
|
|
948
|
+
html += '<span class="text-muted w-20">Route:</span>';
|
|
949
|
+
html += '<span>config/routes.rb:<span class="text-success">' + route.line + '</span></span>';
|
|
1074
950
|
html += '</div>';
|
|
1075
951
|
}
|
|
1076
952
|
|
|
1077
953
|
if (ctrl) {
|
|
1078
|
-
html += '<div
|
|
1079
|
-
html += '<span
|
|
954
|
+
html += '<div class="detail-item flex items-center py-1">';
|
|
955
|
+
html += '<span class="text-muted w-20">Controller:</span>';
|
|
1080
956
|
html += '<span>app/controllers/' + ctrl.filePath;
|
|
1081
|
-
if (action && action.line) html += ':<span
|
|
957
|
+
if (action && action.line) html += ':<span class="text-success">' + action.line + '</span>';
|
|
1082
958
|
html += '</span></div>';
|
|
1083
959
|
}
|
|
1084
960
|
|
|
1085
961
|
if (route.hasView && route.view) {
|
|
1086
|
-
html += '<div
|
|
1087
|
-
html += '<span
|
|
962
|
+
html += '<div class="detail-item flex items-center py-1">';
|
|
963
|
+
html += '<span class="text-muted w-20">View:</span>';
|
|
1088
964
|
html += '<span>app/views/' + route.view.path + '</span>';
|
|
1089
965
|
html += '</div>';
|
|
1090
966
|
}
|
|
@@ -1094,12 +970,12 @@ var PageMapGenerator = class {
|
|
|
1094
970
|
if (ctrl) {
|
|
1095
971
|
html += '<div class="detail-section">';
|
|
1096
972
|
html += '<div class="detail-label">\u{1F4CB} Controller Info</div>';
|
|
1097
|
-
html += '<div
|
|
1098
|
-
html += '<div
|
|
973
|
+
html += '<div class="code-block">';
|
|
974
|
+
html += '<div class="section-title">' + ctrl.className + '</div>';
|
|
1099
975
|
html += '<div style="font-size:11px;color:var(--text2)">extends ' + ctrl.parentClass + '</div>';
|
|
1100
976
|
if (ctrl.concerns && ctrl.concerns.length > 0) {
|
|
1101
977
|
html += '<div style="margin-top:6px;font-size:11px">';
|
|
1102
|
-
html += '<span
|
|
978
|
+
html += '<span class="text-muted">Concerns:</span> ' + ctrl.concerns.join(', ');
|
|
1103
979
|
html += '</div>';
|
|
1104
980
|
}
|
|
1105
981
|
html += '</div></div>';
|
|
@@ -1139,12 +1015,12 @@ var PageMapGenerator = class {
|
|
|
1139
1015
|
const withUsageCount = components.filter(c => c.usedIn && c.usedIn.length > 0).length;
|
|
1140
1016
|
|
|
1141
1017
|
let html = '';
|
|
1142
|
-
html += '<div
|
|
1018
|
+
html += '<div class="info-box mb-3">';
|
|
1143
1019
|
html += '<div style="font-weight:600;margin-bottom:8px;display:flex;align-items:center;gap:8px"><span style="color:#61dafb">\u269B</span> React Components (from Rails)</div>';
|
|
1144
1020
|
html += '<div style="display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--text2)">';
|
|
1145
1021
|
html += '<span>' + components.length + ' components</span>';
|
|
1146
1022
|
html += '<span>\u2022</span>';
|
|
1147
|
-
html += '<span
|
|
1023
|
+
html += '<span class="text-success">' + ssrCount + ' SSR</span>';
|
|
1148
1024
|
html += '<span>\u2022</span>';
|
|
1149
1025
|
html += '<span style="color:#3b82f6">' + (components.length - ssrCount) + ' client</span>';
|
|
1150
1026
|
html += '<span>\u2022</span>';
|
|
@@ -1169,9 +1045,9 @@ var PageMapGenerator = class {
|
|
|
1169
1045
|
withEntry.forEach(comp => {
|
|
1170
1046
|
const usageCount = comp.usedIn?.length || 0;
|
|
1171
1047
|
const tags = [];
|
|
1172
|
-
if (comp.ssr) tags.push('<span class="tag
|
|
1173
|
-
if (usageCount > 0) tags.push('<span class="tag
|
|
1174
|
-
if (comp.sourceFile) tags.push('<span class="tag
|
|
1048
|
+
if (comp.ssr) tags.push('<span class="tag tag-ssr" title="Server-Side Rendering">SSR</span>');
|
|
1049
|
+
if (usageCount > 0) tags.push('<span class="tag tag-view" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
|
|
1050
|
+
if (comp.sourceFile) tags.push('<span class="tag tag-src" title="Has source file">SRC</span>');
|
|
1175
1051
|
|
|
1176
1052
|
// Find URL from routes based on controller/action OR infer from entry file
|
|
1177
1053
|
let urlInfo = '';
|
|
@@ -1193,7 +1069,7 @@ var PageMapGenerator = class {
|
|
|
1193
1069
|
|
|
1194
1070
|
html += '<div class="page-item" data-path="' + comp.name.toLowerCase() + '" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
|
|
1195
1071
|
html += '<div class="page-info">';
|
|
1196
|
-
html += '<span class="page-name" style="display:flex;align-items:center"><span
|
|
1072
|
+
html += '<span class="page-name" style="display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + '</span>';
|
|
1197
1073
|
html += '<span class="page-path" style="font-size:10px;color:var(--accent)">' + urlInfo + '</span>';
|
|
1198
1074
|
html += '</div>';
|
|
1199
1075
|
html += '<div class="page-tags">' + tags.join('') + '</div>';
|
|
@@ -1216,8 +1092,8 @@ var PageMapGenerator = class {
|
|
|
1216
1092
|
withoutEntry.forEach(comp => {
|
|
1217
1093
|
const usageCount = comp.usedIn?.length || 0;
|
|
1218
1094
|
const tags = [];
|
|
1219
|
-
if (comp.ssr) tags.push('<span class="tag
|
|
1220
|
-
if (usageCount > 0) tags.push('<span class="tag
|
|
1095
|
+
if (comp.ssr) tags.push('<span class="tag tag-ssr" title="Server-Side Rendering">SSR</span>');
|
|
1096
|
+
if (usageCount > 0) tags.push('<span class="tag tag-view" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
|
|
1221
1097
|
|
|
1222
1098
|
// Find URL from routes based on controller/action
|
|
1223
1099
|
let urlInfo = '';
|
|
@@ -1235,7 +1111,7 @@ var PageMapGenerator = class {
|
|
|
1235
1111
|
|
|
1236
1112
|
html += '<div class="page-item" data-path="' + comp.name.toLowerCase() + '" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
|
|
1237
1113
|
html += '<div class="page-info">';
|
|
1238
|
-
html += '<span class="page-name" style="display:flex;align-items:center"><span
|
|
1114
|
+
html += '<span class="page-name" style="display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + '</span>';
|
|
1239
1115
|
html += '<span class="page-path" style="font-size:10px;color:var(--accent)">' + (urlInfo || 'View-only') + '</span>';
|
|
1240
1116
|
html += '</div>';
|
|
1241
1117
|
html += '<div class="page-tags">' + tags.join('') + '</div>';
|
|
@@ -1345,7 +1221,7 @@ var PageMapGenerator = class {
|
|
|
1345
1221
|
const totalWithPartials = enrichedViews.filter(v => v.partials.length > 0).length;
|
|
1346
1222
|
|
|
1347
1223
|
let html = '';
|
|
1348
|
-
html += '<div
|
|
1224
|
+
html += '<div class="info-box mb-3">';
|
|
1349
1225
|
html += '<div style="font-weight:600;margin-bottom:8px">\u{1F5BC}\uFE0F Rails Screens (View Templates)</div>';
|
|
1350
1226
|
html += '<div style="display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--text2)">';
|
|
1351
1227
|
html += '<span>' + enrichedViews.length + ' screens</span>';
|
|
@@ -1392,7 +1268,7 @@ var PageMapGenerator = class {
|
|
|
1392
1268
|
if (!view.hasRoute) indicators += '<span class="route-tag route-tag-warn" title="No matching route found">\u26A0\uFE0F</span>';
|
|
1393
1269
|
|
|
1394
1270
|
// Display: URL path (if route exists) or controller/action
|
|
1395
|
-
const displayName = view.hasRoute ? view.path.replace(/:([a-z_]+)/g, '<span
|
|
1271
|
+
const displayName = view.hasRoute ? view.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') : view.controller + '#' + view.action;
|
|
1396
1272
|
|
|
1397
1273
|
// Search-friendly data-path includes path, controller, action
|
|
1398
1274
|
const searchPath = [view.path || '', view.controller || '', view.action || '', view.viewPath || ''].join(' ').toLowerCase();
|
|
@@ -1430,7 +1306,7 @@ var PageMapGenerator = class {
|
|
|
1430
1306
|
html += '<div class="detail-section">';
|
|
1431
1307
|
html += '<div class="detail-label">\u{1F310} URL Path</div>';
|
|
1432
1308
|
if (screen.hasRoute) {
|
|
1433
|
-
html += '<div class="detail-value" style="font-family:monospace">' + screen.path.replace(/:([a-z_]+)/g, '<span
|
|
1309
|
+
html += '<div class="detail-value" style="font-family:monospace">' + screen.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</div>';
|
|
1434
1310
|
} else {
|
|
1435
1311
|
html += '<div class="detail-value" style="color:var(--text2)">No route defined (orphan view)</div>';
|
|
1436
1312
|
}
|
|
@@ -1523,7 +1399,7 @@ var PageMapGenerator = class {
|
|
|
1523
1399
|
|
|
1524
1400
|
const tooltip = assignment && assignment.assignedValue ? assignment.assignedValue.replace(/"/g, '"') : '';
|
|
1525
1401
|
html += '<div class="detail-item"' + hiddenClass + ' title="' + tooltip + '">';
|
|
1526
|
-
html += '<span class="tag
|
|
1402
|
+
html += '<span class="tag tag-var tag-sm">@</span>';
|
|
1527
1403
|
html += '<span class="name" style="font-family:monospace;font-weight:500">' + v + '</span>';
|
|
1528
1404
|
|
|
1529
1405
|
if (linkedModel) {
|
|
@@ -1567,10 +1443,10 @@ var PageMapGenerator = class {
|
|
|
1567
1443
|
html += '<div class="detail-items">';
|
|
1568
1444
|
screen.reactComponents.forEach(rc => {
|
|
1569
1445
|
html += '<div class="detail-item">';
|
|
1570
|
-
html += '<span class="tag" style="
|
|
1446
|
+
html += '<span class="tag tag-react tag-sm" style="font-weight:600">React</span>';
|
|
1571
1447
|
html += '<span class="name" style="font-family:monospace;font-weight:500">' + rc.name + '</span>';
|
|
1572
1448
|
if (rc.ssr) {
|
|
1573
|
-
html += '<span
|
|
1449
|
+
html += '<span class="badge-success">SSR</span>';
|
|
1574
1450
|
}
|
|
1575
1451
|
if (rc.propsVar) {
|
|
1576
1452
|
html += '<span style="margin-left:auto;font-size:10px;color:var(--text2);font-family:monospace">props: ' + rc.propsVar + '</span>';
|
|
@@ -1591,7 +1467,7 @@ var PageMapGenerator = class {
|
|
|
1591
1467
|
html += '<div class="detail-items" id="' + partialListId + '">';
|
|
1592
1468
|
screen.partials.forEach((p, idx) => {
|
|
1593
1469
|
const hiddenClass = idx >= partialLimit ? ' style="display:none" data-hidden="true"' : '';
|
|
1594
|
-
html += '<div class="detail-item"' + hiddenClass + '><span class="tag
|
|
1470
|
+
html += '<div class="detail-item"' + hiddenClass + '><span class="tag tag-partial tag-sm">PARTIAL</span><span class="name" style="font-family:monospace;font-size:11px">' + p + '</span></div>';
|
|
1595
1471
|
});
|
|
1596
1472
|
html += '</div>';
|
|
1597
1473
|
if (hasMorePartials) {
|
|
@@ -1606,7 +1482,7 @@ var PageMapGenerator = class {
|
|
|
1606
1482
|
html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
|
|
1607
1483
|
html += '<div class="detail-items">';
|
|
1608
1484
|
screen.services.forEach(s => {
|
|
1609
|
-
html += '<div class="detail-item"><span class="tag
|
|
1485
|
+
html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
|
|
1610
1486
|
});
|
|
1611
1487
|
html += '</div></div>';
|
|
1612
1488
|
}
|
|
@@ -1617,7 +1493,7 @@ var PageMapGenerator = class {
|
|
|
1617
1493
|
html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
|
|
1618
1494
|
html += '<div class="detail-items">';
|
|
1619
1495
|
screen.grpcCalls.forEach(g => {
|
|
1620
|
-
html += '<div class="detail-item"><span class="tag
|
|
1496
|
+
html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
|
|
1621
1497
|
});
|
|
1622
1498
|
html += '</div></div>';
|
|
1623
1499
|
}
|
|
@@ -1628,7 +1504,7 @@ var PageMapGenerator = class {
|
|
|
1628
1504
|
html += '<div class="detail-label">\u{1F4BE} Models Used</div>';
|
|
1629
1505
|
html += '<div class="detail-items">';
|
|
1630
1506
|
screen.modelAccess.forEach(m => {
|
|
1631
|
-
html += '<div class="detail-item"><span class="tag
|
|
1507
|
+
html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
|
|
1632
1508
|
});
|
|
1633
1509
|
html += '</div></div>';
|
|
1634
1510
|
}
|
|
@@ -1636,10 +1512,10 @@ var PageMapGenerator = class {
|
|
|
1636
1512
|
// Controller Action info
|
|
1637
1513
|
html += '<div class="detail-section">';
|
|
1638
1514
|
html += '<div class="detail-label">\u{1F3AE} Controller Action</div>';
|
|
1639
|
-
html += '<div
|
|
1515
|
+
html += '<div class="code-block">';
|
|
1640
1516
|
html += '<div style="font-family:monospace;font-size:12px">' + screen.controller + '#' + screen.action + '</div>';
|
|
1641
1517
|
if (screen.controllerInfo) {
|
|
1642
|
-
html += '<div
|
|
1518
|
+
html += '<div class="subtext">app/controllers/' + screen.controllerInfo.filePath;
|
|
1643
1519
|
if (screen.actionLine) html += ':' + screen.actionLine;
|
|
1644
1520
|
html += '</div>';
|
|
1645
1521
|
|
|
@@ -1652,7 +1528,7 @@ var PageMapGenerator = class {
|
|
|
1652
1528
|
});
|
|
1653
1529
|
if (applicableFilters.length > 0) {
|
|
1654
1530
|
html += '<div style="margin-top:8px;font-size:11px">';
|
|
1655
|
-
html += '<span
|
|
1531
|
+
html += '<span class="text-success">Before filters:</span> ' + applicableFilters.map(f => f.name).join(', ');
|
|
1656
1532
|
html += '</div>';
|
|
1657
1533
|
}
|
|
1658
1534
|
}
|
|
@@ -1717,7 +1593,7 @@ var PageMapGenerator = class {
|
|
|
1717
1593
|
html += '<div class="detail-label">Method & Path</div>';
|
|
1718
1594
|
html += '<div class="detail-value">';
|
|
1719
1595
|
html += '<span style="background:' + methodColor + ';color:white;padding:2px 8px;border-radius:4px;font-weight:600;margin-right:8px">' + (route.method || 'GET') + '</span>';
|
|
1720
|
-
html += '<span
|
|
1596
|
+
html += '<span class="mono">' + route.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</span>';
|
|
1721
1597
|
html += '</div></div>';
|
|
1722
1598
|
|
|
1723
1599
|
html += '<div class="detail-section">';
|
|
@@ -1739,7 +1615,7 @@ var PageMapGenerator = class {
|
|
|
1739
1615
|
responseTypes.push('<span style="background:#8b5cf6;color:white;padding:2px 8px;border-radius:4px;font-size:11px;margin-right:4px">' + f.toUpperCase() + '</span>');
|
|
1740
1616
|
});
|
|
1741
1617
|
}
|
|
1742
|
-
html += responseTypes.length > 0 ? responseTypes.join('') : '<span
|
|
1618
|
+
html += responseTypes.length > 0 ? responseTypes.join('') : '<span class="text-muted">Unknown</span>';
|
|
1743
1619
|
html += '</div></div>';
|
|
1744
1620
|
|
|
1745
1621
|
if (actionDetails.redirectsTo) {
|
|
@@ -1757,7 +1633,7 @@ var PageMapGenerator = class {
|
|
|
1757
1633
|
html += '<div class="detail-label">\u{1F4C4} View Template</div>';
|
|
1758
1634
|
html += '<div class="detail-value" style="font-family:monospace;font-size:12px">app/views/' + view.path + '</div>';
|
|
1759
1635
|
if (view.partials && view.partials.length > 0) {
|
|
1760
|
-
html += '<div
|
|
1636
|
+
html += '<div class="subtext">Partials: ' + view.partials.slice(0, 5).join(', ') + '</div>';
|
|
1761
1637
|
}
|
|
1762
1638
|
if (view.instanceVars && view.instanceVars.length > 0) {
|
|
1763
1639
|
html += '<div style="margin-top:4px;font-size:11px;color:var(--text2)">Instance vars: @' + view.instanceVars.slice(0, 5).join(', @') + '</div>';
|
|
@@ -1769,7 +1645,7 @@ var PageMapGenerator = class {
|
|
|
1769
1645
|
if (controllerInfo && (controllerInfo.beforeActions.length > 0 || controllerInfo.afterActions.length > 0)) {
|
|
1770
1646
|
html += '<div class="detail-section">';
|
|
1771
1647
|
html += '<div class="detail-label">\u{1F512} Filters Applied</div>';
|
|
1772
|
-
html += '<div
|
|
1648
|
+
html += '<div class="code-block">';
|
|
1773
1649
|
|
|
1774
1650
|
const applicableBeforeFilters = controllerInfo.beforeActions.filter(f => {
|
|
1775
1651
|
if (f.only && f.only.length > 0) return f.only.includes(route.action);
|
|
@@ -1781,7 +1657,7 @@ var PageMapGenerator = class {
|
|
|
1781
1657
|
html += '<div style="font-size:11px;margin-bottom:4px"><span style="color:#22c55e;font-weight:600">Before:</span> ';
|
|
1782
1658
|
html += applicableBeforeFilters.map(f => {
|
|
1783
1659
|
let info = f.name;
|
|
1784
|
-
if (f.if) info += ' <span
|
|
1660
|
+
if (f.if) info += ' <span class="text-muted">(if: ' + f.if + ')</span>';
|
|
1785
1661
|
return info;
|
|
1786
1662
|
}).join(', ');
|
|
1787
1663
|
html += '</div>';
|
|
@@ -1812,7 +1688,7 @@ var PageMapGenerator = class {
|
|
|
1812
1688
|
html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
|
|
1813
1689
|
html += '<div class="detail-items">';
|
|
1814
1690
|
services.forEach(s => {
|
|
1815
|
-
html += '<div class="detail-item"><span class="tag
|
|
1691
|
+
html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
|
|
1816
1692
|
});
|
|
1817
1693
|
html += '</div></div>';
|
|
1818
1694
|
}
|
|
@@ -1824,7 +1700,7 @@ var PageMapGenerator = class {
|
|
|
1824
1700
|
html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
|
|
1825
1701
|
html += '<div class="detail-items">';
|
|
1826
1702
|
grpcCalls.forEach(g => {
|
|
1827
|
-
html += '<div class="detail-item"><span class="tag
|
|
1703
|
+
html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
|
|
1828
1704
|
});
|
|
1829
1705
|
html += '</div></div>';
|
|
1830
1706
|
}
|
|
@@ -1836,7 +1712,7 @@ var PageMapGenerator = class {
|
|
|
1836
1712
|
html += '<div class="detail-label">\u{1F4BE} Models Accessed</div>';
|
|
1837
1713
|
html += '<div class="detail-items">';
|
|
1838
1714
|
models.forEach(m => {
|
|
1839
|
-
html += '<div class="detail-item"><span class="tag
|
|
1715
|
+
html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
|
|
1840
1716
|
});
|
|
1841
1717
|
html += '</div></div>';
|
|
1842
1718
|
}
|
|
@@ -1854,13 +1730,13 @@ var PageMapGenerator = class {
|
|
|
1854
1730
|
html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;max-height:150px;overflow-y:auto">';
|
|
1855
1731
|
html += '<div style="font-family:monospace;font-size:11px;line-height:1.6">';
|
|
1856
1732
|
meaningfulCalls.forEach((call, i) => {
|
|
1857
|
-
html += '<div
|
|
1733
|
+
html += '<div class="accordion-item">';
|
|
1858
1734
|
html += '<span style="color:var(--text2);margin-right:8px">' + (i+1) + '.</span>';
|
|
1859
|
-
html += '<span
|
|
1735
|
+
html += '<span class="text-accent">' + call + '</span>';
|
|
1860
1736
|
html += '</div>';
|
|
1861
1737
|
});
|
|
1862
1738
|
if (actionDetails.methodCalls.length > 15) {
|
|
1863
|
-
html += '<div
|
|
1739
|
+
html += '<div class="note">...and ' + (actionDetails.methodCalls.length - 15) + ' more</div>';
|
|
1864
1740
|
}
|
|
1865
1741
|
html += '</div></div></div>';
|
|
1866
1742
|
}
|
|
@@ -1872,16 +1748,16 @@ var PageMapGenerator = class {
|
|
|
1872
1748
|
html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;font-family:monospace;font-size:11px">';
|
|
1873
1749
|
|
|
1874
1750
|
if (controllerInfo) {
|
|
1875
|
-
html += '<div
|
|
1876
|
-
html += '<span
|
|
1751
|
+
html += '<div class="detail-item flex items-center py-1">';
|
|
1752
|
+
html += '<span class="text-muted w-20">Controller:</span>';
|
|
1877
1753
|
html += '<span>app/controllers/' + controllerInfo.filePath;
|
|
1878
|
-
if (actionDetails && actionDetails.line) html += ':<span
|
|
1754
|
+
if (actionDetails && actionDetails.line) html += ':<span class="text-success">' + actionDetails.line + '</span>';
|
|
1879
1755
|
html += '</span></div>';
|
|
1880
1756
|
}
|
|
1881
1757
|
|
|
1882
1758
|
if (view) {
|
|
1883
|
-
html += '<div
|
|
1884
|
-
html += '<span
|
|
1759
|
+
html += '<div class="detail-item flex items-center py-1">';
|
|
1760
|
+
html += '<span class="text-muted w-20">View:</span>';
|
|
1885
1761
|
html += '<span>app/views/' + view.path + '</span>';
|
|
1886
1762
|
html += '</div>';
|
|
1887
1763
|
}
|
|
@@ -1891,12 +1767,12 @@ var PageMapGenerator = class {
|
|
|
1891
1767
|
if (controllerInfo) {
|
|
1892
1768
|
html += '<div class="detail-section">';
|
|
1893
1769
|
html += '<div class="detail-label">\u{1F4CB} Controller Info</div>';
|
|
1894
|
-
html += '<div
|
|
1895
|
-
html += '<div
|
|
1770
|
+
html += '<div class="code-block">';
|
|
1771
|
+
html += '<div class="section-title">' + controllerInfo.className + '</div>';
|
|
1896
1772
|
html += '<div style="font-size:11px;color:var(--text2)">extends ' + controllerInfo.parentClass + '</div>';
|
|
1897
1773
|
if (controllerInfo.concerns && controllerInfo.concerns.length > 0) {
|
|
1898
1774
|
html += '<div style="margin-top:6px;font-size:11px">';
|
|
1899
|
-
html += '<span
|
|
1775
|
+
html += '<span class="text-muted">Concerns:</span> ' + controllerInfo.concerns.join(', ');
|
|
1900
1776
|
html += '</div>';
|
|
1901
1777
|
}
|
|
1902
1778
|
html += '</div></div>';
|
|
@@ -1935,7 +1811,7 @@ var PageMapGenerator = class {
|
|
|
1935
1811
|
html += '<div class="detail-label">Partials Used</div>';
|
|
1936
1812
|
html += '<div class="detail-items">';
|
|
1937
1813
|
view.partials.forEach(p => {
|
|
1938
|
-
html += '<div class="detail-item"><span class="tag
|
|
1814
|
+
html += '<div class="detail-item"><span class="tag tag-partial">PARTIAL</span><span class="name">' + p + '</span></div>';
|
|
1939
1815
|
});
|
|
1940
1816
|
html += '</div></div>';
|
|
1941
1817
|
}
|
|
@@ -1945,7 +1821,7 @@ var PageMapGenerator = class {
|
|
|
1945
1821
|
html += '<div class="detail-label">Instance Variables</div>';
|
|
1946
1822
|
html += '<div class="detail-items">';
|
|
1947
1823
|
view.instanceVars.slice(0, 10).forEach(v => {
|
|
1948
|
-
html += '<div class="detail-item"><span class="tag
|
|
1824
|
+
html += '<div class="detail-item"><span class="tag tag-var">@</span><span class="name">' + v + '</span></div>';
|
|
1949
1825
|
});
|
|
1950
1826
|
if (view.instanceVars.length > 10) {
|
|
1951
1827
|
html += '<div style="padding:4px 8px;color:var(--text2);font-size:11px">...and ' + (view.instanceVars.length - 10) + ' more</div>';
|
|
@@ -2150,7 +2026,7 @@ var PageMapGenerator = class {
|
|
|
2150
2026
|
// Path header with depth visual
|
|
2151
2027
|
dataHtml += '<div class="data-path-group" style="margin:8px 0">' +
|
|
2152
2028
|
'<div class="data-path-header" style="font-size:11px;color:var(--text2);margin-bottom:4px;padding-left:'+(ops[0]?.depth * 8)+'px">' +
|
|
2153
|
-
depthIndicator + '<span
|
|
2029
|
+
depthIndicator + '<span class="text-accent">' + pathLabel + '</span> (' + ops.length + ')' +
|
|
2154
2030
|
'</div>';
|
|
2155
2031
|
|
|
2156
2032
|
ops.forEach(op => {
|
|
@@ -2171,7 +2047,7 @@ var PageMapGenerator = class {
|
|
|
2171
2047
|
dataHtml += '<div class="detail-section"><h4>Used Components</h4>';
|
|
2172
2048
|
uniqueComponentRefs.forEach(df => {
|
|
2173
2049
|
const name = df.operationName || '';
|
|
2174
|
-
dataHtml += '<div class="detail-item" style="cursor:default"><span class="tag
|
|
2050
|
+
dataHtml += '<div class="detail-item" style="cursor:default"><span class="tag tag-default">COMPONENT</span> '+name+'</div>';
|
|
2175
2051
|
});
|
|
2176
2052
|
dataHtml += '</div>';
|
|
2177
2053
|
}
|
|
@@ -2196,7 +2072,7 @@ var PageMapGenerator = class {
|
|
|
2196
2072
|
const methodColors = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',DELETE:'#ef4444',PATCH:'#8b5cf6'};
|
|
2197
2073
|
const color = methodColors[api.method] || '#6b7280';
|
|
2198
2074
|
restApiHtml += '<div class="detail-item api-item" onclick="event.stopPropagation(); showApiDetail(\\''+api.id.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2199
|
-
'<div class="api-row"><span class="tag" style="background:'+color+'">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
|
|
2075
|
+
'<div class="api-row"><span class="tag" style="background:'+color+';color:white">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
|
|
2200
2076
|
(api.filePath ? '<div class="api-route">'+api.callType+' in '+api.filePath+'</div>' : '') +
|
|
2201
2077
|
'</div>';
|
|
2202
2078
|
});
|
|
@@ -2343,7 +2219,7 @@ var PageMapGenerator = class {
|
|
|
2343
2219
|
html += '<div style="margin-bottom:12px">';
|
|
2344
2220
|
html += '<div class="detail-item" style="cursor:pointer;background:var(--bg3);border-radius:4px" onclick="toggleGroupList(this)">';
|
|
2345
2221
|
html += '<div class="detail-label" style="display:flex;align-items:center;gap:6px"><span class="group-toggle">\u25B8</span>/'+g+'</div>';
|
|
2346
|
-
html += '<span
|
|
2222
|
+
html += '<span class="text-accent">'+groupPages.length+' pages</span></div>';
|
|
2347
2223
|
html += '<div class="group-page-list" style="display:none;margin-left:16px;margin-top:4px">';
|
|
2348
2224
|
groupPages.sort((a,b) => a.path.localeCompare(b.path)).forEach(p => {
|
|
2349
2225
|
const isAuth = p.authentication?.required;
|
|
@@ -2351,7 +2227,7 @@ var PageMapGenerator = class {
|
|
|
2351
2227
|
html += '<div class="detail-item rel-item" style="cursor:pointer;padding:6px 8px" onclick="event.stopPropagation(); selectPage(\\''+p.path+'\\')">'+
|
|
2352
2228
|
'<span style="font-family:monospace;font-size:11px;color:var(--text)">'+p.path+'</span>'+
|
|
2353
2229
|
(isAuth ? '<span class="tag tag-auth" style="margin-left:6px;font-size:9px">AUTH</span>' : '')+
|
|
2354
|
-
(isDynamic ? '<span class="tag" style="margin-left:6px
|
|
2230
|
+
(isDynamic ? '<span class="tag tag-info" style="margin-left:6px" title="Dynamic Route">DYNAMIC</span>' : '')+
|
|
2355
2231
|
'</div>';
|
|
2356
2232
|
});
|
|
2357
2233
|
html += '</div></div>';
|
|
@@ -2464,7 +2340,7 @@ var PageMapGenerator = class {
|
|
|
2464
2340
|
const fragments = Array.from(gqlMap.values()).filter(o => o.type === 'fragment');
|
|
2465
2341
|
|
|
2466
2342
|
if (queries.length > 0) {
|
|
2467
|
-
html += '<div
|
|
2343
|
+
html += '<div class="subtext-accent">Queries ('+queries.length+')</div>';
|
|
2468
2344
|
queries.slice(0, 20).forEach(op => {
|
|
2469
2345
|
html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2470
2346
|
'<span class="tag tag-query">QUERY</span> '+op.name+'</div>';
|
|
@@ -2475,7 +2351,7 @@ var PageMapGenerator = class {
|
|
|
2475
2351
|
}
|
|
2476
2352
|
|
|
2477
2353
|
if (mutations.length > 0) {
|
|
2478
|
-
html += '<div
|
|
2354
|
+
html += '<div class="subtext-accent">Mutations ('+mutations.length+')</div>';
|
|
2479
2355
|
mutations.slice(0, 10).forEach(op => {
|
|
2480
2356
|
html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2481
2357
|
'<span class="tag tag-mutation">MUTATION</span> '+op.name+'</div>';
|
|
@@ -2486,10 +2362,10 @@ var PageMapGenerator = class {
|
|
|
2486
2362
|
}
|
|
2487
2363
|
|
|
2488
2364
|
if (fragments.length > 0) {
|
|
2489
|
-
html += '<div
|
|
2365
|
+
html += '<div class="subtext-accent">Fragments ('+fragments.length+')</div>';
|
|
2490
2366
|
fragments.slice(0, 5).forEach(op => {
|
|
2491
2367
|
html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2492
|
-
'<span class="tag
|
|
2368
|
+
'<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
|
|
2493
2369
|
});
|
|
2494
2370
|
if (fragments.length > 5) {
|
|
2495
2371
|
html += '<div style="color:var(--text2);font-size:10px;padding:4px">... and '+(fragments.length-5)+' more fragments</div>';
|
|
@@ -2514,7 +2390,7 @@ var PageMapGenerator = class {
|
|
|
2514
2390
|
const methodColors = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',DELETE:'#ef4444',PATCH:'#8b5cf6'};
|
|
2515
2391
|
const color = methodColors[api.method] || '#6b7280';
|
|
2516
2392
|
html += '<div class="detail-item api-item" onclick="event.stopPropagation(); showApiDetail(\\''+api.id.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2517
|
-
'<div class="api-row"><span class="tag" style="background:'+color+'">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
|
|
2393
|
+
'<div class="api-row"><span class="tag" style="background:'+color+';color:white">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
|
|
2518
2394
|
'<div class="api-route">'+api.callType+' in '+api.filePath+'</div>' +
|
|
2519
2395
|
'</div>';
|
|
2520
2396
|
});
|
|
@@ -2549,7 +2425,7 @@ var PageMapGenerator = class {
|
|
|
2549
2425
|
|
|
2550
2426
|
if (api.category && api.category !== 'internal') {
|
|
2551
2427
|
html += '<div class="detail-section"><h4>Category</h4>' +
|
|
2552
|
-
'<span class="tag
|
|
2428
|
+
'<span class="tag tag-accent">'+api.category.toUpperCase()+'</span></div>';
|
|
2553
2429
|
}
|
|
2554
2430
|
|
|
2555
2431
|
// Show in modal
|
|
@@ -2656,7 +2532,7 @@ var PageMapGenerator = class {
|
|
|
2656
2532
|
// Source info
|
|
2657
2533
|
if (sourcePath) {
|
|
2658
2534
|
const isHook = sourcePath.startsWith('use');
|
|
2659
|
-
html += '<div class="detail-section"><h4>Source</h4><div class="detail-item" style="font-size:12px">via '+(isHook?'Hook':'Component')+': <span
|
|
2535
|
+
html += '<div class="detail-section"><h4>Source</h4><div class="detail-item" style="font-size:12px">via '+(isHook?'Hook':'Component')+': <span class="text-accent">'+sourcePath+'</span></div></div>';
|
|
2660
2536
|
}
|
|
2661
2537
|
|
|
2662
2538
|
// Operation Name with copy button
|
|
@@ -2734,7 +2610,7 @@ var PageMapGenerator = class {
|
|
|
2734
2610
|
});
|
|
2735
2611
|
if (queries.length > 5) {
|
|
2736
2612
|
const remaining = queries.slice(5).map(o => ({name: o.name}));
|
|
2737
|
-
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2613
|
+
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 5) + ' more queries</div>';
|
|
2738
2614
|
}
|
|
2739
2615
|
}
|
|
2740
2616
|
|
|
@@ -2746,7 +2622,7 @@ var PageMapGenerator = class {
|
|
|
2746
2622
|
});
|
|
2747
2623
|
if (mutations.length > 5) {
|
|
2748
2624
|
const remaining = mutations.slice(5).map(o => ({name: o.name}));
|
|
2749
|
-
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2625
|
+
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more mutations</div>';
|
|
2750
2626
|
}
|
|
2751
2627
|
}
|
|
2752
2628
|
|
|
@@ -2754,11 +2630,11 @@ var PageMapGenerator = class {
|
|
|
2754
2630
|
html += '<div style="margin:8px 0;font-size:10px;color:var(--text2)">Fragments ('+fragments.length+')</div>';
|
|
2755
2631
|
fragments.slice(0,3).forEach(op => {
|
|
2756
2632
|
html += '<div class="detail-item data-op" onclick="showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2757
|
-
'<span class="tag
|
|
2633
|
+
'<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
|
|
2758
2634
|
});
|
|
2759
2635
|
if (fragments.length > 3) {
|
|
2760
2636
|
const remaining = fragments.slice(3).map(o => ({name: o.name}));
|
|
2761
|
-
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2637
|
+
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more fragments</div>';
|
|
2762
2638
|
}
|
|
2763
2639
|
}
|
|
2764
2640
|
|
|
@@ -2874,7 +2750,7 @@ var PageMapGenerator = class {
|
|
|
2874
2750
|
});
|
|
2875
2751
|
if (queries.length > 8) {
|
|
2876
2752
|
const remaining = queries.slice(8).map(o => ({name: o.name}));
|
|
2877
|
-
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2753
|
+
html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 8) + ' more</div>';
|
|
2878
2754
|
}
|
|
2879
2755
|
}
|
|
2880
2756
|
|
|
@@ -2886,7 +2762,7 @@ var PageMapGenerator = class {
|
|
|
2886
2762
|
});
|
|
2887
2763
|
if (mutations.length > 5) {
|
|
2888
2764
|
const remaining = mutations.slice(5).map(o => ({name: o.name}));
|
|
2889
|
-
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2765
|
+
html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more</div>';
|
|
2890
2766
|
}
|
|
2891
2767
|
}
|
|
2892
2768
|
|
|
@@ -2894,11 +2770,11 @@ var PageMapGenerator = class {
|
|
|
2894
2770
|
html += '<div style="margin:8px 0 6px;font-size:10px;color:var(--text2)">Fragments ('+fragments.length+')</div>';
|
|
2895
2771
|
fragments.slice(0, 3).forEach(op => {
|
|
2896
2772
|
html += '<div class="detail-item data-op" onclick="showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
|
|
2897
|
-
'<span class="tag
|
|
2773
|
+
'<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
|
|
2898
2774
|
});
|
|
2899
2775
|
if (fragments.length > 3) {
|
|
2900
2776
|
const remaining = fragments.slice(3).map(o => ({name: o.name}));
|
|
2901
|
-
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)"
|
|
2777
|
+
html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '"')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more</div>';
|
|
2902
2778
|
}
|
|
2903
2779
|
}
|
|
2904
2780
|
|
|
@@ -3441,86 +3317,21 @@ var PageMapGenerator = class {
|
|
|
3441
3317
|
}
|
|
3442
3318
|
</script>
|
|
3443
3319
|
</body>
|
|
3444
|
-
</html
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
const colors = [
|
|
3448
|
-
"#ef4444",
|
|
3449
|
-
"#f97316",
|
|
3450
|
-
"#eab308",
|
|
3451
|
-
"#22c55e",
|
|
3452
|
-
"#14b8a6",
|
|
3453
|
-
"#3b82f6",
|
|
3454
|
-
"#8b5cf6",
|
|
3455
|
-
"#ec4899"
|
|
3456
|
-
];
|
|
3457
|
-
let idx = 0;
|
|
3458
|
-
return Array.from(groups.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([name, pages]) => {
|
|
3459
|
-
const color = colors[idx++ % colors.length];
|
|
3460
|
-
const sorted = pages.sort((a, b) => a.path.localeCompare(b.path));
|
|
3461
|
-
const pathSet = new Set(sorted.map((p) => p.path));
|
|
3462
|
-
const depthMap = /* @__PURE__ */ new Map();
|
|
3463
|
-
for (const p of sorted) {
|
|
3464
|
-
const segments = p.path.split("/").filter(Boolean);
|
|
3465
|
-
let depth = 0;
|
|
3466
|
-
for (let i = segments.length - 1; i >= 1; i--) {
|
|
3467
|
-
const ancestorPath = "/" + segments.slice(0, i).join("/");
|
|
3468
|
-
if (pathSet.has(ancestorPath)) {
|
|
3469
|
-
depth = (depthMap.get(ancestorPath) ?? 0) + 1;
|
|
3470
|
-
break;
|
|
3471
|
-
}
|
|
3472
|
-
}
|
|
3473
|
-
depthMap.set(p.path, depth);
|
|
3474
|
-
}
|
|
3475
|
-
const pagesHtml = sorted.map((p) => {
|
|
3476
|
-
const type = this.getPageType(p.path);
|
|
3477
|
-
const queries = (p.dataFetching || []).filter(
|
|
3478
|
-
(d) => !d.type?.includes("Mutation")
|
|
3479
|
-
).length;
|
|
3480
|
-
const mutations = (p.dataFetching || []).filter(
|
|
3481
|
-
(d) => d.type?.includes("Mutation")
|
|
3482
|
-
).length;
|
|
3483
|
-
const depth = depthMap.get(p.path) ?? 0;
|
|
3484
|
-
const pageNode = p;
|
|
3485
|
-
const repoName = pageNode.repo || "";
|
|
3486
|
-
const showRepoTag = allPages.some(
|
|
3487
|
-
(pg) => pg.repo && pg.repo !== repoName
|
|
3488
|
-
);
|
|
3489
|
-
const shortRepoName = repoName.split("/").pop()?.split("-").map((s) => s.substring(0, 4)).join("-") || repoName.substring(0, 8);
|
|
3490
|
-
const repoTag = showRepoTag && repoName ? `<span class="tag tag-repo" title="${repoName}">${shortRepoName}</span>` : "";
|
|
3491
|
-
const isSpaComponent = /^\/[A-Z]/.test(p.path) || p.filePath && p.filePath.includes("components/pages");
|
|
3492
|
-
const displayPath = isSpaComponent && p.filePath ? p.filePath.replace(/\.tsx?$/, "").replace(/^(frontend\/src\/|src\/)/, "") : p.path;
|
|
3493
|
-
const spaTag = isSpaComponent ? '<span class="tag" style="background:#6366f1;color:white" title="SPA Component Page">SPA</span>' : "";
|
|
3494
|
-
return `<div class="page-item" data-path="${p.path}" data-repo="${repoName}" onclick="selectPage('${p.path}')" style="--depth:${depth}">
|
|
3495
|
-
<span class="page-type" style="--type-color:${type.color}">${type.label}</span>
|
|
3496
|
-
<span class="page-path">${displayPath}</span>
|
|
3320
|
+
</html>`}buildTreeHtml(s,r){let c=["#ef4444","#f97316","#eab308","#22c55e","#14b8a6","#3b82f6","#8b5cf6","#ec4899"],v=0;return Array.from(s.entries()).sort((t,l)=>t[0].localeCompare(l[0])).map(([t,l])=>{let e=c[v++%c.length],i=l.sort((a,m)=>a.path.localeCompare(m.path)),o=new Set(i.map(a=>a.path)),p=new Map;for(let a of i){let m=a.path.split("/").filter(Boolean),u=0;for(let h=m.length-1;h>=1;h--){let y="/"+m.slice(0,h).join("/");if(o.has(y)){u=(p.get(y)??0)+1;break}}p.set(a.path,u);}let f=i.map(a=>{let m=this.getPageType(a.path),u=(a.dataFetching||[]).filter(g=>!g.type?.includes("Mutation")).length,h=(a.dataFetching||[]).filter(g=>g.type?.includes("Mutation")).length,y=p.get(a.path)??0,n=a.repo||"",w=r.some(g=>g.repo&&g.repo!==n),C=n.split("/").pop()?.split("-").map(g=>g.substring(0,4)).join("-")||n.substring(0,8),x=w&&n?`<span class="tag tag-repo" title="${n}">${C}</span>`:"",d=/^\/[A-Z]/.test(a.path)||a.filePath&&a.filePath.includes("components/pages"),b=d&&a.filePath?a.filePath.replace(/\.tsx?$/,"").replace(/^(frontend\/src\/|src\/)/,""):a.path,R=d?'<span class="tag tag-info" title="SPA Component Page">SPA</span>':"";return `<div class="page-item" data-path="${a.path}" data-repo="${n}" onclick="selectPage('${a.path}')" style="--depth:${y}">
|
|
3321
|
+
<span class="page-type" style="--type-color:${m.color}">${m.label}</span>
|
|
3322
|
+
<span class="page-path">${b}</span>
|
|
3497
3323
|
<div class="page-tags">
|
|
3498
|
-
${
|
|
3499
|
-
${
|
|
3500
|
-
${
|
|
3501
|
-
${
|
|
3502
|
-
${
|
|
3324
|
+
${x}
|
|
3325
|
+
${R}
|
|
3326
|
+
${a.authentication?.required?'<span class="tag tag-auth">AUTH</span>':""}
|
|
3327
|
+
${u>0?`<span class="tag tag-query">Q:${u}</span>`:""}
|
|
3328
|
+
${h>0?`<span class="tag tag-mutation">M:${h}</span>`:""}
|
|
3503
3329
|
</div>
|
|
3504
|
-
</div
|
|
3505
|
-
|
|
3506
|
-
return `<div class="group">
|
|
3507
|
-
<div class="group-header" onclick="toggleGroup(this)" style="--group-color:${color}">
|
|
3330
|
+
</div>`}).join("");return `<div class="group">
|
|
3331
|
+
<div class="group-header" onclick="toggleGroup(this)" style="--group-color:${e}">
|
|
3508
3332
|
<span class="group-arrow">\u25BC</span>
|
|
3509
|
-
<span class="group-name">/${
|
|
3510
|
-
<span class="group-count">${
|
|
3333
|
+
<span class="group-name">/${t}</span>
|
|
3334
|
+
<span class="group-count">${l.length}</span>
|
|
3511
3335
|
</div>
|
|
3512
|
-
<div class="group-content">${
|
|
3513
|
-
</div
|
|
3514
|
-
}).join("");
|
|
3515
|
-
}
|
|
3516
|
-
getPageType(path) {
|
|
3517
|
-
const last = path.split("/").filter(Boolean).pop() || "";
|
|
3518
|
-
if (last === "new" || path.endsWith("/new")) return { label: "CREATE", color: "#22c55e" };
|
|
3519
|
-
if (last === "edit" || path.includes("/edit")) return { label: "EDIT", color: "#f59e0b" };
|
|
3520
|
-
if (last.startsWith("[") || last.startsWith(":")) return { label: "DETAIL", color: "#3b82f6" };
|
|
3521
|
-
if (path.includes("setting")) return { label: "SETTINGS", color: "#6b7280" };
|
|
3522
|
-
return { label: "LIST", color: "#06b6d4" };
|
|
3523
|
-
}
|
|
3524
|
-
};
|
|
3525
|
-
|
|
3526
|
-
export { PageMapGenerator };
|
|
3336
|
+
<div class="group-content">${f}</div>
|
|
3337
|
+
</div>`}).join("")}getPageType(s){let r=s.split("/").filter(Boolean).pop()||"";return r==="new"||s.endsWith("/new")?{label:"CREATE",color:"#22c55e"}:r==="edit"||s.includes("/edit")?{label:"EDIT",color:"#f59e0b"}:r.startsWith("[")||r.startsWith(":")?{label:"DETAIL",color:"#3b82f6"}:s.includes("setting")?{label:"SETTINGS",color:"#6b7280"}:{label:"LIST",color:"#06b6d4"}}};export{S as a};
|