Skip to content

Commit 2b430f5

Browse files
authored
Merge branch 'main' into table-row-border-style
2 parents fa67503 + 3bc4a6e commit 2b430f5

File tree

19 files changed

+161
-42
lines changed

19 files changed

+161
-42
lines changed

projects/components/src/filtering/filter-bar/filter-chip/filter-chip.service.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
tryParseStringForAttribute
1414
} from '../../filter/parser/parsed-filter';
1515
import { AbstractFilterParser } from '../../filter/parser/types/abstract-filter-parser';
16+
import { FilterValue } from './../../filter/filter';
1617

1718
@Injectable({
1819
providedIn: 'root'
@@ -61,7 +62,7 @@ export class FilterChipService {
6162

6263
private buildIncompleteFiltersForAttribute(
6364
text: string,
64-
filterBuilder: AbstractFilterBuilder<unknown>,
65+
filterBuilder: AbstractFilterBuilder<FilterValue>,
6566
attributeExpression: FilterAttributeExpression
6667
): IncompleteFilter[] {
6768
const topLevelOperatorFilters = filterBuilder.supportedTopLevelOperators().map(operator => ({
@@ -95,8 +96,8 @@ export class FilterChipService {
9596
}
9697

9798
private buildIncompleteFilterForAttributeAndOperator(
98-
filterBuilder: AbstractFilterBuilder<unknown>,
99-
filterParser: AbstractFilterParser<unknown>,
99+
filterBuilder: AbstractFilterBuilder<FilterValue>,
100+
filterParser: AbstractFilterParser<FilterValue>,
100101
splitFilter: SplitFilter<FilterOperator>,
101102
text: string
102103
): IncompleteFilter {
@@ -132,7 +133,7 @@ export class FilterChipService {
132133
}
133134

134135
private buildIncompleteFilterForPartialAttributeMatch(
135-
filterBuilder: AbstractFilterBuilder<unknown>,
136+
filterBuilder: AbstractFilterBuilder<FilterValue>,
136137
attribute: FilterAttribute
137138
): IncompleteFilter {
138139
return {

projects/components/src/filtering/filter-button/filter-button.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Out
22
import { IconType } from '@hypertrace/assets-library';
33
import { IconSize } from '../../icon/icon-size';
44
import { FilterBuilderLookupService } from '../filter/builder/filter-builder-lookup.service';
5-
import { Filter } from '../filter/filter';
5+
import { Filter, FilterValue } from '../filter/filter';
66
import { FilterAttribute } from '../filter/filter-attribute';
77
import { FilterUrlService } from '../filter/filter-url.service';
88

@@ -45,7 +45,7 @@ export class FilterButtonComponent implements OnChanges {
4545
public attribute?: FilterAttribute;
4646

4747
@Input()
48-
public value?: unknown;
48+
public value?: FilterValue;
4949

5050
@Output()
5151
public readonly popoverOpen: EventEmitter<boolean> = new EventEmitter();

projects/components/src/filtering/filter-modal/in-filter-modal.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { sortUnknown } from '@hypertrace/common';
33
import { ButtonRole } from '../../button/button';
44
import { ModalRef, MODAL_DATA } from '../../modal/modal';
55
import { FilterBuilderLookupService } from '../filter/builder/filter-builder-lookup.service';
6-
import { IncompleteFilter } from '../filter/filter';
6+
import { FilterValue, IncompleteFilter } from '../filter/filter';
77
import { FilterAttribute } from '../filter/filter-attribute';
88
import { FilterOperator } from '../filter/filter-operators';
99
import { FilterUrlService } from '../filter/filter-url.service';
@@ -43,7 +43,7 @@ import { FilterUrlService } from '../filter/filter-url.service';
4343
})
4444
export class InFilterModalComponent {
4545
public isSupported: boolean = false;
46-
public selected: Set<unknown> = new Set<unknown>();
46+
public selected: Set<FilterValue> = new Set<FilterValue>();
4747

4848
public constructor(
4949
private readonly modalRef: ModalRef<never>,
@@ -91,7 +91,7 @@ export class InFilterModalComponent {
9191
this.modalRef.close();
9292
}
9393

94-
public onChecked(checked: boolean, value: unknown): void {
94+
public onChecked(checked: boolean, value: FilterValue): void {
9595
checked ? this.selected.add(value) : this.selected.delete(value);
9696
}
9797
}

projects/components/src/filtering/filter/builder/filter-builder-lookup.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { assertUnreachable } from '@hypertrace/common';
3+
import { FilterValue } from '../filter';
34
import { FilterAttributeType } from '../filter-attribute-type';
45
import { AbstractFilterBuilder } from './types/abstract-filter-builder';
56
import { BooleanFilterBuilder } from './types/boolean-filter-builder';
@@ -11,7 +12,7 @@ import { StringMapFilterBuilder } from './types/string-map-filter-builder';
1112
providedIn: 'root'
1213
})
1314
export class FilterBuilderLookupService {
14-
public lookup(type: FilterAttributeType): AbstractFilterBuilder<unknown> {
15+
public lookup(type: FilterAttributeType): AbstractFilterBuilder<FilterValue> {
1516
switch (type) {
1617
case FilterAttributeType.Boolean:
1718
return new BooleanFilterBuilder();

projects/components/src/filtering/filter/builder/types/abstract-filter-builder.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { collapseWhitespace } from '@hypertrace/common';
22
import { isEmpty } from 'lodash-es';
3-
import { Filter } from '../../filter';
3+
import { Filter, FilterValue, IncompleteFilter } from '../../filter';
44
import { FilterAttribute } from '../../filter-attribute';
55
import { FilterAttributeType } from '../../filter-attribute-type';
66
import { MAP_LHS_DELIMITER } from '../../filter-delimiters';
77
import { FilterOperator, toUrlFilterOperator } from '../../filter-operators';
88
import { FilterAttributeExpression } from '../../parser/parsed-filter';
99

10-
export abstract class AbstractFilterBuilder<TValue> {
10+
export abstract class AbstractFilterBuilder<TValue extends FilterValue> {
1111
public abstract supportedAttributeType(): FilterAttributeType;
1212

1313
public abstract supportedSubpathOperators(): FilterOperator[];
@@ -47,6 +47,30 @@ export abstract class AbstractFilterBuilder<TValue> {
4747
};
4848
}
4949

50+
public buildPartialFilter(
51+
attribute: FilterAttribute,
52+
operator?: FilterOperator,
53+
value?: TValue,
54+
subpath?: string
55+
): IncompleteFilter<TValue> {
56+
if (
57+
operator !== undefined &&
58+
((isEmpty(subpath) && !this.supportedTopLevelOperators().includes(operator)) ||
59+
(!isEmpty(subpath) && !this.supportedSubpathOperators().includes(operator)))
60+
) {
61+
throw Error(`Operator '${operator}' not supported for filter attribute type '${attribute.type}'`);
62+
}
63+
64+
return {
65+
metadata: attribute,
66+
field: attribute.name,
67+
subpath: subpath,
68+
operator: operator,
69+
value: value,
70+
userString: this.buildUserFilterString(attribute, subpath, operator, value)
71+
};
72+
}
73+
5074
public buildUserFilterString(
5175
attribute: FilterAttribute,
5276
subpath?: string,

projects/components/src/filtering/filter/filter-url.service.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { NavigationService } from '@hypertrace/common';
3+
import { remove } from 'lodash-es';
34
import { Observable } from 'rxjs';
45
import { map } from 'rxjs/operators';
56
import { FilterBuilderLookupService } from './builder/filter-builder-lookup.service';
@@ -25,6 +26,21 @@ export class FilterUrlService {
2526
return this.navigationService.navigation$.pipe(map(() => this.getUrlFilters(attributes)));
2627
}
2728

29+
public getUrlFiltersForAttributes(attributes: FilterAttribute[]): (Filter | IncompleteFilter)[] {
30+
const urlFilters = this.getUrlFilters(attributes);
31+
32+
return attributes.map(attribute => {
33+
const match = urlFilters.find(f => f.field === attribute.name);
34+
if (match !== undefined) {
35+
remove(urlFilters, f => f === match);
36+
37+
return match;
38+
}
39+
40+
return this.filterBuilderLookupService.lookup(attribute.type).buildPartialFilter(attribute);
41+
});
42+
}
43+
2844
public getUrlFilters(attributes: FilterAttribute[]): Filter[] {
2945
return this.navigationService
3046
.getAllValuesForQueryParameter(FilterUrlService.FILTER_QUERY_PARAM)
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
1+
import { Dictionary } from '@hypertrace/common';
12
import { FilterAttribute } from './filter-attribute';
23
import { FilterOperator, incompatibleOperators } from './filter-operators';
34

4-
export interface Filter<TValue = unknown> extends IncompleteFilter {
5+
export interface Filter<TValue extends FilterValue = FilterValue> extends IncompleteFilter {
56
operator: FilterOperator;
67
value: TValue;
78
urlString: string;
89
}
910

10-
export interface IncompleteFilter<TValue = unknown> extends FieldFilter<TValue> {
11+
export interface IncompleteFilter<TValue extends FilterValue = FilterValue> extends FieldFilter<TValue> {
1112
metadata: FilterAttribute;
1213
userString: string;
1314
}
1415

15-
export interface FieldFilter<TValue = unknown> {
16+
export interface FieldFilter<TValue extends FilterValue = FilterValue> {
1617
field: string;
1718
subpath?: string;
1819
operator?: FilterOperator;
1920
value?: TValue;
2021
}
2122

23+
export type FilterValue = string | number | boolean | Date | Dictionary<FilterValue> | FilterValue[];
24+
2225
export const areCompatibleFilters = (f1: Filter, f2: Filter) =>
2326
f1.field !== f2.field || f1.subpath !== f2.subpath || !incompatibleOperators(f1.operator).includes(f2.operator);

projects/components/src/filtering/filter/parser/filter-parser-lookup.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { assertUnreachable } from '@hypertrace/common';
3+
import { FilterValue } from '../filter';
34
import { FilterAttributeType } from '../filter-attribute-type';
45
import { FilterOperator } from '../filter-operators';
56
import { AbstractFilterParser } from './types/abstract-filter-parser';
@@ -14,7 +15,7 @@ export class FilterParserLookupService {
1415
// TODO remove the separate parsers entirely.
1516
// There's next to no logic left in them, and they duplicate (incorrectly) supported operators,
1617
// Which should be based on attribute type (as defined in filter builders)
17-
public lookup(operator: FilterOperator): AbstractFilterParser<unknown> {
18+
public lookup(operator: FilterOperator): AbstractFilterParser<FilterValue> {
1819
switch (operator) {
1920
case FilterOperator.Equals:
2021
case FilterOperator.NotEquals:

projects/components/src/table/table-api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Dictionary } from '@hypertrace/common';
22
import { Observable } from 'rxjs';
3-
import { FieldFilter } from '../filtering/filter/filter';
3+
import { FieldFilter, FilterValue } from '../filtering/filter/filter';
44
import { FilterOperator } from '../filtering/filter/filter-operators';
55
import { TableCellAlignmentType } from './cells/types/table-cell-alignment-type';
66

@@ -60,7 +60,7 @@ export interface RowStateChange {
6060

6161
export interface TableFilter extends FieldFilter {
6262
operator: FilterOperator;
63-
value: unknown;
63+
value: FilterValue;
6464
}
6565

6666
export const enum TableSortDirection {

projects/components/src/table/table.component.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ export class TableComponent
308308
@Output()
309309
public readonly columnConfigsChange: EventEmitter<TableColumnConfig[]> = new EventEmitter<TableColumnConfig[]>();
310310

311+
@Output()
312+
public readonly sortChange: EventEmitter<SortedColumn> = new EventEmitter<SortedColumn>();
313+
311314
@ViewChild(PaginatorComponent)
312315
public paginator?: PaginatorComponent;
313316

@@ -538,10 +541,12 @@ export class TableComponent
538541

539542
public onSortChange(direction: TableSortDirection, columnConfig: TableColumnConfigExtended): void {
540543
if (TableCdkColumnUtil.isColumnSortable(columnConfig)) {
541-
this.updateSort({
544+
const sortedColumn: SortedColumn = {
542545
column: columnConfig,
543546
direction: direction
544-
});
547+
};
548+
this.sortChange.emit(sortedColumn);
549+
this.updateSort(sortedColumn);
545550
}
546551

547552
if (this.syncWithUrl) {
@@ -776,7 +781,7 @@ export class TableComponent
776781
}
777782
}
778783

779-
interface SortedColumn {
784+
export interface SortedColumn {
780785
column: TableColumnConfigExtended;
781786
direction?: TableSortDirection;
782787
}

0 commit comments

Comments
 (0)