Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ describe('Table Controls component', () => {
[searchEnabled]="searchEnabled"
[searchPlaceholder]="searchPlaceholder"
[filterItems]="filterItems"
[modeItems]="modeItems"
[viewItems]="viewItems"
(searchChange)="searchChange($event)"
(filterChange)="filterChange($event)"
(modeChange)="modeChange($event)"
(viewChange)="viewChange($event)"
>
</ht-table-controls>
`
Expand Down Expand Up @@ -103,10 +103,10 @@ describe('Table Controls component', () => {
expect(onChangeSpy).toHaveBeenCalled();
});

test('should provide toggle group items for each mode', () => {
test('should provide toggle group items for each view', () => {
const spectator = createHost(undefined, {
hostProps: {
modeItems: [
viewItems: [
{
label: 'test1',
value: 'TEST1'
Expand All @@ -122,12 +122,12 @@ describe('Table Controls component', () => {
expect(spectator.query(ToggleGroupComponent)?.items?.length).toEqual(2);
});

test('should emit mode when selected', () => {
test('should emit view when selected', () => {
const onChangeSpy = jest.fn();

const spectator = createHost(undefined, {
hostProps: {
modeItems: [
viewItems: [
{
label: 'test1',
value: 'TEST1'
Expand All @@ -137,7 +137,7 @@ describe('Table Controls component', () => {
value: 'TEST2'
}
],
modeChange: onChangeSpy
viewChange: onChangeSpy
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { isEmpty } from 'lodash-es';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { ToggleItem } from '../../toggle-group/toggle-item';
import { TableMode } from '../table-api';
import { SelectChange, SelectFilter } from './table-controls-api';

@Component({
Expand Down Expand Up @@ -60,10 +59,10 @@ import { SelectChange, SelectFilter } from './table-controls-api';

<!-- Mode Toggle -->
<ht-toggle-group
*ngIf="this.modeToggleEnabled"
*ngIf="this.viewToggleEnabled"
class="control mode-toggle-group"
[items]="this.modeItems"
[activeItem]="this.activeModeItem"
[items]="this.viewItems"
[activeItem]="this.activeViewItem"
(activeItemChange)="this.onModeChange($event)"
></ht-toggle-group>
</div>
Expand All @@ -86,10 +85,10 @@ export class TableControlsComponent implements OnChanges {
public activeFilterItem?: ToggleItem;

@Input()
public modeItems?: ToggleItem[] = [];
public viewItems?: ToggleItem[] = [];

@Input()
public activeModeItem?: ToggleItem;
public activeViewItem?: ToggleItem;

// Checkbox filter
@Input()
Expand All @@ -111,10 +110,10 @@ export class TableControlsComponent implements OnChanges {
public readonly filterChange: EventEmitter<ToggleItem> = new EventEmitter<ToggleItem>();

@Output()
public readonly modeChange: EventEmitter<TableMode> = new EventEmitter<TableMode>();
public readonly viewChange: EventEmitter<string> = new EventEmitter<string>();

public get modeToggleEnabled(): boolean {
return !!this.modeItems && this.modeItems.length > 0;
public get viewToggleEnabled(): boolean {
return !!this.viewItems && this.viewItems.length > 0;
}

public get checkboxEnabled(): boolean {
Expand All @@ -126,7 +125,7 @@ export class TableControlsComponent implements OnChanges {
}

public get anyControlsEnabled(): boolean {
return this.modeToggleEnabled || this.checkboxEnabled || this.filterItemsEnabled || !!this.searchEnabled;
return this.viewToggleEnabled || this.checkboxEnabled || this.filterItemsEnabled || !!this.searchEnabled;
}

private readonly searchDebounceSubject: Subject<string> = new Subject<string>();
Expand All @@ -142,8 +141,8 @@ export class TableControlsComponent implements OnChanges {
this.setActiveFilterItem();
}

if (changes.modeItems) {
this.setActiveModeItem();
if (changes.viewItems) {
this.setActiveViewItem();
}
}

Expand All @@ -153,9 +152,9 @@ export class TableControlsComponent implements OnChanges {
}
}

private setActiveModeItem(): void {
if (this.modeItems !== undefined) {
this.activeModeItem = this.modeItems.find(item => item === this.activeModeItem) ?? this.modeItems[0];
private setActiveViewItem(): void {
if (this.viewItems !== undefined) {
this.activeViewItem = this.viewItems.find(item => item === this.activeViewItem) ?? this.viewItems[0];
}
}

Expand All @@ -174,7 +173,7 @@ export class TableControlsComponent implements OnChanges {
this.searchDebounceSubject.next(text);
}

public onModeChange(item: ToggleItem<TableMode>): void {
this.modeChange.emit(item.value);
public onModeChange(item: ToggleItem<string>): void {
this.viewChange.emit(item.value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ export abstract class TableWidgetBaseModel extends BaseModel {
return TableSelectionMode.Single;
}

public setMode(_mode: TableMode): void {
public setView(_view: string): void {
// No-op here, but can be overridden
return;
}

public getModeOptions(): TableMode[] {
public getViewOptions(): string[] {
// No-op here, but can be overridden
return [];
}
Expand All @@ -152,6 +152,10 @@ export abstract class TableWidgetBaseModel extends BaseModel {
return this.filterOptions;
}

public getSearchAttribute(): string | undefined {
return this.searchAttribute;
}

public getCheckboxFilterOption(): TableWidgetCheckboxFilterModel | undefined {
return this.checkboxFilterOption;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
TableColumnConfig,
TableDataSource,
TableFilter,
TableMode,
TableRow,
TableSelectionMode,
TableStyle,
Expand All @@ -32,14 +31,14 @@ import { filter, first, map, pairwise, share, startWith, switchMap, tap } from '
import { AttributeMetadata, toFilterAttributeType } from '../../../graphql/model/metadata/attribute-metadata';
import { MetadataService } from '../../../services/metadata/metadata.service';
import { InteractionHandler } from '../../interaction/interaction-handler';
import { ModeToggleTableWidgetModel } from './mode-toggle-table-widget.model';
import { TableWidgetBaseModel } from './table-widget-base.model';
import { SpecificationBackedTableColumnDef } from './table-widget-column.model';
import { TableWidgetFilterModel } from './table-widget-filter-model';
import { TableWidgetViewToggleModel } from './table-widget-view-toggle.model';
import { TableWidgetModel } from './table-widget.model';

@Renderer({ modelClass: TableWidgetModel })
@Renderer({ modelClass: ModeToggleTableWidgetModel })
@Renderer({ modelClass: TableWidgetViewToggleModel })
@Component({
selector: 'ht-table-widget-renderer',
styleUrls: ['./table-widget-renderer.component.scss'],
Expand All @@ -53,17 +52,17 @@ import { TableWidgetModel } from './table-widget.model';
<div class="table-content-container">
<ht-table-controls
class="table-controls"
[searchEnabled]="!!this.api.model.searchAttribute"
[searchEnabled]="!!this.api.model.getSearchAttribute()"
[selectFilterItems]="this.selectFilterItems$ | async"
[filterItems]="this.filterItems"
[modeItems]="this.modeItems"
[viewItems]="this.viewItems"
[checkboxLabel]="this.model.getCheckboxFilterOption()?.label"
[checkboxChecked]="this.model.getCheckboxFilterOption()?.checked"
(checkboxCheckedChange)="this.onCheckboxCheckedChange($event)"
(selectChange)="this.onSelectChange($event)"
(searchChange)="this.onSearchChange($event)"
(filterChange)="this.onFilterChange($event)"
(modeChange)="this.onModeChange($event)"
(viewChange)="this.onViewChange($event)"
>
</ht-table-controls>

Expand All @@ -72,7 +71,7 @@ import { TableWidgetModel } from './table-widget.model';
[ngClass]="{ 'header-margin': this.model.header?.topMargin }"
[columnConfigs]="this.columnConfigs$ | async"
[metadata]="this.metadata$ | async"
[mode]="this.activeMode"
[mode]="this.model.mode"
[selectionMode]="this.model.getSelectionMode()"
[display]="this.model.style"
[data]="this.data$ | async"
Expand All @@ -96,8 +95,7 @@ export class TableWidgetRendererComponent
extends WidgetRenderer<TableWidgetBaseModel, TableDataSource<TableRow> | undefined>
implements OnInit {
public filterItems: ToggleItem<TableWidgetFilterModel>[] = [];
public modeItems: ToggleItem<TableMode>[] = [];
public activeMode!: TableMode;
public viewItems: ToggleItem<string>[] = [];

public selectFilterItems$!: Observable<SelectFilter[]>;

Expand All @@ -124,8 +122,6 @@ export class TableWidgetRendererComponent
public ngOnInit(): void {
super.ngOnInit();

this.onModeChange(this.model.mode);

this.metadata$ = this.getScopeAttributes();
this.columnConfigs$ = (isNonEmptyString(this.model.id)
? this.preferenceService.get<TableColumnConfig[]>(this.model.id, [])
Expand All @@ -151,9 +147,9 @@ export class TableWidgetRendererComponent
value: filterOption
}));

this.modeItems = this.model.getModeOptions().map(modeOption => ({
label: capitalize(modeOption),
value: modeOption
this.viewItems = this.model.getViewOptions().map(viewOption => ({
label: capitalize(viewOption),
value: viewOption
}));

this.maybeEmitInitialCheckboxFilterChange();
Expand Down Expand Up @@ -321,16 +317,15 @@ export class TableWidgetRendererComponent

public onSearchChange(text: string): void {
const searchFilter: TableFilter = {
field: this.api.model.searchAttribute!,
field: this.api.model.getSearchAttribute()!,
operator: FilterOperator.Like,
value: text
};
this.searchFilterSubject.next([searchFilter]);
}

public onModeChange(mode: TableMode): void {
this.activeMode = mode;
this.model.setMode(mode);
public onViewChange(view: string): void {
this.model.setView(view);
this.columnConfigs$ = this.getColumnConfigs();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FilterOperator, TableFilter } from '@hypertrace/components';
import { Model, ModelApi, ModelProperty, STRING_PROPERTY } from '@hypertrace/hyperdash';
import { ModelInject, MODEL_API } from '@hypertrace/hyperdash-angular';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Model({
type: 'table-widget-select-filter',
Expand All @@ -26,7 +27,15 @@ export class TableWidgetSelectFilterModel {
protected readonly api!: ModelApi;

public getData(): Observable<PrimitiveValue[]> {
return this.api.getData<PrimitiveValue[]>();
return this.api.getData<PrimitiveValue[]>().pipe(
map(values => values.filter(value => !this.isEmpty(value))),
map(values => values.sort())
);
}

public isEmpty(value: unknown): boolean {
// Empty values can't be queried through filtering yet, so need to remove them so they don't appear in the dropdown
return value === undefined || value === null || value === '';
}

public getTableFilter(value: unknown): TableFilter {
Expand Down
Loading