Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.3.0 #11

Merged
merged 5 commits into from
Jan 13, 2024
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
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,20 @@ Customizable native Vue3 data grid with very limited dependencies. Leverages a f

## Release Notes

### v3.3.0
- Add `date` and `dateTime` filtering support to `ClientSideDataService`.
- Improved `date` and `dateTime` support for sorting and filtering in `ClientSideDataService` ensuring all computations are done on UTC dates and falsey values are converted to the JS minimum date of `1970-01-01 00:00:00.000+00:00`.
- Fix for sorting being able to override the filter.

### v3.2.0
- [#9](https://github.com/nruffing/data-grid-vue/issues/9): Add package export so styles can be loaded via `data-grid-vue/style`.
- Fix bug in `ClientSideDataService` where paging through a sorted grid could cause data to not stay sorted.
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v2.1.0 to leverage ability to debounce the `dragover` event.
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v2.1.0 to leverage ability to debounce the `dragover` event.
- Replace [`debounce`](https://www.npmjs.com/package/debounce) with new [`native-event-vue`](https://www.npmjs.com/package/native-event-vue) package to leverage the lightweight vue-friendly native event handling with debounce.
- Update development dependencies.

### v3.1.0
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v1.1.0
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v1.1.0
- update development dependencies

### v3.0.1
Expand Down Expand Up @@ -193,7 +198,7 @@ Customizable native Vue3 data grid with very limited dependencies. Leverages a f
- Repo now uses [`pnpm`](https://pnpm.io/) where the `data-grid-vue` package is build from the root workspace and the documentation site and dev app are nested workspaces.
- Now being built with `vite` [v5](https://vitejs.dev/blog/announcing-vite5).
- Update [`debounce`](https://www.npmjs.com/package/debounce/v/2.0.0) dependency to new major version v2.0.0 which requires node v18 ([current oldest supported version](https://nodejs.org/en/about/previous-releases)).
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v0.2.0
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v0.2.0
- Documentation site theme update
- Documentation site is now setup up as a [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps).
- bugfix: `DataGridVueOptions.clickOutsideDirectiveName` removed.
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"datagridvue",
"docsearch",
"dragover",
"falsey",
"gapi",
"keyvault",
"navigatable",
Expand Down
265 changes: 265 additions & 0 deletions lib/DataService.Client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
import { expect, test, describe } from 'vitest'
import { ClientSideDataService, StubDataService } from './DataService'
import { SortType } from './Sort'
import { DataType } from './DataGridVue'
import { FilterOperator } from './Filter'

interface TestDataItem {
id: number
name: string
date: string
}

const TestDataItemOne = { id: 1, name: 'Test 1', date: '2024-01-13T12:33:00.000Z' }
const TestDataItemTwo = { id: 2, name: 'Test 2', date: '2024-01-12T12:32:00.000Z' }
const TestDataItemThree = { id: 2, name: 'Test 3', date: '2024-01-11T12:31:00.000Z' }
const TestDataItemFour = { id: 4, name: 'Test 4', date: '2024-01-10T12:30:00.000Z' }
const TestDataItemFive = { id: 5, name: 'Test 5', date: '2024-01-10T12:29:00.000Z' }

const TestDataSet = [TestDataItemThree, TestDataItemTwo, TestDataItemFour, TestDataItemFive, TestDataItemOne] as TestDataItem[]

describe('StubDataService', () => {
test('getPageAsync', async () => {
const pageData = await StubDataService.getPageAsync(1, 10, [], undefined)
expect(pageData).toEqual({
totalItems: 0,
dataItems: [],
})
})
})

describe('ClientSideDataService', () => {
test('getPageAsync | pages', async () => {
const dataService = new ClientSideDataService([...TestDataSet])
const pageDataOne = await dataService.getPageAsync(1, 2, [], undefined)
const pageDataTwo = await dataService.getPageAsync(2, 1, [], undefined)
const pageDataThree = await dataService.getPageAsync(2, 3, [], undefined)
expect(pageDataOne).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemThree, TestDataItemTwo],
})
expect(pageDataTwo).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemTwo],
})
expect(pageDataThree).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemFive, TestDataItemOne],
})
})

