viberadar 0.3.0 → 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/scanner/index.d.ts.map +1 -1
- package/dist/scanner/index.js +40 -2
- package/dist/scanner/index.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +73 -6
- package/dist/server/index.js.map +1 -1
- package/dist/ui/dashboard.html +72 -9
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrE,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;CACpB;AA0FD,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrE,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,OAAO,CAAC;CACpB;AA0FD,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAyJ1E"}
|
package/dist/scanner/index.js
CHANGED
|
@@ -142,7 +142,7 @@ async function scanProject(projectRoot) {
|
|
|
142
142
|
absolute: true,
|
|
143
143
|
});
|
|
144
144
|
const coverageMap = loadCoverageMap(projectRoot);
|
|
145
|
-
const
|
|
145
|
+
const testFileSet = new Set(files.filter((f) => TEST_PATTERNS.some((t) => f.includes(t))));
|
|
146
146
|
const modules = files.map((filePath) => {
|
|
147
147
|
const relativePath = path.relative(projectRoot, filePath);
|
|
148
148
|
const name = path.basename(filePath, path.extname(filePath));
|
|
@@ -155,8 +155,9 @@ async function scanProject(projectRoot) {
|
|
|
155
155
|
`${base}.test${ext}`,
|
|
156
156
|
`${base}.spec${ext}`,
|
|
157
157
|
filePath.replace('/src/', '/tests/').replace(ext, `.test${ext}`),
|
|
158
|
+
filePath.replace('\\src\\', '\\tests\\').replace(ext, `.test${ext}`),
|
|
158
159
|
];
|
|
159
|
-
testFile = candidates.find((c) =>
|
|
160
|
+
testFile = candidates.find((c) => testFileSet.has(c));
|
|
160
161
|
}
|
|
161
162
|
let size = 0;
|
|
162
163
|
try {
|
|
@@ -177,6 +178,43 @@ async function scanProject(projectRoot) {
|
|
|
177
178
|
featureKeys: [], // filled below
|
|
178
179
|
};
|
|
179
180
|
});
|
|
181
|
+
// ─── Fuzzy test pairing for centralized test directories ─────────────────────
|
|
182
|
+
// Handles patterns like: server/routes/auth.routes.ts → tests/auth.test.ts
|
|
183
|
+
// Also: WorkspaceSettings.tsx → workspace-settings.test.ts
|
|
184
|
+
//
|
|
185
|
+
// Strategy: strip extensions + .test/.spec + dashes/underscores + lowercase
|
|
186
|
+
// and match source file's first name segment against test file's clean name.
|
|
187
|
+
function cleanName(s) {
|
|
188
|
+
return s.toLowerCase().replace(/[_\-]/g, '');
|
|
189
|
+
}
|
|
190
|
+
// Build map: cleanName → test file absolute path (first match wins)
|
|
191
|
+
const testByCleanName = new Map();
|
|
192
|
+
for (const tf of testFileSet) {
|
|
193
|
+
let base = path.basename(tf, path.extname(tf)); // e.g. "auth.test" or "chat.spec"
|
|
194
|
+
base = base.replace(/\.(test|spec)$/, ''); // → "auth"
|
|
195
|
+
const clean = cleanName(base.split('.')[0]); // first dot-segment, cleaned
|
|
196
|
+
if (!testByCleanName.has(clean)) {
|
|
197
|
+
testByCleanName.set(clean, tf);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Second pass: for source modules still missing a test, try fuzzy match
|
|
201
|
+
for (const m of modules) {
|
|
202
|
+
if (m.hasTests || m.type === 'test')
|
|
203
|
+
continue;
|
|
204
|
+
// Try each dot-segment of the module name from left to right
|
|
205
|
+
const segments = m.name.split('.');
|
|
206
|
+
for (const seg of segments) {
|
|
207
|
+
const clean = cleanName(seg);
|
|
208
|
+
if (clean.length < 3)
|
|
209
|
+
continue; // skip too-short segments (avoid false positives)
|
|
210
|
+
const matched = testByCleanName.get(clean);
|
|
211
|
+
if (matched) {
|
|
212
|
+
m.hasTests = true;
|
|
213
|
+
m.testFile = path.relative(projectRoot, matched);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
180
218
|
// ─── Load viberadar.config.json ──────────────────────────────────────────────
|
|
181
219
|
let config = null;
|
|
182
220
|
const configPath = path.join(projectRoot, 'viberadar.config.json');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoJA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ interface ServerOptions {
|
|
|
5
5
|
port: number;
|
|
6
6
|
projectRoot: string;
|
|
7
7
|
}
|
|
8
|
-
export declare function startServer({ data, port, projectRoot }: ServerOptions): Promise<http.Server>;
|
|
8
|
+
export declare function startServer({ data: initialData, port, projectRoot }: ServerOptions): Promise<http.Server>;
|
|
9
9
|
export {};
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAErD,UAAU,aAAa;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAwGzG"}
|
package/dist/server/index.js
CHANGED
|
@@ -32,14 +32,72 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
exports.startServer = startServer;
|
|
37
40
|
const http = __importStar(require("http"));
|
|
38
41
|
const fs = __importStar(require("fs"));
|
|
39
42
|
const path = __importStar(require("path"));
|
|
43
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
|
44
|
+
const scanner_1 = require("../scanner");
|
|
40
45
|
const DASHBOARD_HTML = fs.readFileSync(path.join(__dirname, '../ui/dashboard.html'), 'utf-8');
|
|
41
|
-
function startServer({ data, port, projectRoot }) {
|
|
46
|
+
function startServer({ data: initialData, port, projectRoot }) {
|
|
42
47
|
return new Promise((resolve, reject) => {
|
|
48
|
+
// ── Mutable data reference ──────────────────────────────────────────────────
|
|
49
|
+
let currentData = initialData;
|
|
50
|
+
// ── SSE clients ─────────────────────────────────────────────────────────────
|
|
51
|
+
const sseClients = new Set();
|
|
52
|
+
function broadcast(event) {
|
|
53
|
+
const msg = `event: ${event}\ndata: {}\n\n`;
|
|
54
|
+
for (const client of sseClients) {
|
|
55
|
+
try {
|
|
56
|
+
client.write(msg);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
sseClients.delete(client);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ── File watcher + re-scan ──────────────────────────────────────────────────
|
|
64
|
+
let scanDebounce = null;
|
|
65
|
+
async function scheduleRescan(changedFile) {
|
|
66
|
+
if (scanDebounce)
|
|
67
|
+
clearTimeout(scanDebounce);
|
|
68
|
+
scanDebounce = setTimeout(async () => {
|
|
69
|
+
try {
|
|
70
|
+
const label = changedFile
|
|
71
|
+
? path.relative(projectRoot, changedFile).replace(/\\/g, '/')
|
|
72
|
+
: '…';
|
|
73
|
+
process.stdout.write(`\r 🔄 ${label} changed, rescanning... `);
|
|
74
|
+
currentData = await (0, scanner_1.scanProject)(projectRoot);
|
|
75
|
+
process.stdout.write(`\r ✅ ${currentData.modules.length} modules` +
|
|
76
|
+
(currentData.features ? `, ${currentData.features.length} features` : '') +
|
|
77
|
+
' \n');
|
|
78
|
+
broadcast('data-updated');
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
console.error('\nRescan error:', err.message);
|
|
82
|
+
}
|
|
83
|
+
}, 600);
|
|
84
|
+
}
|
|
85
|
+
chokidar_1.default.watch([
|
|
86
|
+
'**/*.{ts,tsx,js,jsx,vue,svelte}',
|
|
87
|
+
'viberadar.config.json',
|
|
88
|
+
], {
|
|
89
|
+
cwd: projectRoot,
|
|
90
|
+
ignored: [
|
|
91
|
+
'**/node_modules/**', '**/dist/**', '**/.git/**',
|
|
92
|
+
'**/coverage/**', '**/.next/**', '**/.turbo/**',
|
|
93
|
+
],
|
|
94
|
+
ignoreInitial: true,
|
|
95
|
+
persistent: true,
|
|
96
|
+
})
|
|
97
|
+
.on('add', f => scheduleRescan(path.join(projectRoot, f)))
|
|
98
|
+
.on('change', f => scheduleRescan(path.join(projectRoot, f)))
|
|
99
|
+
.on('unlink', f => scheduleRescan(path.join(projectRoot, f)));
|
|
100
|
+
// ── HTTP server ─────────────────────────────────────────────────────────────
|
|
43
101
|
const server = http.createServer((req, res) => {
|
|
44
102
|
const url = req.url ?? '/';
|
|
45
103
|
if (url === '/') {
|
|
@@ -49,7 +107,19 @@ function startServer({ data, port, projectRoot }) {
|
|
|
49
107
|
}
|
|
50
108
|
if (url === '/api/data') {
|
|
51
109
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
52
|
-
res.end(JSON.stringify(
|
|
110
|
+
res.end(JSON.stringify(currentData));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Server-Sent Events endpoint
|
|
114
|
+
if (url === '/api/events') {
|
|
115
|
+
res.writeHead(200, {
|
|
116
|
+
'Content-Type': 'text/event-stream',
|
|
117
|
+
'Cache-Control': 'no-cache',
|
|
118
|
+
'Connection': 'keep-alive',
|
|
119
|
+
});
|
|
120
|
+
res.write('data: connected\n\n'); // initial ping
|
|
121
|
+
sseClients.add(res);
|
|
122
|
+
req.on('close', () => sseClients.delete(res));
|
|
53
123
|
return;
|
|
54
124
|
}
|
|
55
125
|
res.writeHead(404);
|
|
@@ -63,10 +133,7 @@ function startServer({ data, port, projectRoot }) {
|
|
|
63
133
|
reject(err);
|
|
64
134
|
}
|
|
65
135
|
});
|
|
66
|
-
server.listen(port, '127.0.0.1', () =>
|
|
67
|
-
resolve(server);
|
|
68
|
-
});
|
|
69
|
-
// Graceful shutdown
|
|
136
|
+
server.listen(port, '127.0.0.1', () => resolve(server));
|
|
70
137
|
process.on('SIGINT', () => {
|
|
71
138
|
console.log('\n👋 VibeRadar stopped.');
|
|
72
139
|
server.close(() => process.exit(0));
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,kCAwGC;AAzHD,2CAA6B;AAC7B,uCAAyB;AACzB,2CAA6B;AAC7B,wDAAgC;AAChC,wCAAqD;AAQrD,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,EAC5C,OAAO,CACR,CAAC;AAEF,SAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAiB;IACjF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAErC,+EAA+E;QAC/E,IAAI,WAAW,GAAG,WAAW,CAAC;QAE9B,+EAA+E;QAC/E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAC;QAElD,SAAS,SAAS,CAAC,KAAa;YAC9B,MAAM,GAAG,GAAG,UAAU,KAAK,gBAAgB,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;gBAChC,IAAI,CAAC;oBAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC;oBAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,+EAA+E;QAC/E,IAAI,YAAY,GAAyC,IAAI,CAAC;QAE9D,KAAK,UAAU,cAAc,CAAC,WAAoB;YAChD,IAAI,YAAY;gBAAE,YAAY,CAAC,YAAY,CAAC,CAAC;YAC7C,YAAY,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;gBACnC,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,WAAW;wBACvB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;wBAC7D,CAAC,CAAC,GAAG,CAAC;oBACR,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,8BAA8B,CAAC,CAAC;oBACrE,WAAW,GAAG,MAAM,IAAA,qBAAW,EAAC,WAAW,CAAC,CAAC;oBAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,UAAU,WAAW,CAAC,OAAO,CAAC,MAAM,UAAU;wBAC9C,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,QAAQ,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;wBACzE,cAAc,CACf,CAAC;oBACF,SAAS,CAAC,cAAc,CAAC,CAAC;gBAC5B,CAAC;gBAAC,OAAO,GAAQ,EAAE,CAAC;oBAClB,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QAED,kBAAQ,CAAC,KAAK,CAAC;YACb,iCAAiC;YACjC,uBAAuB;SACxB,EAAE;YACD,GAAG,EAAE,WAAW;YAChB,OAAO,EAAE;gBACP,oBAAoB,EAAE,YAAY,EAAE,YAAY;gBAChD,gBAAgB,EAAK,aAAa,EAAE,cAAc;aACnD;YACD,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,IAAI;SACjB,CAAC;aACC,EAAE,CAAC,KAAK,EAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;aAC5D,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;aAC5D,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhE,+EAA+E;QAC/E,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;YAE3B,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;gBAChB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBACxB,OAAO;YACT,CAAC;YAED,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;gBACxB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;gBACrC,OAAO;YACT,CAAC;YAED,8BAA8B;YAC9B,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;gBAC1B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;oBACjB,cAAc,EAAG,mBAAmB;oBACpC,eAAe,EAAE,UAAU;oBAC3B,YAAY,EAAK,YAAY;iBAC9B,CAAC,CAAC;gBACH,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,eAAe;gBACjD,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACpB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAChD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,mDAAmD,CAAC,CAAC,CAAC;YACrF,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAExD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/ui/dashboard.html
CHANGED
|
@@ -351,6 +351,12 @@
|
|
|
351
351
|
<h1>VibeRadar</h1>
|
|
352
352
|
<span class="header-project" id="projectName">—</span>
|
|
353
353
|
<span class="header-time" id="scannedAt"></span>
|
|
354
|
+
<span id="liveDot" title="Connecting…" style="
|
|
355
|
+
width:8px; height:8px; border-radius:50%;
|
|
356
|
+
background:var(--dim); display:inline-block;
|
|
357
|
+
margin-left:8px; transition:background 0.3s;
|
|
358
|
+
flex-shrink:0;
|
|
359
|
+
"></span>
|
|
354
360
|
</header>
|
|
355
361
|
|
|
356
362
|
<div class="stats-bar" id="statsBar"></div>
|
|
@@ -540,8 +546,7 @@ function renderFeatureCards(c) {
|
|
|
540
546
|
const grid = document.getElementById('featGrid');
|
|
541
547
|
|
|
542
548
|
list.forEach(f => {
|
|
543
|
-
|
|
544
|
-
const pct = f.fileCount > 0 ? Math.min(100, Math.round(f.testFileCount / f.fileCount * 100)) : 0;
|
|
549
|
+
const pct = f.fileCount > 0 ? Math.round(f.testedCount / f.fileCount * 100) : 0;
|
|
545
550
|
const isActive = activePanelKey === f.key;
|
|
546
551
|
|
|
547
552
|
const card = document.createElement('div');
|
|
@@ -558,7 +563,7 @@ function renderFeatureCards(c) {
|
|
|
558
563
|
<div class="feature-progress-bar">
|
|
559
564
|
<div class="feature-progress-fill" style="width:${pct}%;background:${f.color}"></div>
|
|
560
565
|
</div>
|
|
561
|
-
<span class="feature-progress-label" style="color:${covColor(pct)}">${f.
|
|
566
|
+
<span class="feature-progress-label" style="color:${covColor(pct)}">${f.testedCount}/${f.fileCount} ✓</span>
|
|
562
567
|
</div>
|
|
563
568
|
</div>`;
|
|
564
569
|
card.onclick = () => openFeaturePanel(f.key);
|
|
@@ -608,7 +613,8 @@ function openFeaturePanel(key) {
|
|
|
608
613
|
const mods = D.modules.filter(m => m.featureKeys && m.featureKeys.includes(key));
|
|
609
614
|
const src = mods.filter(m => m.type !== 'test');
|
|
610
615
|
const tst = mods.filter(m => m.type === 'test');
|
|
611
|
-
const
|
|
616
|
+
const testedSrc = src.filter(m => m.hasTests).length;
|
|
617
|
+
const pct = src.length > 0 ? Math.round(testedSrc / src.length * 100) : 0;
|
|
612
618
|
|
|
613
619
|
document.getElementById('panelContent').innerHTML = `
|
|
614
620
|
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
|
@@ -623,12 +629,12 @@ function openFeaturePanel(key) {
|
|
|
623
629
|
<div class="panel-stat-lbl">Файлов</div>
|
|
624
630
|
</div>
|
|
625
631
|
<div class="panel-stat">
|
|
626
|
-
<div class="panel-stat-val">${
|
|
627
|
-
<div class="panel-stat-lbl"
|
|
632
|
+
<div class="panel-stat-val" style="color:${covColor(pct)}">${pct}%</div>
|
|
633
|
+
<div class="panel-stat-lbl">С тестами</div>
|
|
628
634
|
</div>
|
|
629
635
|
<div class="panel-stat">
|
|
630
|
-
<div class="panel-stat-val"
|
|
631
|
-
<div class="panel-stat-lbl"
|
|
636
|
+
<div class="panel-stat-val">${tst.length}</div>
|
|
637
|
+
<div class="panel-stat-lbl">Тест-файлов</div>
|
|
632
638
|
</div>
|
|
633
639
|
</div>
|
|
634
640
|
|
|
@@ -749,7 +755,64 @@ document.getElementById('searchInput').oninput = e => {
|
|
|
749
755
|
document.getElementById('panelClose').onclick = closePanel;
|
|
750
756
|
document.addEventListener('keydown', e => { if (e.key === 'Escape') closePanel(); });
|
|
751
757
|
|
|
752
|
-
|
|
758
|
+
// ─── Live reload ──────────────────────────────────────────────────────────────
|
|
759
|
+
function setLiveDot(color, title) {
|
|
760
|
+
const dot = document.getElementById('liveDot');
|
|
761
|
+
dot.style.background = color;
|
|
762
|
+
dot.title = title;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
async function refreshData() {
|
|
766
|
+
try {
|
|
767
|
+
const res = await fetch('/api/data');
|
|
768
|
+
D = await res.json();
|
|
769
|
+
|
|
770
|
+
// Update header timestamp
|
|
771
|
+
document.getElementById('scannedAt').textContent =
|
|
772
|
+
new Date(D.scannedAt).toLocaleTimeString();
|
|
773
|
+
|
|
774
|
+
renderStats();
|
|
775
|
+
renderSidebar();
|
|
776
|
+
renderContent();
|
|
777
|
+
|
|
778
|
+
// Re-open panel if it was open
|
|
779
|
+
const panelOpen = document.getElementById('panel').classList.contains('open');
|
|
780
|
+
if (panelOpen && activePanelKey) {
|
|
781
|
+
if (view === 'features' && D.features) {
|
|
782
|
+
openFeaturePanel(activePanelKey);
|
|
783
|
+
} else {
|
|
784
|
+
const m = D.modules.find(m => m.id === activePanelKey);
|
|
785
|
+
if (m) openModulePanel(m);
|
|
786
|
+
else closePanel();
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Brief green flash on the dot to signal fresh data
|
|
791
|
+
setLiveDot('#3fb950', 'Live — обновлено только что');
|
|
792
|
+
setTimeout(() => setLiveDot('#3fb950', 'Live — автообновление включено'), 1500);
|
|
793
|
+
} catch (err) {
|
|
794
|
+
console.error('Refresh failed:', err);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function connectSSE() {
|
|
799
|
+
const es = new EventSource('/api/events');
|
|
800
|
+
|
|
801
|
+
es.onopen = () => setLiveDot('#3fb950', 'Live — автообновление включено');
|
|
802
|
+
|
|
803
|
+
es.addEventListener('data-updated', () => {
|
|
804
|
+
setLiveDot('#e3b341', 'Обновляю данные…');
|
|
805
|
+
refreshData();
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
es.onerror = () => {
|
|
809
|
+
setLiveDot('var(--dim)', 'Нет соединения — переподключаюсь…');
|
|
810
|
+
es.close();
|
|
811
|
+
setTimeout(connectSSE, 3000);
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
init().then(() => connectSSE());
|
|
753
816
|
</script>
|
|
754
817
|
</body>
|
|
755
818
|
</html>
|