-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
closes: #1122 Co-authored-by: Sebastian Leidig <sebastian.leidig@gmail.com>
- Loading branch information
1 parent
32befc0
commit b2279d2
Showing
12 changed files
with
207 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 4 additions & 7 deletions
11
src/app/core/entity-components/entity-list/filter-predicate.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,12 @@ | ||
import { Entity } from "../../entity/model/entity"; | ||
import { entityListSortingAccessor } from "../entity-subrecord/entity-subrecord/sorting-accessor"; | ||
import { getReadableValue } from "../entity-subrecord/entity-subrecord/value-accessor"; | ||
|
||
export function entityFilterPredicate<T extends Entity>( | ||
export function entityFilterPredicate<T extends Entity, P extends keyof T>( | ||
data: T, | ||
filter: string | ||
): boolean { | ||
const keys = Object.keys(data); | ||
const keys = Object.keys(data) as P[]; | ||
return keys.some((property) => | ||
entityListSortingAccessor(data, property) | ||
?.toString() | ||
.toLowerCase() | ||
.includes(filter) | ||
getReadableValue(data, property)?.toString().toLowerCase().includes(filter) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 0 additions & 24 deletions
24
src/app/core/entity-components/entity-subrecord/entity-subrecord/sorting-accessor.ts
This file was deleted.
Oops, something went wrong.
81 changes: 81 additions & 0 deletions
81
src/app/core/entity-components/entity-subrecord/entity-subrecord/table-sort.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { tableSort } from "./table-sort"; | ||
import moment from "moment"; | ||
import { ConfigurableEnumConfig } from "../../../configurable-enum/configurable-enum.interface"; | ||
|
||
describe("TableSort", () => { | ||
it("should sort strings with partial numbers correctly", () => { | ||
testSort(["PN1", "PN2", "PN12"]); | ||
}); | ||
|
||
it("should sort dates correctly", () => { | ||
testSort([ | ||
moment().subtract(1, "week").toDate(), | ||
moment().subtract(3, "days").toDate(), | ||
new Date(), | ||
]); | ||
}); | ||
|
||
it("should sort numbers correctly", () => { | ||
testSort([1, 1.4, 3, Infinity]); | ||
}); | ||
|
||
it("should sort a array with null and undefined values correctly", () => { | ||
testSort(["1", 2, "three", undefined]); | ||
}); | ||
|
||
it("should sort configurable enums based on their label", () => { | ||
const values: ConfigurableEnumConfig = [ | ||
{ id: "first", label: "aAa" }, | ||
{ id: "second", label: "Bbb" }, | ||
{ id: "third", label: "CDE" }, | ||
]; | ||
testSort(values); | ||
}); | ||
|
||
it("should allow to filter descending", () => { | ||
testSort([null, 3, 2.5, 2, "1"], "desc"); | ||
}); | ||
|
||
it("should return input array if not sort direction is defined", () => { | ||
const values = ["3", 1, 2, undefined, "ten"].map((val) => ({ | ||
record: { key: val }, | ||
})); | ||
const result = tableSort([...values], { direction: "", active: "key" }); | ||
expect(result).toEqual(values); | ||
}); | ||
|
||
it("should return input array if no active property is defined", () => { | ||
const values = [2, 1, 3].map((val) => ({ record: { key: val } })); | ||
const result = tableSort([...values], { direction: "asc", active: "" }); | ||
expect(result).toEqual(values); | ||
}); | ||
|
||
function testSort( | ||
sortedArray: any[], | ||
direction: "asc" | "desc" | "" = "asc" | ||
) { | ||
const objectArray = sortedArray.map((val) => ({ record: { key: val } })); | ||
for (let i = 0; i < sortedArray.length; i++) { | ||
const shuffled = shuffle(objectArray); | ||
const result = tableSort(shuffled, { direction, active: "key" }); | ||
const resultValues = result.map((row) => row.record.key); | ||
expect(resultValues).toEqual(sortedArray); | ||
} | ||
} | ||
|
||
function shuffle<OBJECT>(array: OBJECT[]): OBJECT[] { | ||
const result = [...array]; | ||
for (let currentIndex = 0; currentIndex < array.length; currentIndex++) { | ||
// Pick a remaining element... | ||
const randomIndex = Math.floor(Math.random() * currentIndex); | ||
|
||
// And swap it with the current element. | ||
[result[currentIndex], result[randomIndex]] = [ | ||
result[randomIndex], | ||
result[currentIndex], | ||
]; | ||
} | ||
|
||
return result; | ||
} | ||
}); |
56 changes: 56 additions & 0 deletions
56
src/app/core/entity-components/entity-subrecord/entity-subrecord/table-sort.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { getReadableValue } from "./value-accessor"; | ||
import { TableRow } from "./entity-subrecord.component"; | ||
|
||
/** | ||
* Custom sort implementation for a MatTableDataSource<TableRow<T>> | ||
* @param data The data of the data source | ||
* @param direction direction "asc", "desc" or "" meaning none | ||
* @param active the property of T for which it should be sorted | ||
* @returns the sorted table rows | ||
*/ | ||
export function tableSort<OBJECT, PROPERTY extends keyof OBJECT>( | ||
data: TableRow<OBJECT>[], | ||
{ | ||
direction, | ||
active, | ||
}: { direction: "asc" | "desc" | ""; active: PROPERTY | "" } | ||
): TableRow<OBJECT>[] { | ||
if (direction === "" || !active) { | ||
return data; | ||
} | ||
data.sort((objA, objB) => { | ||
const valueA = getComparableValue(objA.record, active); | ||
const valueB = getComparableValue(objB.record, active); | ||
return compareValues(valueA, valueB); | ||
}); | ||
if (direction === "desc") { | ||
data.reverse(); | ||
} | ||
return data; | ||
} | ||
|
||
function getComparableValue<OBJECT, PROPERTY extends keyof OBJECT>( | ||
obj: OBJECT, | ||
key: PROPERTY | ||
): OBJECT[PROPERTY] | string { | ||
const value = getReadableValue(obj, key) as OBJECT[PROPERTY]; | ||
if (value instanceof Date) { | ||
return value.getTime() + ""; | ||
} else if (typeof value === "number") { | ||
return value + ""; | ||
} else { | ||
return value; | ||
} | ||
} | ||
|
||
function compareValues(a, b) { | ||
if (a === b) { | ||
return 0; | ||
} else if (typeof a === "string" && typeof b === "string") { | ||
return a.localeCompare(b, undefined, { numeric: true }); | ||
} else if (a > b || b === null || b === undefined) { | ||
return -1; | ||
} else if (a < b || a === null || a === undefined) { | ||
return 1; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/app/core/entity-components/entity-subrecord/entity-subrecord/value-accessor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* An enhanced sortingDataAccessor function that can be set for a MatTableDataSource | ||
* in order to support sorting by ConfigurableEnum columns and other Entity specific values. | ||
* | ||
* @param data The object (table row); passed in by the data source | ||
* @param key The active sorting header key; passed in by the data source | ||
*/ | ||
export function getReadableValue<OBJECT, PROPERTY extends keyof OBJECT>( | ||
data: OBJECT, | ||
key: PROPERTY | ||
): OBJECT[PROPERTY] | string { | ||
if (isConfigurableEnum(data, key)) { | ||
return (data[key] as any).label; | ||
} else { | ||
return data[key]; | ||
} | ||
} | ||
|
||
function isConfigurableEnum<OBJECT, PROPERTY extends keyof OBJECT>( | ||
data: OBJECT, | ||
key: PROPERTY | ||
): boolean { | ||
return typeof data[key] === "object" && data[key] && "label" in data[key]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.