test('getPageAsync | filters', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const testCases = [
{
filter: { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.equals, value: '3' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 0,
expected: [],
},
{
filter: { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.equals, value: '4' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.date, operator: FilterOperator.lessThan, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 2,
expected: [TestDataItemFour, TestDataItemFive],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.date, operator: FilterOperator.equals, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemThree],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 0,
expected: [],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T12:30:00.000Z' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T14:30:00.000+02:00' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T14:30:00.000+02:00' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.equals, value: 'Test 3' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemThree],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.notEquals, value: 'Test 3' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 4,
expected: [TestDataItemTwo, TestDataItemFour, TestDataItemFive, TestDataItemOne],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.contains, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 1,
expected: [TestDataItemTwo],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.startsWith, value: 'te' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 5,
expected: [TestDataItemThree, TestDataItemTwo, TestDataItemFour, TestDataItemFive],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.endsWith, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 1,
expected: [TestDataItemTwo],
},
{
filter: {
or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.notEquals, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 3,
expected: [TestDataItemFour, TestDataItemFive, TestDataItemOne],
},
]

for (const testCase of testCases) {
const pageData = await dataService.getPageAsync(testCase.pageNum, testCase.pageSize, [], testCase.filter)
expect(pageData, JSON.stringify(testCase)).toEqual({
totalItems: testCase.expectedTotalItems,
dataItems: testCase.expected,
})
}
})

test('getPageAsync | sorts', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const testCases = [
{
sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFive, TestDataItemFour],
},
{
sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }],
pageNum: 2,
pageSize: 2,
expected: [TestDataItemThree, TestDataItemTwo],
},
{ sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }], pageNum: 3, pageSize: 2, expected: [TestDataItemOne] },
{ sort: [], pageNum: 3, pageSize: 1, expected: [TestDataItemFour] },
{
sort: [
{ fieldName: 'id', dataType: DataType.number, type: SortType.ascending },
{ fieldName: 'name', dataType: DataType.alphanumeric, type: SortType.descending },
],
pageNum: 1,
pageSize: 3,
expected: [TestDataItemOne, TestDataItemThree, TestDataItemTwo],
},
{
sort: [{ fieldName: 'date', dataType: DataType.date, type: SortType.ascending }],
pageNum: 2,
pageSize: 2,
expected: [TestDataItemThree, TestDataItemTwo],
},
{
sort: [{ fieldName: 'date', dataType: DataType.date, type: SortType.ascending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFour, TestDataItemFive],
},
{
sort: [{ fieldName: 'date', dataType: DataType.dateTime, type: SortType.ascending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFive, TestDataItemFour],
},
]

for (const testCase of testCases) {
const pageData = await dataService.getPageAsync(testCase.pageNum, testCase.pageSize, testCase.sort, undefined)
expect(pageData, JSON.stringify(testCase)).toEqual({
totalItems: TestDataSet.length,
dataItems: testCase.expected,
})
}
})

test('getPageAsync | filters and sorts', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const filter = { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.greaterThan, value: '2' }], and: undefined }
const sort = [
{ fieldName: 'date', dataType: DataType.dateTime, type: SortType.ascending },
{ fieldName: 'name', dataType: DataType.alphanumeric, type: SortType.descending },
]

const pageData = await dataService.getPageAsync(1, 4, sort, filter)

console.log(JSON.stringify(pageData, null, 2))

expect(pageData).toEqual({
totalItems: 2,
dataItems: [TestDataItemFive, TestDataItemFour],
})
})
})
76 changes: 0 additions & 76 deletions lib/DataService.spec.ts

This file was deleted.

1 change: 1 addition & 0 deletions lib/DataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class ClientSideDataService implements DataService {

const sortJson = JSON.stringify(sort)
if (sortJson !== this.previousSortJson) {
this.sorted = [...this.filtered]
ClientSideSort.sort(sort, this.sorted)
this.previousSortJson = sortJson
}
Expand Down
Loading