Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ describe('LogsFiltersController', () => {

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

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

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

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

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

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

it('should decode response-time filter', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,19 +239,16 @@ class LogsFiltersController {
for (let i = 0; i < filters.length; i++) {
const filter = filters[i].replace(/[()]/g, '');
const k = filter.split(':')[0].trim();
const v = filter
.substring(filter.indexOf(':') + 1)
.split('OR')
.map((x) => x.trim());
const v = filter.substring(filter.indexOf(':') + 1).trim();
switch (k) {
case 'api':
this.filters.api = v;
this.filters.api.push(v);
break;
case 'application':
this.filters.application = v;
this.filters.application.push(v);
break;
case 'path': {
const value = v[0].replace(/\\"/g, '');
const value = v.replace(/\\"/g, '');
if (this.api) {
this.filters.uri = this.api.proxy.virtual_hosts[0].path + value;
} else {
Expand All @@ -260,46 +257,74 @@ class LogsFiltersController {
break;
}
case 'uri':
this.filters.uri = v[0].replace(/\*|\\\\/g, '');
this.filters.uri = v.replace(/\*|\\\\/g, '');
break;
case 'plan':
this.filters.plan = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters.plan)) {
this.filters.plan = [];
}
this.filters.plan.push(v);
break;
case 'response-time':
this.filters.responseTime = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters.responseTime)) {
this.filters.responseTime = [];
}
this.filters.responseTime.push(v);
break;
case 'method':
this.filters.method = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters.method)) {
this.filters.method = [];
}
this.filters.method.push(v);
break;
case 'status':
this.filters.status.push(v);
break;
case '_id':
this.filters.id = v[0];
this.filters.id = v;
break;
case 'transaction':
this.filters.transaction = v[0];
this.filters.transaction = v;
break;
case 'tenant':
this.filters.tenant = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters.tenant)) {
this.filters.tenant = [];
}
this.filters.tenant.push(v);
break;
case '_exists_':
this.filters._exists_ = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters._exists_)) {
this.filters._exists_ = [];
}
this.filters._exists_.push(v);
break;
case '!_exists_':
this.filters['!_exists_'] = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters['!_exists_'])) {
this.filters['!_exists_'] = [];
}
this.filters['!_exists_'].push(v);
break;
case 'body':
this.filters.body = v[0].replace(/^\*(.*)\*$/g, '$1');
this.filters.body = v.replace(/^\*(.*)\*$/g, '$1');
break;
case 'endpoint':
this.filters.endpoint = v[0].replace(/\*|\\\\/g, '');
this.filters.endpoint = v.replace(/\*|\\\\/g, '');
break;
case 'remote-address':
this.filters['remote-address'] = v;
// Initialize as array if not already, then push the value
if (!Array.isArray(this.filters['remote-address'])) {
this.filters['remote-address'] = [];
}
this.filters['remote-address'].push(v);
break;
case 'host':
this.filters.host = v[0].replace(/\\"/g, '');
this.filters.host = v.replace(/\\"/g, '');
break;
default:
this.$log.error('unknown filter: ', k);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,49 @@ export class SearchAndSelectController {
}

async $onInit() {
// Normalize selectModel if it has nested arrays (fix for decodeQueryFilters bug)
// Check if any nested arrays exist before flattening for better performance
if (this.selectModel && Array.isArray(this.selectModel) && this.selectModel.some(Array.isArray)) {
this.selectModel = this.flattenArray(this.selectModel);
}

if (this.init) {
const options = await this.init();
this.selector.updateOptions(options);
}
this.select();
}

/**
* Recursively flattens nested arrays
* Example: [[1], [2]] -> [1, 2]
*/
private flattenArray(arr: any[]): string[] {
const result: string[] = [];
for (const item of arr) {
if (Array.isArray(item)) {
result.push(...this.flattenArray(item));
} else if (item !== null && item !== undefined) {
result.push(item);
}
}
return result;
}

async onSearch() {
const options = await this.search({ term: this.searchTerm });
this.selector.updateOptions(options);
}

select() {
this.selector.updateSelection(this.selectModel, () => this.onSearch());
// Normalize selectModel before using it (defensive check)
// Only flatten if nested arrays are detected for better performance
let normalizedModel = this.selectModel || [];
if (Array.isArray(normalizedModel) && normalizedModel.some(Array.isArray)) {
normalizedModel = this.flattenArray(normalizedModel);
}

this.selector.updateSelection(normalizedModel, () => this.onSearch());
this.onSelect({ selection: this.selection });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
data-md-container-class="selectdemoSelectHeader"
md-on-open="$ctrl.onSearch()"
multiple
ng-change="$ctrl.select(item)"
ng-change="$ctrl.select()"
>
<md-select-header class="demo-select-header">
<input
Expand Down