@aiready/visualizer 0.1.22 → 0.1.24
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/package.json +2 -2
- package/web/dist/assets/index-CmCfrPIo.js +50 -0
- package/web/dist/assets/index-Dizv739M.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/src/App.tsx +42 -1
- package/web/src/constants.ts +2 -2
- package/web/src/types.ts +8 -0
- package/web/src/utils.ts +67 -10
- package/web/vite.config.ts +15 -2
- package/web/dist/assets/index-R1Ga3mzd.js +0 -50
- package/web/dist/assets/index-cSvqzd3J.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-cyan-400:oklch(78.9% .154 211.53);--color-purple-400:oklch(71.4% .203 305.504);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-in:cubic-bezier(.4,0,1,1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.bottom-6{bottom:calc(var(--spacing)*6)}.left-6{left:calc(var(--spacing)*6)}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-4{margin-left:calc(var(--spacing)*4)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.h-1{height:calc(var(--spacing)*1)}.h-2{height:calc(var(--spacing)*2)}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-9{height:calc(var(--spacing)*9)}.h-12{height:calc(var(--spacing)*12)}.h-16{height:calc(var(--spacing)*16)}.h-full{height:100%}.h-screen{height:100vh}.w-2{width:calc(var(--spacing)*2)}.w-3{width:calc(var(--spacing)*3)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-7{width:calc(var(--spacing)*7)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-16{width:calc(var(--spacing)*16)}.w-80{width:calc(var(--spacing)*80)}.w-auto{width:auto}.w-full{width:100%}.w-px{width:1px}.max-w-md{max-width:var(--container-md)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-5{gap:calc(var(--spacing)*5)}.gap-6{gap:calc(var(--spacing)*6)}:where(.-space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*-2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*-2)*calc(1 - var(--tw-space-x-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.bg-cyan-400{background-color:var(--color-cyan-400)}.bg-purple-400{background-color:var(--color-purple-400)}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-10{padding-block:calc(var(--spacing)*10)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-400{color:var(--color-amber-400)}.text-amber-500{color:var(--color-amber-500)}.text-cyan-400{color:var(--color-cyan-400)}.text-purple-400{color:var(--color-purple-400)}.text-yellow-600{color:var(--color-yellow-600)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.uppercase{text-transform:uppercase}.opacity-40{opacity:.4}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.backdrop-blur-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}@media (hover:hover){.group-hover\:scale-125:is(:where(.group):hover *){--tw-scale-x:125%;--tw-scale-y:125%;--tw-scale-z:125%;scale:var(--tw-scale-x)var(--tw-scale-y)}.group-hover\:scale-y-150:is(:where(.group):hover *){--tw-scale-y:150%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white)5%,transparent)}}.hover\:bg-white\/10:hover{background-color:#ffffff1a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/10:hover{background-color:color-mix(in oklab,var(--color-white)10%,transparent)}}.hover\:text-yellow-800:hover{color:var(--color-yellow-800)}}}*{box-sizing:border-box;margin:0;padding:0}html,body,#root{width:100%;height:100%;overflow:hidden}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}#root{flex-direction:column;width:100%;height:100vh;display:flex}@keyframes fadeIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
|
package/web/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>AIReady Visualizer (Dev)</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CmCfrPIo.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dizv739M.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/web/src/App.tsx
CHANGED
|
@@ -24,6 +24,7 @@ function App() {
|
|
|
24
24
|
const [selectedNode, setSelectedNode] = useState<FileNode | null>(null);
|
|
25
25
|
const [loading, setLoading] = useState(true);
|
|
26
26
|
const [error, setError] = useState<string | null>(null);
|
|
27
|
+
const [truncatedWarning, setTruncatedWarning] = useState<{ nodes: boolean; edges: boolean } | null>(null);
|
|
27
28
|
|
|
28
29
|
// Filter state - start with all visible
|
|
29
30
|
const [visibleSeverities, setVisibleSeverities] = useState<Set<SeverityLevel>>(
|
|
@@ -51,7 +52,19 @@ function App() {
|
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
// Extract optional visualizer config from report (injected by CLI)
|
|
56
|
+
const visualizerConfig = (reportData as any).visualizerConfig;
|
|
57
|
+
const graphData = transformReportToGraph(reportData, visualizerConfig);
|
|
58
|
+
setData(graphData);
|
|
59
|
+
|
|
60
|
+
// Show warning if graph was truncated
|
|
61
|
+
if (graphData.truncated?.nodes || graphData.truncated?.edges) {
|
|
62
|
+
setTruncatedWarning({
|
|
63
|
+
nodes: graphData.truncated.nodes,
|
|
64
|
+
edges: graphData.truncated.edges,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
setLoading(false);
|
|
56
69
|
};
|
|
57
70
|
|
|
@@ -148,6 +161,34 @@ function App() {
|
|
|
148
161
|
data={filteredData}
|
|
149
162
|
/>
|
|
150
163
|
|
|
164
|
+
{/* Truncation warning banner */}
|
|
165
|
+
{truncatedWarning && (truncatedWarning.nodes || truncatedWarning.edges) && (
|
|
166
|
+
<div
|
|
167
|
+
className="px-4 py-3 bg-yellow-50 border-b flex items-center justify-between"
|
|
168
|
+
style={{ borderColor: colors.panelBorder }}
|
|
169
|
+
>
|
|
170
|
+
<div className="flex-1">
|
|
171
|
+
<p className="text-sm text-yellow-800 font-medium">
|
|
172
|
+
⚠️ Graph visualization truncated at display limits.
|
|
173
|
+
{truncatedWarning.nodes && ' Too many nodes.'}
|
|
174
|
+
{truncatedWarning.edges && ' Too many edges.'}
|
|
175
|
+
</p>
|
|
176
|
+
<p className="text-xs text-yellow-700 mt-1">
|
|
177
|
+
To show more data, increase graph limits in aiready.json:
|
|
178
|
+
<code className="bg-yellow-100 px-1 rounded" style={{ marginLeft: '4px' }}>
|
|
179
|
+
{'"visualizer": { "graph": { "maxNodes": 2000, "maxEdges": 5000 } }'}
|
|
180
|
+
</code>
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
<button
|
|
184
|
+
onClick={() => setTruncatedWarning(null)}
|
|
185
|
+
className="text-yellow-600 hover:text-yellow-800 ml-4 flex-shrink-0"
|
|
186
|
+
>
|
|
187
|
+
✕
|
|
188
|
+
</button>
|
|
189
|
+
</div>
|
|
190
|
+
)}
|
|
191
|
+
|
|
151
192
|
<div className="flex flex-1 overflow-hidden">
|
|
152
193
|
<div ref={containerRef} className="flex-1 relative">
|
|
153
194
|
{filteredData && (
|
package/web/src/constants.ts
CHANGED
package/web/src/types.ts
CHANGED
|
@@ -20,6 +20,14 @@ export interface GraphEdge {
|
|
|
20
20
|
export interface GraphData {
|
|
21
21
|
nodes: FileNode[];
|
|
22
22
|
edges: GraphEdge[];
|
|
23
|
+
truncated?: {
|
|
24
|
+
nodes: boolean;
|
|
25
|
+
edges: boolean;
|
|
26
|
+
nodeCount: number;
|
|
27
|
+
edgeCount: number;
|
|
28
|
+
nodeLimit: number;
|
|
29
|
+
edgeLimit: number;
|
|
30
|
+
};
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
// Filter types
|
package/web/src/utils.ts
CHANGED
|
@@ -11,7 +11,12 @@ export function getSeverityColor(severity: string | undefined): string {
|
|
|
11
11
|
return severityColors.default;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function transformReportToGraph(report: ReportData): GraphData {
|
|
14
|
+
export function transformReportToGraph(report: ReportData, runtimeGraphConfig?: { maxNodes?: number; maxEdges?: number }): GraphData {
|
|
15
|
+
// Use runtime config if available (from aiready.json), else use defaults from constants
|
|
16
|
+
const graphConfig = {
|
|
17
|
+
maxNodes: runtimeGraphConfig?.maxNodes ?? GRAPH_CONFIG.maxNodes,
|
|
18
|
+
maxEdges: runtimeGraphConfig?.maxEdges ?? GRAPH_CONFIG.maxEdges,
|
|
19
|
+
};
|
|
15
20
|
const nodes: FileNode[] = [];
|
|
16
21
|
const edges: GraphEdge[] = [];
|
|
17
22
|
const nodeMap = new Map<string, FileNode>();
|
|
@@ -33,7 +38,19 @@ export function transformReportToGraph(report: ReportData): GraphData {
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
for (const ctx of report.context) {
|
|
36
|
-
|
|
41
|
+
// Try direct match first. If not found, try basename fallback so that
|
|
42
|
+
// pattern entries with different path styles still associate their
|
|
43
|
+
// severity with the context file in consumer reports.
|
|
44
|
+
let issues = fileIssues.get(ctx.file);
|
|
45
|
+
if (!issues) {
|
|
46
|
+
const ctxBase = (ctx.file || '').split('/').pop();
|
|
47
|
+
for (const [k, v] of fileIssues.entries()) {
|
|
48
|
+
if ((k || '').split('/').pop() === ctxBase) {
|
|
49
|
+
issues = v;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
37
54
|
const severity = issues?.maxSeverity || ctx.severity || 'default';
|
|
38
55
|
const tokenCost = ctx.tokenCost || 0;
|
|
39
56
|
|
|
@@ -109,13 +126,45 @@ export function transformReportToGraph(report: ReportData): GraphData {
|
|
|
109
126
|
}
|
|
110
127
|
|
|
111
128
|
for (const related of ctx.relatedFiles || []) {
|
|
112
|
-
|
|
129
|
+
let relatedId: string | undefined = related;
|
|
130
|
+
|
|
131
|
+
// If exact match exists, use it. Otherwise try resolving relative paths
|
|
132
|
+
// from the source file's directory and try common extensions. As a
|
|
133
|
+
// final fallback, match by basename (endsWith) similar to dependency
|
|
134
|
+
// heuristics.
|
|
135
|
+
if (!nodeMap.has(relatedId)) {
|
|
136
|
+
const sourceDir = ctx.file.substring(0, ctx.file.lastIndexOf('/'));
|
|
137
|
+
const normalizedRel = related.replace(/^\.\/?/, '');
|
|
138
|
+
const tryPaths = [
|
|
139
|
+
`${sourceDir}/${normalizedRel}.ts`,
|
|
140
|
+
`${sourceDir}/${normalizedRel}.tsx`,
|
|
141
|
+
`${sourceDir}/${normalizedRel}/index.ts`,
|
|
142
|
+
`${sourceDir}/${normalizedRel}/index.tsx`,
|
|
143
|
+
`${sourceDir}/${normalizedRel}`,
|
|
144
|
+
];
|
|
145
|
+
for (const p of tryPaths) {
|
|
146
|
+
if (nodeMap.has(p)) {
|
|
147
|
+
relatedId = p;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Fallback: loose basename matching
|
|
154
|
+
if (!nodeMap.has(relatedId)) {
|
|
155
|
+
const relBase = (related.split('/').pop() || related).replace(/\.(ts|tsx|js|jsx)$/, '');
|
|
156
|
+
relatedId = [...nodeMap.keys()].find(k =>
|
|
157
|
+
k.endsWith(`/${relBase}.ts`) || k.endsWith(`/${relBase}.tsx`) || k.endsWith(`/${relBase}/index.ts`) || k.endsWith(`/${relBase}/index.tsx`) || k.endsWith(`/${relBase}`)
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (relatedId && nodeMap.has(relatedId) && relatedId !== ctx.file) {
|
|
113
162
|
const exists = edges.some(
|
|
114
163
|
e =>
|
|
115
|
-
(e.source === ctx.file && e.target ===
|
|
116
|
-
(e.source ===
|
|
164
|
+
(e.source === ctx.file && e.target === relatedId) ||
|
|
165
|
+
(e.source === relatedId && e.target === ctx.file)
|
|
117
166
|
);
|
|
118
|
-
if (!exists) edges.push({ source: ctx.file, target:
|
|
167
|
+
if (!exists) edges.push({ source: ctx.file, target: relatedId, type: 'related' });
|
|
119
168
|
}
|
|
120
169
|
}
|
|
121
170
|
}
|
|
@@ -135,8 +184,8 @@ export function transformReportToGraph(report: ReportData): GraphData {
|
|
|
135
184
|
const edgePriority: Record<string, number> = {
|
|
136
185
|
similarity: 1,
|
|
137
186
|
dependency: 2,
|
|
138
|
-
reference:
|
|
139
|
-
related:
|
|
187
|
+
reference: 4,
|
|
188
|
+
related: 3,
|
|
140
189
|
};
|
|
141
190
|
const sortedEdges = [...edges].sort((a, b) => {
|
|
142
191
|
const priorityA = edgePriority[a.type] || 99;
|
|
@@ -145,8 +194,16 @@ export function transformReportToGraph(report: ReportData): GraphData {
|
|
|
145
194
|
});
|
|
146
195
|
|
|
147
196
|
return {
|
|
148
|
-
nodes: nodes.slice(0,
|
|
149
|
-
edges: sortedEdges.slice(0,
|
|
197
|
+
nodes: nodes.slice(0, graphConfig.maxNodes),
|
|
198
|
+
edges: sortedEdges.slice(0, graphConfig.maxEdges),
|
|
199
|
+
truncated: {
|
|
200
|
+
nodes: nodes.length > graphConfig.maxNodes,
|
|
201
|
+
edges: sortedEdges.length > graphConfig.maxEdges,
|
|
202
|
+
nodeCount: nodes.length,
|
|
203
|
+
edgeCount: sortedEdges.length,
|
|
204
|
+
nodeLimit: graphConfig.maxNodes,
|
|
205
|
+
edgeLimit: graphConfig.maxEdges,
|
|
206
|
+
},
|
|
150
207
|
};
|
|
151
208
|
}
|
|
152
209
|
|
package/web/vite.config.ts
CHANGED
|
@@ -28,6 +28,7 @@ export default defineConfig(async ({ command }) => {
|
|
|
28
28
|
name: 'aiready-report-proxy',
|
|
29
29
|
configureServer(server: any) {
|
|
30
30
|
const reportPath = process.env.AIREADY_REPORT_PATH;
|
|
31
|
+
const visualizerConfigStr = process.env.AIREADY_VISUALIZER_CONFIG;
|
|
31
32
|
if (!reportPath) return;
|
|
32
33
|
server.middlewares.use(async (req: any, res: any, next: any) => {
|
|
33
34
|
try {
|
|
@@ -40,10 +41,22 @@ export default defineConfig(async ({ command }) => {
|
|
|
40
41
|
res.end('Report not found');
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
let data = await fsp.readFile(reportPath, 'utf8');
|
|
45
|
+
const report = JSON.parse(data);
|
|
46
|
+
|
|
47
|
+
// Inject visualizer config from env if available
|
|
48
|
+
if (visualizerConfigStr) {
|
|
49
|
+
try {
|
|
50
|
+
const visualizerConfig = JSON.parse(visualizerConfigStr);
|
|
51
|
+
report.visualizerConfig = visualizerConfig;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
// Silently ignore parse errors
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
res.statusCode = 200;
|
|
45
58
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
46
|
-
res.end(
|
|
59
|
+
res.end(JSON.stringify(report));
|
|
47
60
|
return;
|
|
48
61
|
}
|
|
49
62
|
} catch (e) {
|