Skip to content

Commit

Permalink
feat: add column config local storage support to table (#2417)
Browse files Browse the repository at this point in the history
  • Loading branch information
arjunlalb authored Sep 21, 2023
1 parent 24f49c6 commit df5b00c
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 90 deletions.
18 changes: 18 additions & 0 deletions projects/common/src/preference/preference.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ export class PreferenceService {
);
}

/**
* Returns the current storage value if defined, else the default value.
*/
public getOnce<T extends PreferenceValue>(
key: PreferenceKey,
defaultValue?: T,
type: StorageType = PreferenceService.DEFAULT_STORAGE_TYPE
): T {
const storedValue = this.preferenceStorage(type).get(this.asStorageKey(key));
const value = this.fromStorageValue<T>(storedValue) ?? defaultValue;

if (value === undefined) {
throw Error(`No value found or default provided for preferenceKey: ${key}`);
}

return value;
}

public set(
key: PreferenceKey,
value: PreferenceValue,
Expand Down
181 changes: 173 additions & 8 deletions projects/components/src/table/table.component.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* eslint-disable max-lines */
import { fakeAsync, flush } from '@angular/core/testing';
import { ActivatedRoute, convertToParamMap } from '@angular/router';
import { DomElementMeasurerService, NavigationService } from '@hypertrace/common';
import {
DomElementMeasurerService,
NavigationService,
PreferenceService,
PreferenceValue,
StorageType
} from '@hypertrace/common';
import { runFakeRxjs } from '@hypertrace/test-utils';
import { createHostFactory, mockProvider } from '@ngneat/spectator/jest';
import { MockComponent } from 'ng-mocks';
Expand All @@ -20,6 +26,7 @@ import { TableColumnConfigExtended, TableService } from './table.service';
import { ModalService } from '../modal/modal.service';

describe('Table component', () => {
let localStorage: PreferenceValue = { columns: [] };
// TODO remove builders once table stops mutating inputs
const buildData = () => [
{
Expand Down Expand Up @@ -56,7 +63,6 @@ describe('Table component', () => {
imports: [LetAsyncModule],
providers: [
mockProvider(NavigationService),
mockProvider(ActivatedRoute),
mockProvider(ActivatedRoute, {
queryParamMap: EMPTY
}),
Expand All @@ -75,6 +81,10 @@ describe('Table component', () => {
}),
mockProvider(ModalService, {
createModal: jest.fn().mockReturnValue({ closed$: of([]) })
}),
mockProvider(PreferenceService, {
getOnce: jest.fn().mockReturnValue(localStorage),
set: (_: unknown, value: PreferenceValue) => (localStorage = value)
})
],
declarations: [MockComponent(PaginatorComponent), MockComponent(SearchBoxComponent)],
Expand Down Expand Up @@ -256,12 +266,15 @@ describe('Table component', () => {
});
spectator.tick();

expect(spectator.component.columnConfigs![0]).toEqual(
expect.objectContaining({
sort: TableSortDirection.Ascending,
id: 'firstId'
})
);
runFakeRxjs(({ expectObservable }) => {
expectObservable(spectator.component.columnConfigs$.pipe(map(columns => columns[0]))).toBe('x', {
x: expect.objectContaining({
sort: TableSortDirection.Ascending,
id: 'firstId'
})
});
});
flush();
}));

test('does not alter the URL on sorting if syncWithUrl false', fakeAsync(() => {
Expand Down Expand Up @@ -580,5 +593,157 @@ describe('Table component', () => {
]
});
});
flush();
}));

test('saved preferences should be accounted for while building column configs', fakeAsync(() => {
const columns = buildColumns();
let localStorageOverride: PreferenceValue = {
columns: [
{
id: 'firstId',
visible: false
},
{ id: 'secondId', visible: true }
]
};
const spectator = createHost(
'<ht-table id="test-table" [columnConfigs]="columnConfigs" [data]="data" [selectionMode]="selectionMode" [mode]="mode"></ht-table>',
{
hostProps: {
columnConfigs: columns,
data: buildData(),
selectionMode: TableSelectionMode.Single,
mode: TableMode.Flat
},
providers: [
mockProvider(PreferenceService, {
getOnce: jest.fn().mockReturnValue(localStorageOverride),
set: jest.fn().mockImplementation((_key: string, value: PreferenceValue, _storageType: StorageType) => {
localStorageOverride = value;
})
})
]
}
);
spectator.tick();

runFakeRxjs(({ expectObservable }) => {
expectObservable(spectator.component.columnConfigs$).toBe('x', {
x: [
expect.objectContaining({
id: 'firstId',
visible: false
}),
expect.objectContaining({
id: 'secondId',
visible: true
})
]
});
});

expect(spectator.inject(PreferenceService).getOnce).toHaveBeenLastCalledWith(
'test-table',
{ columns: [] },
StorageType.Local
);
flush();
}));

test('should save user preferences for columns when a column is hidden', fakeAsync(() => {
const columns = buildColumns();
let localStorageOverride: PreferenceValue = {
columns: []
};
const spectator = createHost(
'<ht-table id="test-table" [columnConfigs]="columnConfigs" [data]="data" [selectionMode]="selectionMode" [mode]="mode"></ht-table>',
{
hostProps: {
columnConfigs: columns,
data: buildData(),
selectionMode: TableSelectionMode.Single,
mode: TableMode.Flat
},
providers: [
mockProvider(PreferenceService, {
getOnce: jest.fn().mockReturnValue(localStorageOverride),
set: jest.fn().mockImplementation((_key: string, value: PreferenceValue, _storageType: StorageType) => {
localStorageOverride = value;
})
})
]
}
);
spectator.component.onHideColumn({ ...columns[0] });
spectator.tick();
expect(spectator.inject(PreferenceService).set).toHaveBeenCalledWith(
'test-table',
{
columns: expect.arrayContaining([
{
id: 'firstId',
visible: false
},
{
id: 'secondId',
visible: true
}
])
},
StorageType.Local
);

flush();
}));

test('should save user preferences for columns when columns are edited', fakeAsync(() => {
const columns = buildColumns();
let localStorageOverride: PreferenceValue = {
columns: []
};
const spectator = createHost(
'<ht-table id="test-table" [columnConfigs]="columnConfigs" [data]="data" [selectionMode]="selectionMode" [mode]="mode"></ht-table>',
{
hostProps: {
columnConfigs: columns,
data: buildData(),
selectionMode: TableSelectionMode.Single,
mode: TableMode.Flat
},
providers: [
mockProvider(PreferenceService, {
getOnce: jest.fn().mockReturnValue(localStorageOverride),
set: jest.fn().mockImplementation((_key: string, value: PreferenceValue, _storageType: StorageType) => {
localStorageOverride = value;
})
}),
mockProvider(ModalService, {
createModal: jest.fn().mockReturnValue({ closed$: of([columns[0], { ...columns[1], visible: false }]) })
})
]
}
);
spectator.tick();
spectator.component.showEditColumnsModal();
spectator.tick();
expect(spectator.inject(PreferenceService).set).toHaveBeenCalledWith(
'test-table',
{
columns: expect.arrayContaining([
{
id: 'firstId',
visible: true
},
{
id: 'secondId',
visible: false
}
])
},
StorageType.Local
);

flush();
}));
});
Loading

0 comments on commit df5b00c

Please sign in to comment.