@open-dcp/grid 0.0.0-stage → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +42 -0
- package/CLA.md +22 -0
- package/LICENSE +190 -0
- package/NOTICE.md +31 -0
- package/README.md +39 -3
- package/SECURITY.md +27 -0
- package/dist/GridService.d.ts +83 -0
- package/dist/GridService.js +410 -0
- package/dist/__tests__/GridServices.test.d.ts +1 -0
- package/dist/__tests__/GridServices.test.js +288 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/services/FilteringService.d.ts +34 -0
- package/dist/services/FilteringService.js +278 -0
- package/dist/services/FormattingService.d.ts +17 -0
- package/dist/services/FormattingService.js +179 -0
- package/dist/services/RowHeightService.d.ts +15 -0
- package/dist/services/RowHeightService.js +63 -0
- package/dist/services/SelectionService.d.ts +14 -0
- package/dist/services/SelectionService.js +55 -0
- package/dist/services/SortingService.d.ts +15 -0
- package/dist/services/SortingService.js +82 -0
- package/dist/services/__tests__/FilteringService.test.d.ts +1 -0
- package/dist/services/__tests__/FilteringService.test.js +140 -0
- package/dist/services/__tests__/FormattingService.test.d.ts +1 -0
- package/dist/services/__tests__/FormattingService.test.js +122 -0
- package/dist/types/grid.d.ts +71 -0
- package/dist/types/grid.js +1 -0
- package/dist/types/sorting.d.ts +8 -0
- package/dist/types/sorting.js +1 -0
- package/jest.config.js +16 -0
- package/package.json +43 -4
- package/reports/junit.xml +3 -0
- package/src/GridService.ts +561 -0
- package/src/__tests__/GridServices.test.ts +348 -0
- package/src/index.ts +17 -0
- package/src/services/FilteringService.ts +347 -0
- package/src/services/FormattingService.ts +205 -0
- package/src/services/RowHeightService.ts +81 -0
- package/src/services/SelectionService.ts +71 -0
- package/src/services/SortingService.ts +105 -0
- package/src/services/__tests__/FilteringService.test.ts +173 -0
- package/src/services/__tests__/FormattingService.test.ts +157 -0
- package/src/types/grid.ts +84 -0
- package/src/types/sorting.ts +9 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { GridService } from '../../GridService';
|
|
2
|
+
describe('FormattingService', () => {
|
|
3
|
+
let gridService;
|
|
4
|
+
let formattingService;
|
|
5
|
+
let mockColumns;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
mockColumns = [
|
|
8
|
+
{ key: 'id', label: 'ID', type: 'integer' },
|
|
9
|
+
{ key: 'name', label: 'Name', type: 'string' },
|
|
10
|
+
{ key: 'price', label: 'Price', type: 'number' },
|
|
11
|
+
{ key: 'created', label: 'Created', type: 'date' },
|
|
12
|
+
{ key: 'updated', label: 'Updated', type: 'datetime' },
|
|
13
|
+
{ key: 'duration', label: 'Duration', type: 'duration' },
|
|
14
|
+
];
|
|
15
|
+
gridService = new GridService([], mockColumns);
|
|
16
|
+
formattingService = gridService['formattingService'];
|
|
17
|
+
});
|
|
18
|
+
describe('applyFormattingToRow', () => {
|
|
19
|
+
it('should format a complete row with all column types', () => {
|
|
20
|
+
const row = {
|
|
21
|
+
id: { raw: '123', value: '123' },
|
|
22
|
+
name: { raw: 'Product', value: 'Product' },
|
|
23
|
+
price: { raw: '99.99', value: '99.99' },
|
|
24
|
+
created: { raw: '2024-01-15', value: '2024-01-15' },
|
|
25
|
+
updated: { raw: '2024-01-15T14:30:00Z', value: '2024-01-15T14:30:00Z' },
|
|
26
|
+
duration: { raw: '3661', value: '3661' },
|
|
27
|
+
};
|
|
28
|
+
const formatted = formattingService.applyFormattingToRow(row);
|
|
29
|
+
expect(formatted.id.value).toBe(123);
|
|
30
|
+
expect(formatted.name.value).toBe('Product');
|
|
31
|
+
expect(formatted.price.value).toBe(99.99);
|
|
32
|
+
expect(formatted.duration.value).toBe(3661);
|
|
33
|
+
expect(formatted.created.raw).toBe('2024-01-15');
|
|
34
|
+
expect(formatted.updated.raw).toBe('2024-01-15T14:30:00Z');
|
|
35
|
+
});
|
|
36
|
+
it('should handle null values', () => {
|
|
37
|
+
const row = {
|
|
38
|
+
id: { raw: null, value: null },
|
|
39
|
+
name: { raw: null, value: null },
|
|
40
|
+
};
|
|
41
|
+
const formatted = formattingService.applyFormattingToRow(row);
|
|
42
|
+
expect(formatted.id.value).toBeNull();
|
|
43
|
+
expect(formatted.name.value).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('formatCellValue', () => {
|
|
47
|
+
it('should transform integer values', () => {
|
|
48
|
+
const row = { id: { raw: '42', value: '42' } };
|
|
49
|
+
const column = { key: 'id', label: 'ID', type: 'integer' };
|
|
50
|
+
const result = formattingService.formatCellValue(row, column);
|
|
51
|
+
expect(result).toBe(42);
|
|
52
|
+
});
|
|
53
|
+
it('should transform number values', () => {
|
|
54
|
+
const row = { price: { raw: '19.99', value: '19.99' } };
|
|
55
|
+
const column = { key: 'price', label: 'Price', type: 'number' };
|
|
56
|
+
const result = formattingService.formatCellValue(row, column);
|
|
57
|
+
expect(result).toBe(19.99);
|
|
58
|
+
});
|
|
59
|
+
it('should transform date values to timestamps', () => {
|
|
60
|
+
const row = { created: { raw: '2024-01-15', value: '2024-01-15' } };
|
|
61
|
+
const column = { key: 'created', label: 'Created', type: 'date' };
|
|
62
|
+
const result = formattingService.formatCellValue(row, column);
|
|
63
|
+
expect(typeof result).toBe('number');
|
|
64
|
+
expect(result).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
it('should transform string values', () => {
|
|
67
|
+
const row = { name: { raw: 'Test', value: 'Test' } };
|
|
68
|
+
const column = { key: 'name', label: 'Name', type: 'string' };
|
|
69
|
+
const result = formattingService.formatCellValue(row, column);
|
|
70
|
+
expect(result).toBe('Test');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('formatCellDisplay', () => {
|
|
74
|
+
it('should format integer for display', () => {
|
|
75
|
+
const row = { id: { raw: 42, value: 42 } };
|
|
76
|
+
const column = { key: 'id', label: 'ID', type: 'integer' };
|
|
77
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
78
|
+
expect(result.display).toBe('42');
|
|
79
|
+
});
|
|
80
|
+
it('should format date for display', () => {
|
|
81
|
+
const row = { created: { raw: '2024-01-15', value: new Date('2024-01-15').getTime() } };
|
|
82
|
+
const column = { key: 'created', label: 'Created', type: 'date' };
|
|
83
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
84
|
+
expect(result.display).toContain('2024');
|
|
85
|
+
});
|
|
86
|
+
it('should format datetime for display', () => {
|
|
87
|
+
const row = { updated: { raw: '2024-01-15T14:30:00Z', value: new Date('2024-01-15T14:30:00Z').getTime() } };
|
|
88
|
+
const column = { key: 'updated', label: 'Updated', type: 'datetime' };
|
|
89
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
90
|
+
expect(result.display).toBeTruthy();
|
|
91
|
+
expect(result.display).toContain('2024');
|
|
92
|
+
});
|
|
93
|
+
it('should format duration for display', () => {
|
|
94
|
+
const row = { duration: { raw: 3661, value: 3661 } };
|
|
95
|
+
const column = { key: 'duration', label: 'Duration', type: 'duration' };
|
|
96
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
97
|
+
expect(result.display).toBe('01:01:01');
|
|
98
|
+
});
|
|
99
|
+
it('should handle null values in display', () => {
|
|
100
|
+
const row = { name: { raw: null, value: null } };
|
|
101
|
+
const column = { key: 'name', label: 'Name', type: 'string' };
|
|
102
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
103
|
+
expect(result.display).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('Display format changes', () => {
|
|
107
|
+
it('should respect timezone changes for date formatting', () => {
|
|
108
|
+
const row = { created: { raw: '2024-01-15T12:00:00Z', value: new Date('2024-01-15T12:00:00Z').getTime() } };
|
|
109
|
+
const column = { key: 'created', label: 'Created', type: 'datetime' };
|
|
110
|
+
gridService.updateDisplayFormat({ timeZone: 'America/New_York' });
|
|
111
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
112
|
+
expect(result.display).toBeTruthy();
|
|
113
|
+
});
|
|
114
|
+
it('should respect date format changes', () => {
|
|
115
|
+
const row = { created: { raw: '2024-01-15', value: new Date('2024-01-15').getTime() } };
|
|
116
|
+
const column = { key: 'created', label: 'Created', type: 'date' };
|
|
117
|
+
gridService.updateDisplayFormat({ dateFormat: 'dd/MM/yyyy' });
|
|
118
|
+
const result = formattingService.formatCellDisplay(row, column);
|
|
119
|
+
expect(result.display).toContain('/');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { FilterNode } from '@open-dcp/filter';
|
|
2
|
+
import type { SortingCondition } from './sorting';
|
|
3
|
+
export type ColumnType = 'string' | 'integer' | 'number' | 'date' | 'datetime' | 'duration' | 'custom' | 'component' | 'enum';
|
|
4
|
+
export type GlobalSearchMode = 'value' | 'raw' | 'display';
|
|
5
|
+
export interface FilterOption {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string | number | boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface Column {
|
|
10
|
+
label: string;
|
|
11
|
+
style?: string;
|
|
12
|
+
key: string | number;
|
|
13
|
+
type: ColumnType;
|
|
14
|
+
renderCell?: (cellValue: CellValue, row: Row) => string | HTMLElement;
|
|
15
|
+
displayAsHtml?: boolean;
|
|
16
|
+
component?: any;
|
|
17
|
+
componentPropsMapper?: (cellValue: CellValue, row: Row) => Record<string, any>;
|
|
18
|
+
globalSearchText?: (cellValue: CellValue | null, row: Row, mode: GlobalSearchMode) => string | number | boolean | null | undefined;
|
|
19
|
+
transformer?: (rawValue: any) => string | number | boolean;
|
|
20
|
+
filterOptions?: FilterOption[];
|
|
21
|
+
}
|
|
22
|
+
export interface Row {
|
|
23
|
+
[key: string]: CellValue;
|
|
24
|
+
}
|
|
25
|
+
export interface RenderRow {
|
|
26
|
+
globaIndex: number;
|
|
27
|
+
data: Row;
|
|
28
|
+
}
|
|
29
|
+
export interface CellValue {
|
|
30
|
+
raw: any;
|
|
31
|
+
value: any;
|
|
32
|
+
display?: string | null;
|
|
33
|
+
renderedElement?: HTMLElement;
|
|
34
|
+
}
|
|
35
|
+
export interface GridState {
|
|
36
|
+
startIndex: number;
|
|
37
|
+
step: number;
|
|
38
|
+
firstRowHeight: number;
|
|
39
|
+
lastRowHeight: number;
|
|
40
|
+
renderRows: RenderRow[];
|
|
41
|
+
}
|
|
42
|
+
export interface DisplayFormat {
|
|
43
|
+
timeZone: string;
|
|
44
|
+
dateFormat: string;
|
|
45
|
+
timeFormat: string;
|
|
46
|
+
}
|
|
47
|
+
export interface DisplayValue {
|
|
48
|
+
display: string | undefined | null;
|
|
49
|
+
renderedElement: HTMLElement | undefined;
|
|
50
|
+
}
|
|
51
|
+
export interface GlobalSearchOptions {
|
|
52
|
+
columns?: Array<string | number>;
|
|
53
|
+
caseInsensitive?: boolean;
|
|
54
|
+
searchMode?: GlobalSearchMode;
|
|
55
|
+
}
|
|
56
|
+
export interface GlobalSearchState {
|
|
57
|
+
query: string;
|
|
58
|
+
options?: GlobalSearchOptions;
|
|
59
|
+
}
|
|
60
|
+
export interface FilterSortUpdatePayload {
|
|
61
|
+
filterTree: FilterNode | null;
|
|
62
|
+
sorts: SortingCondition[];
|
|
63
|
+
globalSearch?: GlobalSearchState | null;
|
|
64
|
+
}
|
|
65
|
+
export interface GridOptions {
|
|
66
|
+
elementHeight: number;
|
|
67
|
+
multiSelect: boolean;
|
|
68
|
+
allSelector: boolean;
|
|
69
|
+
displayFormat: Partial<DisplayFormat>;
|
|
70
|
+
caseInsensitiveFiltering: boolean;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
transform: {
|
|
3
|
+
'^.+\\.tsx?$': 'ts-jest',
|
|
4
|
+
'^.+\\.jsx?$': 'ts-jest',
|
|
5
|
+
},
|
|
6
|
+
testMatch: [
|
|
7
|
+
"**/__tests__/**/*.test.ts"
|
|
8
|
+
],
|
|
9
|
+
moduleNameMapper: {
|
|
10
|
+
'^@/(.*)$': '<rootDir>/src/$1',
|
|
11
|
+
'^lodash-es$': 'lodash'
|
|
12
|
+
},
|
|
13
|
+
transformIgnorePatterns: [
|
|
14
|
+
'node_modules/(?!@open-dcp)',
|
|
15
|
+
],
|
|
16
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-dcp/grid",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.17",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "npm run dev",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "jest"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"rxjs": ">=7.8.2"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@open-dcp/filter": ">=0.1.6",
|
|
21
|
+
"@open-dcp/utilities": ">=1.1.1",
|
|
22
|
+
"@types/lodash-es": ">=4.17.12",
|
|
23
|
+
"date-fns": ">=4.1.0",
|
|
24
|
+
"date-fns-tz": ">=3.2.0",
|
|
25
|
+
"lodash-es": ">=4.17.21",
|
|
26
|
+
"tslib": ">=2.8.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/jest": "^29.5.11",
|
|
30
|
+
"@types/lodash": "^4.17.23",
|
|
31
|
+
"jest": "^29.7.0",
|
|
32
|
+
"jest-junit": "^17.0.0",
|
|
33
|
+
"lodash": "^4.17.21",
|
|
34
|
+
"rxjs": "^7.8.2",
|
|
35
|
+
"ts-jest": "^29.4.4",
|
|
36
|
+
"typescript": "^5.7.3"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/Roche/dcp-pkg-fe-ts-grid.git"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|