Skip to content

Commit 3cb70c0

Browse files
fix(console): correct query parsing for parentheses and AND/OR logic for filter logs
1 parent 2a5ba09 commit 3cb70c0

File tree

4 files changed

+84
-32
lines changed

4 files changed

+84
-32
lines changed

gravitee-apim-console-webui/src/components/logs/logs-filters.controller.spec.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ describe('LogsFiltersController', () => {
111111

112112
expect(controller.filters.api).toEqual(['api-id']);
113113
expect(controller.filters.method).toEqual(['GET']);
114-
// status uses push(v) where v is an array, so it becomes [[...]]
115-
expect(controller.filters.status).toEqual([['200']]);
114+
// status now correctly pushes string values, not nested arrays
115+
expect(controller.filters.status).toEqual(['200']);
116116
});
117117

118118
it('should set display mode based on query filters', () => {
@@ -320,15 +320,13 @@ describe('LogsFiltersController', () => {
320320
});
321321

322322
it('should decode multiple api filters with OR', () => {
323-
// Note: The decodeQueryFilters processes filters sequentially and overwrites
324-
// So with "api:api-1 OR api:api-2", it processes api:api-1 first (sets to ['api-1']),
325-
// then processes api:api-2 (sets to ['api-2']), overwriting the first
326-
// This is actually a limitation of the current implementation
323+
// flatMap splits OR conditions, so each filter is processed separately
324+
// Both values should be accumulated in the array
327325
const query = 'api:api-1 OR api:api-2';
328326
controller['decodeQueryFilters'](query);
329327

330-
// Only the last one will remain due to overwriting behavior
331-
expect(controller.filters.api).toEqual(['api-2']);
328+
// Both values should be accumulated
329+
expect(controller.filters.api).toEqual(['api-1', 'api-2']);
332330
});
333331

334332
it('should decode application filter', () => {
@@ -384,8 +382,8 @@ describe('LogsFiltersController', () => {
384382
controller.filters.status = [];
385383
controller['decodeQueryFilters'](query);
386384

387-
// status uses push(v) where v is an array, so it becomes [[...]]
388-
expect(controller.filters.status).toEqual([['200']]);
385+
// status now correctly pushes string values, not nested arrays
386+
expect(controller.filters.status).toEqual(['200']);
389387
});
390388

391389
it('should decode response-time filter', () => {

gravitee-apim-console-webui/src/components/logs/logs-filters.controller.ts

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,16 @@ class LogsFiltersController {
239239
for (let i = 0; i < filters.length; i++) {
240240
const filter = filters[i].replace(/[()]/g, '');
241241
const k = filter.split(':')[0].trim();
242-
const v = filter
243-
.substring(filter.indexOf(':') + 1)
244-
.split('OR')
245-
.map((x) => x.trim());
242+
const v = filter.substring(filter.indexOf(':') + 1).trim();
246243
switch (k) {
247244
case 'api':
248-
this.filters.api = v;
245+
this.filters.api.push(v);
249246
break;
250247
case 'application':
251-
this.filters.application = v;
248+
this.filters.application.push(v);
252249
break;
253250
case 'path': {
254-
const value = v[0].replace(/\\"/g, '');
251+
const value = v.replace(/\\"/g, '');
255252
if (this.api) {
256253
this.filters.uri = this.api.proxy.virtual_hosts[0].path + value;
257254
} else {
@@ -260,46 +257,74 @@ class LogsFiltersController {
260257
break;
261258
}
262259
case 'uri':
263-
this.filters.uri = v[0].replace(/\*|\\\\/g, '');
260+
this.filters.uri = v.replace(/\*|\\\\/g, '');
264261
break;
265262
case 'plan':
266-
this.filters.plan = v;
263+
// Initialize as array if not already, then push the value
264+
if (!Array.isArray(this.filters.plan)) {
265+
this.filters.plan = [];
266+
}
267+
this.filters.plan.push(v);
267268
break;
268269
case 'response-time':
269-
this.filters.responseTime = v;
270+
// Initialize as array if not already, then push the value
271+
if (!Array.isArray(this.filters.responseTime)) {
272+
this.filters.responseTime = [];
273+
}
274+
this.filters.responseTime.push(v);
270275
break;
271276
case 'method':
272-
this.filters.method = v;
277+
// Initialize as array if not already, then push the value
278+
if (!Array.isArray(this.filters.method)) {
279+
this.filters.method = [];
280+
}
281+
this.filters.method.push(v);
273282
break;
274283
case 'status':
275284
this.filters.status.push(v);
276285
break;
277286
case '_id':
278-
this.filters.id = v[0];
287+
this.filters.id = v;
279288
break;
280289
case 'transaction':
281-
this.filters.transaction = v[0];
290+
this.filters.transaction = v;
282291
break;
283292
case 'tenant':
284-
this.filters.tenant = v;
293+
// Initialize as array if not already, then push the value
294+
if (!Array.isArray(this.filters.tenant)) {
295+
this.filters.tenant = [];
296+
}
297+
this.filters.tenant.push(v);
285298
break;
286299
case '_exists_':
287-
this.filters._exists_ = v;
300+
// Initialize as array if not already, then push the value
301+
if (!Array.isArray(this.filters._exists_)) {
302+
this.filters._exists_ = [];
303+
}
304+
this.filters._exists_.push(v);
288305
break;
289306
case '!_exists_':
290-
this.filters['!_exists_'] = v;
307+
// Initialize as array if not already, then push the value
308+
if (!Array.isArray(this.filters['!_exists_'])) {
309+
this.filters['!_exists_'] = [];
310+
}
311+
this.filters['!_exists_'].push(v);
291312
break;
292313
case 'body':
293-
this.filters.body = v[0].replace(/^\*(.*)\*$/g, '$1');
314+
this.filters.body = v.replace(/^\*(.*)\*$/g, '$1');
294315
break;
295316
case 'endpoint':
296-
this.filters.endpoint = v[0].replace(/\*|\\\\/g, '');
317+
this.filters.endpoint = v.replace(/\*|\\\\/g, '');
297318
break;
298319
case 'remote-address':
299-
this.filters['remote-address'] = v;
320+
// Initialize as array if not already, then push the value
321+
if (!Array.isArray(this.filters['remote-address'])) {
322+
this.filters['remote-address'] = [];
323+
}
324+
this.filters['remote-address'].push(v);
300325
break;
301326
case 'host':
302-
this.filters.host = v[0].replace(/\\"/g, '');
327+
this.filters.host = v.replace(/\\"/g, '');
303328
break;
304329
default:
305330
this.$log.error('unknown filter: ', k);

gravitee-apim-console-webui/src/components/logs/search-and-select/search-and-select.controller.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,49 @@ export class SearchAndSelectController {
5959
}
6060

6161
async $onInit() {
62+
// Normalize selectModel if it has nested arrays (fix for decodeQueryFilters bug)
63+
// Check if any nested arrays exist before flattening for better performance
64+
if (this.selectModel && Array.isArray(this.selectModel) && this.selectModel.some(Array.isArray)) {
65+
this.selectModel = this.flattenArray(this.selectModel);
66+
}
67+
6268
if (this.init) {
6369
const options = await this.init();
6470
this.selector.updateOptions(options);
6571
}
6672
this.select();
6773
}
6874

75+
/**
76+
* Recursively flattens nested arrays
77+
* Example: [[1], [2]] -> [1, 2]
78+
*/
79+
private flattenArray(arr: any[]): string[] {
80+
const result: string[] = [];
81+
for (const item of arr) {
82+
if (Array.isArray(item)) {
83+
result.push(...this.flattenArray(item));
84+
} else if (item !== null && item !== undefined) {
85+
result.push(item);
86+
}
87+
}
88+
return result;
89+
}
90+
6991
async onSearch() {
7092
const options = await this.search({ term: this.searchTerm });
7193
this.selector.updateOptions(options);
7294
}
7395

7496
select() {
75-
this.selector.updateSelection(this.selectModel, () => this.onSearch());
97+
// Normalize selectModel before using it (defensive check)
98+
// Only flatten if nested arrays are detected for better performance
99+
let normalizedModel = this.selectModel || [];
100+
if (Array.isArray(normalizedModel) && normalizedModel.some(Array.isArray)) {
101+
normalizedModel = this.flattenArray(normalizedModel);
102+
}
103+
104+
this.selector.updateSelection(normalizedModel, () => this.onSearch());
76105
this.onSelect({ selection: this.selection });
77106
}
78107

gravitee-apim-console-webui/src/components/logs/search-and-select/search-and-select.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
data-md-container-class="selectdemoSelectHeader"
2222
md-on-open="$ctrl.onSearch()"
2323
multiple
24-
ng-change="$ctrl.select(item)"
24+
ng-change="$ctrl.select()"
2525
>
2626
<md-select-header class="demo-select-header">
2727
<input

0 commit comments

Comments
 (0)