Skip to content

Commit 6e7e0b9

Browse files
authored
Merge pull request #75 from FloSch62/fix_54 [skip ci]
EQL query changes for 25.8 and the Fabric dashboard
2 parents 19d157e + 9badbd0 commit 6e7e0b9

File tree

4 files changed

+186
-33
lines changed

4 files changed

+186
-33
lines changed

src/webviews/dashboard/fabric/fabricDashboardPanel.ts

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ export class FabricDashboardPanel extends BasePanel {
3434
private superSpineStreamName = '';
3535
private fabricStatusStreamName = '';
3636
private initialized = false;
37+
private useFieldsQuery = false;
3738

3839
private get fabricQueryBase(): string {
39-
return '.namespace.resources.cr-status.fabrics_eda_nokia_com.v1alpha1.fabric.status';
40+
return this.useFieldsQuery
41+
? '.namespace.resources.cr.fabrics_eda_nokia_com.v1alpha1.fabric'
42+
: '.namespace.resources.cr-status.fabrics_eda_nokia_com.v1alpha1.fabric.status';
4043
}
4144

4245
constructor(context: vscode.ExtensionContext, title: string) {
@@ -46,6 +49,9 @@ export class FabricDashboardPanel extends BasePanel {
4649
});
4750

4851
this.edaClient = serviceManager.getClient<EdaClient>('eda');
52+
const specManager = (this.edaClient as any)['specManager'];
53+
const apiVersion = specManager?.getApiVersion?.() ?? '0';
54+
this.useFieldsQuery = this.isVersionAtLeast(apiVersion, '25.8');
4955

5056
this.streamClient = this.createStreamClient();
5157
void this.streamClient.connect();
@@ -114,6 +120,27 @@ export class FabricDashboardPanel extends BasePanel {
114120
return client;
115121
}
116122

123+
private isVersionAtLeast(version: string, target: string): boolean {
124+
const parse = (v: string) =>
125+
v
126+
.replace(/^[^0-9]*/, '')
127+
.split('.')
128+
.map(n => {
129+
const num = parseInt(n, 10);
130+
return Number.isNaN(num) ? 0 : num;
131+
});
132+
const vParts = parse(version);
133+
const tParts = parse(target);
134+
const len = Math.max(vParts.length, tParts.length);
135+
for (let i = 0; i < len; i++) {
136+
const vVal = vParts[i] ?? 0;
137+
const tVal = tParts[i] ?? 0;
138+
if (vVal > tVal) return true;
139+
if (vVal < tVal) return false;
140+
}
141+
return true;
142+
}
143+
117144
protected getHtml(): string {
118145
return this.readWebviewFile('dashboard', 'fabric', 'fabricDashboardPanel.html');
119146
}
@@ -485,7 +512,10 @@ export class FabricDashboardPanel extends BasePanel {
485512
await this.streamClient.closeEqlStream(this.spineStreamName);
486513
const namespaces = ns === 'All Namespaces' ? undefined : ns;
487514
this.spineStreamName = `spine-${namespaces ?? 'all'}-${randomUUID()}`;
488-
this.streamClient.setEqlQuery(`${this.fabricQueryBase}.spineNodes`, namespaces, this.spineStreamName);
515+
const query = this.useFieldsQuery
516+
? `${this.fabricQueryBase} fields [ status.spineNodes[].node ]`
517+
: `${this.fabricQueryBase}.spineNodes`;
518+
this.streamClient.setEqlQuery(query, namespaces, this.spineStreamName);
489519
this.streamClient.subscribeToStream(this.spineStreamName);
490520
await this.streamClient.connect();
491521
const stats = this.computeFabricGroupStats(ns, 'spines');
@@ -496,7 +526,10 @@ export class FabricDashboardPanel extends BasePanel {
496526
await this.streamClient.closeEqlStream(this.leafStreamName);
497527
const namespaces = ns === 'All Namespaces' ? undefined : ns;
498528
this.leafStreamName = `leaf-${namespaces ?? 'all'}-${randomUUID()}`;
499-
this.streamClient.setEqlQuery(`${this.fabricQueryBase}.leafNodes`, namespaces, this.leafStreamName);
529+
const query = this.useFieldsQuery
530+
? `${this.fabricQueryBase} fields [ status.leafNodes[].node ]`
531+
: `${this.fabricQueryBase}.leafNodes`;
532+
this.streamClient.setEqlQuery(query, namespaces, this.leafStreamName);
500533
this.streamClient.subscribeToStream(this.leafStreamName);
501534
await this.streamClient.connect();
502535
const stats = this.computeFabricGroupStats(ns, 'leafs');
@@ -507,7 +540,10 @@ export class FabricDashboardPanel extends BasePanel {
507540
await this.streamClient.closeEqlStream(this.borderLeafStreamName);
508541
const namespaces = ns === 'All Namespaces' ? undefined : ns;
509542
this.borderLeafStreamName = `borderleaf-${namespaces ?? 'all'}-${randomUUID()}`;
510-
this.streamClient.setEqlQuery(`${this.fabricQueryBase}.borderLeafNodes`, namespaces, this.borderLeafStreamName);
543+
const query = this.useFieldsQuery
544+
? `${this.fabricQueryBase} fields [ status.borderLeafNodes[].node ]`
545+
: `${this.fabricQueryBase}.borderLeafNodes`;
546+
this.streamClient.setEqlQuery(query, namespaces, this.borderLeafStreamName);
511547
this.streamClient.subscribeToStream(this.borderLeafStreamName);
512548
await this.streamClient.connect();
513549
const stats = this.computeFabricGroupStats(ns, 'borderleafs');
@@ -518,7 +554,10 @@ export class FabricDashboardPanel extends BasePanel {
518554
await this.streamClient.closeEqlStream(this.superSpineStreamName);
519555
const namespaces = ns === 'All Namespaces' ? undefined : ns;
520556
this.superSpineStreamName = `superspine-${namespaces ?? 'all'}-${randomUUID()}`;
521-
this.streamClient.setEqlQuery(`${this.fabricQueryBase}.superSpineNodes`, namespaces, this.superSpineStreamName);
557+
const query = this.useFieldsQuery
558+
? `${this.fabricQueryBase} fields [ status.superSpineNodes[].node ]`
559+
: `${this.fabricQueryBase}.superSpineNodes`;
560+
this.streamClient.setEqlQuery(query, namespaces, this.superSpineStreamName);
522561
this.streamClient.subscribeToStream(this.superSpineStreamName);
523562
await this.streamClient.connect();
524563
const stats = this.computeFabricGroupStats(ns, 'superspines');
@@ -529,7 +568,10 @@ export class FabricDashboardPanel extends BasePanel {
529568
await this.streamClient.closeEqlStream(this.fabricStatusStreamName);
530569
const namespaces = ns === 'All Namespaces' ? undefined : ns;
531570
this.fabricStatusStreamName = `fabricstatus-${namespaces ?? 'all'}-${randomUUID()}`;
532-
this.streamClient.setEqlQuery(this.fabricQueryBase, namespaces, this.fabricStatusStreamName);
571+
const query = this.useFieldsQuery
572+
? `${this.fabricQueryBase} fields [ status.health ]`
573+
: this.fabricQueryBase;
574+
this.streamClient.setEqlQuery(query, namespaces, this.fabricStatusStreamName);
533575
this.streamClient.subscribeToStream(this.fabricStatusStreamName);
534576
await this.streamClient.connect();
535577
const health = this.computeFabricHealth(ns);
@@ -560,6 +602,33 @@ export class FabricDashboardPanel extends BasePanel {
560602
this.updateNodeGroup(msg, 'superspines');
561603
}
562604

605+
private extractNodesFromRow(
606+
data: any,
607+
key: 'leafs' | 'borderleafs' | 'spines' | 'superspines'
608+
): string[] {
609+
const status = data?.status;
610+
if (!status) return [];
611+
let arr: any[] | undefined;
612+
switch (key) {
613+
case 'spines':
614+
arr = status.spineNodes;
615+
break;
616+
case 'leafs':
617+
arr = status.leafNodes;
618+
break;
619+
case 'borderleafs':
620+
arr = status.borderLeafNodes;
621+
break;
622+
case 'superspines':
623+
arr = status.superSpineNodes;
624+
break;
625+
}
626+
if (!Array.isArray(arr)) return [];
627+
return arr
628+
.map(n => n?.node)
629+
.filter((n): n is string => typeof n === 'string');
630+
}
631+
563632
private updateNodeGroup(
564633
msg: any,
565634
key: 'leafs' | 'borderleafs' | 'spines' | 'superspines'
@@ -572,9 +641,7 @@ export class FabricDashboardPanel extends BasePanel {
572641
if (Array.isArray(rows)) {
573642
for (const r of rows) {
574643
const ns = r.data?.['.namespace.name'] as string | undefined;
575-
const name = r.data?.node as string | undefined;
576-
const id = r.id as number | undefined;
577-
if (!ns || !name || id === undefined) continue;
644+
if (!ns) continue;
578645
let stats = this.fabricMap.get(ns);
579646
if (!stats) {
580647
stats = {
@@ -586,16 +653,27 @@ export class FabricDashboardPanel extends BasePanel {
586653
};
587654
this.fabricMap.set(ns, stats);
588655
}
589-
stats[key].nodes.set(id, name);
656+
if (this.useFieldsQuery) {
657+
const nodes = this.extractNodesFromRow(r.data, key);
658+
stats[key].nodes.clear();
659+
nodes.forEach((n, idx) => stats![key].nodes.set(idx, n));
660+
} else {
661+
const name = r.data?.node as string | undefined;
662+
const id = r.id as number | undefined;
663+
if (!name || id === undefined) continue;
664+
stats[key].nodes.set(id, name);
665+
}
590666
changed.add(ns);
591667
}
592668
}
593-
const delIds = op?.delete?.ids;
594-
if (Array.isArray(delIds)) {
595-
for (const delId of delIds) {
596-
for (const [ns, stats] of this.fabricMap) {
597-
if (stats[key].nodes.delete(delId)) {
598-
changed.add(ns);
669+
if (!this.useFieldsQuery) {
670+
const delIds = op?.delete?.ids;
671+
if (Array.isArray(delIds)) {
672+
for (const delId of delIds) {
673+
for (const [ns, stats] of this.fabricMap) {
674+
if (stats[key].nodes.delete(delId)) {
675+
changed.add(ns);
676+
}
599677
}
600678
}
601679
}
@@ -638,7 +716,9 @@ export class FabricDashboardPanel extends BasePanel {
638716
this.fabricMap.set(ns, stats);
639717
}
640718

641-
const newHealth = Number(data?.health ?? 0);
719+
const newHealth = Number(
720+
data?.health ?? data?.status?.health ?? 0
721+
);
642722
if (stats.health !== newHealth) {
643723
stats.health = newHealth;
644724
changed.add(ns);

src/webviews/dashboard/queries/queriesDashboard.css

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@
198198
}
199199

200200
.results-table {
201-
width: 100%;
201+
width: max-content;
202+
min-width: 100%;
202203
border-collapse: separate;
203204
border-spacing: 0;
204205
border-radius: 8px;
@@ -218,6 +219,17 @@
218219
user-select: none;
219220
}
220221

222+
.results-table td {
223+
vertical-align: top;
224+
}
225+
226+
.cell-content {
227+
max-width: 600px;
228+
max-height: 200px;
229+
overflow: auto;
230+
white-space: pre-wrap;
231+
}
232+
221233
.status-bar {
222234
padding: 4px 0;
223235
border-top: 1px solid var(--border);

src/webviews/dashboard/queries/queriesDashboard.webview.ts

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,45 @@ declare function acquireVsCodeApi(): {
3737
let sortAsc = true;
3838
let copyFormat: 'ascii' | 'markdown' | 'json' | 'yaml' = 'ascii';
3939

40+
function formatValue(value: any): string {
41+
if (value === null || value === undefined) return '';
42+
if (Array.isArray(value)) {
43+
if (value.length === 0) return '';
44+
const formatted = value.map(v => formatValue(v));
45+
const isPrimitive = value.every(
46+
v => v === null || v === undefined || typeof v !== 'object'
47+
);
48+
return formatted.join(isPrimitive ? ', ' : '\n');
49+
}
50+
if (typeof value === 'object') {
51+
const entries = Object.entries(value);
52+
if (entries.length === 0) return '';
53+
return entries
54+
.map(([k, v]) => `${k}: ${formatValue(v)}`)
55+
.join(', ');
56+
}
57+
return String(value);
58+
}
59+
60+
function pruneEmptyColumns(cols: string[], rows: any[][]): {
61+
cols: string[];
62+
rows: any[][];
63+
} {
64+
if (!rows.length) {
65+
return { cols, rows };
66+
}
67+
const keep: number[] = [];
68+
cols.forEach((_, idx) => {
69+
const hasValue = rows.some(r => formatValue(r[idx]) !== '');
70+
if (hasValue) keep.push(idx);
71+
});
72+
return {
73+
cols: keep.map(i => cols[i]),
74+
rows: rows.map(r => keep.map(i => r[i]))
75+
};
76+
}
77+
78+
4079
function updateQueryInputPlaceholder(): void {
4180
const queryType = queryTypeSelect.value;
4281
switch (queryType) {
@@ -252,9 +291,10 @@ declare function acquireVsCodeApi(): {
252291
autocompleteList.style.display = 'none';
253292
}
254293
} else if (msg.command === 'results') {
255-
const colsChanged = !arraysEqual(columns, msg.columns);
256-
columns = msg.columns;
257-
allRows = msg.rows;
294+
const filtered = pruneEmptyColumns(msg.columns, msg.rows);
295+
const colsChanged = !arraysEqual(columns, filtered.cols);
296+
columns = filtered.cols;
297+
allRows = filtered.rows;
258298
if (colsChanged) {
259299
sortIndex = -1;
260300
sortAsc = true;
@@ -404,8 +444,10 @@ declare function acquireVsCodeApi(): {
404444
const tr = document.createElement('tr');
405445
columns.forEach((_, i) => {
406446
const td = document.createElement('td');
407-
const val = row[i] == null ? '' : String(row[i]);
408-
td.textContent = val;
447+
const div = document.createElement('div');
448+
div.className = 'cell-content';
449+
div.textContent = formatValue(row[i]);
450+
td.appendChild(div);
409451
tr.appendChild(td);
410452
});
411453
resultsBody.appendChild(tr);
@@ -421,9 +463,9 @@ declare function acquireVsCodeApi(): {
421463
if (!val) return true;
422464
try {
423465
const regex = new RegExp(val, 'i');
424-
return regex.test(String(row[idx] ?? ''));
466+
return regex.test(formatValue(row[idx]));
425467
} catch {
426-
return String(row[idx] ?? '').toLowerCase().includes(val.toLowerCase());
468+
return formatValue(row[idx]).toLowerCase().includes(val.toLowerCase());
427469
}
428470
});
429471
});
@@ -450,8 +492,8 @@ declare function acquireVsCodeApi(): {
450492
function sortRows(): void {
451493
if (sortIndex < 0) return;
452494
allRows.sort((a, b) => {
453-
const av = a[sortIndex] ?? '';
454-
const bv = b[sortIndex] ?? '';
495+
const av = formatValue(a[sortIndex]);
496+
const bv = formatValue(b[sortIndex]);
455497
if (av < bv) return sortAsc ? -1 : 1;
456498
if (av > bv) return sortAsc ? 1 : -1;
457499
return 0;
@@ -483,7 +525,9 @@ declare function acquireVsCodeApi(): {
483525
const lines = rows.map(r =>
484526
'| ' +
485527
cols
486-
.map((_, i) => String(r[i] ?? '').replace(/[|]/g, '\\|'))
528+
.map((_, i) =>
529+
formatValue(r[i]).replace(/[|]/g, '\\|').replace(/\n/g, '<br/>')
530+
)
487531
.join(' | ') +
488532
' |'
489533
);
@@ -493,15 +537,15 @@ declare function acquireVsCodeApi(): {
493537
function toAsciiTable(cols: string[], rows: any[]): string {
494538
if (!cols.length) return '';
495539
const widths = cols.map((c, i) =>
496-
Math.max(c.length, ...rows.map(r => String(r[i] ?? '').length))
540+
Math.max(c.length, ...rows.map(r => formatValue(r[i]).length))
497541
);
498542
const hr = '+' + widths.map(w => '-'.repeat(w + 2)).join('+') + '+';
499543
const header =
500544
'|' + cols.map((c, i) => ' ' + c.padEnd(widths[i]) + ' ').join('|') + '|';
501545
const lines = rows.map(row =>
502546
'|' +
503547
cols
504-
.map((_, i) => ' ' + String(row[i] ?? '').padEnd(widths[i]) + ' ')
548+
.map((_, i) => ' ' + formatValue(row[i]).padEnd(widths[i]) + ' ')
505549
.join('|') +
506550
'|'
507551
);
@@ -523,7 +567,7 @@ declare function acquireVsCodeApi(): {
523567
const objs = rows.map(r => {
524568
const obj: Record<string, any> = {};
525569
cols.forEach((c, i) => {
526-
obj[c] = r[i];
570+
obj[c] = formatValue(r[i]);
527571
});
528572
return obj;
529573
});

0 commit comments

Comments
 (0)