@truedat/dq 7.13.8 → 7.13.10
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/package.json +3 -3
- package/src/components/RuleImplementationsTable.js +13 -48
- package/src/components/__tests__/Implementations.spec.js +5 -0
- package/src/components/__tests__/RuleFormImplementations.spec.js +17 -27
- package/src/components/__tests__/RuleImplementationsTable.spec.js +59 -15
- package/src/components/__tests__/__snapshots__/Implementations.spec.js.snap +2 -2
- package/src/reducers/__tests__/ruleImplementationQuery.spec.js +0 -13
- package/src/reducers/ruleImplementationQuery.js +1 -5
- package/src/routines.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dq",
|
|
3
|
-
"version": "7.13.
|
|
3
|
+
"version": "7.13.10",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@testing-library/jest-dom": "^6.6.3",
|
|
54
54
|
"@testing-library/react": "^16.3.0",
|
|
55
55
|
"@testing-library/user-event": "^14.6.1",
|
|
56
|
-
"@truedat/test": "7.13.
|
|
56
|
+
"@truedat/test": "7.13.10",
|
|
57
57
|
"identity-obj-proxy": "^3.0.0",
|
|
58
58
|
"jest": "^29.7.0",
|
|
59
59
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"semantic-ui-react": "^3.0.0-beta.2",
|
|
87
87
|
"swr": "^2.3.3"
|
|
88
88
|
},
|
|
89
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "1db951294c0ca7ddc8425acb02b641bd9844f219"
|
|
90
90
|
}
|
|
@@ -1,49 +1,33 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
2
|
import PropTypes from "prop-types";
|
|
4
|
-
import { connect } from "react-redux";
|
|
5
|
-
import { getSortInfo, sortColumn } from "@truedat/core/services/sort";
|
|
6
3
|
import { Checkbox, Table, Header, Icon } from "semantic-ui-react";
|
|
7
4
|
import { useIntl } from "react-intl";
|
|
8
5
|
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
9
|
-
import { sortImplementations } from "../routines";
|
|
10
6
|
import RuleImplementationRow from "./RuleImplementationRow";
|
|
11
7
|
export const RuleImplementationsTable = ({
|
|
12
8
|
addAll,
|
|
13
9
|
checkedAll,
|
|
14
10
|
checkRow,
|
|
15
11
|
executeImplementationsOn,
|
|
16
|
-
implementationsSort,
|
|
17
|
-
sortImplementations,
|
|
18
12
|
columns,
|
|
19
|
-
ruleImplementationsLoading,
|
|
20
13
|
isRowChecked,
|
|
21
14
|
}) => {
|
|
22
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
searchData,
|
|
17
|
+
loading,
|
|
18
|
+
sortColumn,
|
|
19
|
+
sortDirection,
|
|
20
|
+
handleSortSelection,
|
|
21
|
+
} = useSearchContext();
|
|
23
22
|
|
|
24
23
|
const { formatMessage } = useIntl();
|
|
25
24
|
|
|
26
|
-
const
|
|
27
|
-
_.prop("column")(getSortInfo(implementationsSort))
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const [direction, setDirection] = useState(
|
|
31
|
-
_.prop("direction")(getSortInfo(implementationsSort))
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const ruleImplementations = searchData?.data;
|
|
25
|
+
const ruleImplementations = searchData?.data || [];
|
|
35
26
|
|
|
36
27
|
const validColumns = _.reject(
|
|
37
28
|
({ hideOn }) => _.isFunction(hideOn) && hideOn(ruleImplementations)
|
|
38
29
|
)(columns);
|
|
39
30
|
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
const { column: sortedColumn, direction: direction } =
|
|
42
|
-
getSortInfo(implementationsSort);
|
|
43
|
-
setColumn(sortedColumn);
|
|
44
|
-
setDirection(direction);
|
|
45
|
-
}, [implementationsSort]);
|
|
46
|
-
|
|
47
31
|
return (
|
|
48
32
|
<>
|
|
49
33
|
{!_.isEmpty(ruleImplementations) ? (
|
|
@@ -71,22 +55,15 @@ export const RuleImplementationsTable = ({
|
|
|
71
55
|
}`,
|
|
72
56
|
})}
|
|
73
57
|
sorted={
|
|
74
|
-
_.path("sort.name")(column) ===
|
|
75
|
-
?
|
|
58
|
+
_.path("sort.name")(column) === sortColumn
|
|
59
|
+
? sortDirection
|
|
76
60
|
: null
|
|
77
61
|
}
|
|
78
62
|
className={
|
|
79
63
|
_.path("sort.name")(column) ? "" : "disabled"
|
|
80
64
|
}
|
|
81
65
|
onClick={() =>
|
|
82
|
-
|
|
83
|
-
column,
|
|
84
|
-
sortImplementations,
|
|
85
|
-
setDirection,
|
|
86
|
-
setColumn,
|
|
87
|
-
direction,
|
|
88
|
-
sortedColumn
|
|
89
|
-
)
|
|
66
|
+
handleSortSelection(_.path("sort.name")(column))
|
|
90
67
|
}
|
|
91
68
|
/>
|
|
92
69
|
))
|
|
@@ -108,7 +85,7 @@ export const RuleImplementationsTable = ({
|
|
|
108
85
|
</Table>
|
|
109
86
|
</div>
|
|
110
87
|
) : null}
|
|
111
|
-
{_.isEmpty(ruleImplementations) && !
|
|
88
|
+
{_.isEmpty(ruleImplementations) && !loading ? (
|
|
112
89
|
<Header as="h4">
|
|
113
90
|
<Icon name="search" />
|
|
114
91
|
<Header.Content>
|
|
@@ -125,20 +102,8 @@ RuleImplementationsTable.propTypes = {
|
|
|
125
102
|
checkedAll: PropTypes.bool,
|
|
126
103
|
checkRow: PropTypes.func,
|
|
127
104
|
executeImplementationsOn: PropTypes.bool,
|
|
128
|
-
implementationsSort: PropTypes.array,
|
|
129
105
|
isRowChecked: PropTypes.func,
|
|
130
|
-
ruleImplementationsLoading: PropTypes.bool,
|
|
131
|
-
sortImplementations: PropTypes.func,
|
|
132
|
-
ruleImplementations: PropTypes.array,
|
|
133
106
|
columns: PropTypes.array,
|
|
134
107
|
};
|
|
135
108
|
|
|
136
|
-
|
|
137
|
-
ruleImplementations: props.ruleImplementations || state.ruleImplementations,
|
|
138
|
-
ruleImplementationsLoading: state.ruleImplementationsLoading,
|
|
139
|
-
implementationsSort: _.path("ruleImplementationQuery.sort")(state),
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
export default connect(mapStateToProps, { sortImplementations })(
|
|
143
|
-
RuleImplementationsTable
|
|
144
|
-
);
|
|
109
|
+
export default RuleImplementationsTable;
|
|
@@ -52,7 +52,12 @@ describe("<Implementations />", () => {
|
|
|
52
52
|
],
|
|
53
53
|
scroll_id: null,
|
|
54
54
|
},
|
|
55
|
+
loading: false,
|
|
55
56
|
searchMust: { status: ["pending"] },
|
|
57
|
+
sortColumn: "implementation_key.sort",
|
|
58
|
+
sortDirection: "ascending",
|
|
59
|
+
handleSortSelection: jest.fn(),
|
|
60
|
+
toggleHiddenFilterValue: jest.fn(),
|
|
56
61
|
setOnSearchChange: jest.fn(),
|
|
57
62
|
});
|
|
58
63
|
});
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
|
-
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
3
|
-
import {
|
|
4
|
-
useRuleImplementationFromRulesSearch,
|
|
5
|
-
useRuleImplementationFilters,
|
|
6
|
-
} from "../../hooks/useImplementations";
|
|
7
2
|
import { RuleFormImplementations } from "../RuleFormImplementations";
|
|
8
3
|
|
|
9
4
|
jest.mock("@truedat/core/search/SearchContext", () => {
|
|
@@ -18,10 +13,7 @@ jest.mock("@truedat/core/search/SearchContext", () => {
|
|
|
18
13
|
};
|
|
19
14
|
});
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
useRuleImplementationFromRulesSearch: jest.fn(),
|
|
23
|
-
useRuleImplementationFilters: jest.fn(),
|
|
24
|
-
}));
|
|
16
|
+
const { useSearchContext } = require("@truedat/core/search/SearchContext");
|
|
25
17
|
|
|
26
18
|
describe("<RuleFormImplementations />", () => {
|
|
27
19
|
const rule = { id: 1, name: "rule name" };
|
|
@@ -32,50 +24,48 @@ describe("<RuleFormImplementations />", () => {
|
|
|
32
24
|
deletedRender: false,
|
|
33
25
|
};
|
|
34
26
|
|
|
27
|
+
const renderOpts = {
|
|
28
|
+
state: {
|
|
29
|
+
rule: { id: 1, name: "rule name" },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
35
33
|
beforeEach(() => {
|
|
36
|
-
jest.clearAllMocks();
|
|
37
|
-
useRuleImplementationFromRulesSearch.mockReturnValue({
|
|
38
|
-
trigger: jest.fn(),
|
|
39
|
-
});
|
|
40
|
-
useRuleImplementationFilters.mockReturnValue({
|
|
41
|
-
trigger: jest.fn(),
|
|
42
|
-
});
|
|
43
34
|
useSearchContext.mockReturnValue({
|
|
44
35
|
searchData: {
|
|
45
36
|
data: [],
|
|
46
37
|
scroll_id: null,
|
|
47
38
|
},
|
|
48
|
-
|
|
39
|
+
loading: false,
|
|
40
|
+
searchMust: {},
|
|
41
|
+
sortColumn: "implementation_key.raw",
|
|
42
|
+
sortDirection: "ascending",
|
|
43
|
+
handleSortSelection: jest.fn(),
|
|
44
|
+
toggleHiddenFilterValue: jest.fn(),
|
|
49
45
|
setOnSearchChange: jest.fn(),
|
|
50
46
|
});
|
|
51
47
|
});
|
|
52
48
|
|
|
53
49
|
it("matches the latest snapshot", async () => {
|
|
54
|
-
const rendered = render(<RuleFormImplementations {...props}
|
|
50
|
+
const rendered = render(<RuleFormImplementations {...props} />, renderOpts);
|
|
55
51
|
await waitForLoad(rendered);
|
|
56
52
|
expect(rendered.container).toMatchSnapshot();
|
|
57
53
|
});
|
|
58
54
|
|
|
59
55
|
it("renders null when rule is empty", async () => {
|
|
60
56
|
const rendered = render(
|
|
61
|
-
<RuleFormImplementations {...{ ...props, rule: {} }}
|
|
57
|
+
<RuleFormImplementations {...{ ...props, rule: {} }} />,
|
|
58
|
+
renderOpts
|
|
62
59
|
);
|
|
63
60
|
await waitForLoad(rendered);
|
|
64
61
|
expect(rendered.container.firstChild).toBeNull();
|
|
65
62
|
});
|
|
66
63
|
|
|
67
64
|
it("renders RuleFormImplementations when rule is not empty", async () => {
|
|
68
|
-
const rendered = render(<RuleFormImplementations {...props}
|
|
65
|
+
const rendered = render(<RuleFormImplementations {...props} />, renderOpts);
|
|
69
66
|
await waitForLoad(rendered);
|
|
70
67
|
expect(
|
|
71
68
|
rendered.container.querySelector(".implementation-actions")
|
|
72
69
|
).toBeInTheDocument();
|
|
73
70
|
});
|
|
74
|
-
|
|
75
|
-
it("uses useRuleImplementationFromRulesSearch hook", async () => {
|
|
76
|
-
const rendered = render(<RuleFormImplementations {...props} />);
|
|
77
|
-
await waitForLoad(rendered);
|
|
78
|
-
|
|
79
|
-
expect(useRuleImplementationFromRulesSearch).toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
71
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { waitFor } from "@testing-library/react";
|
|
1
2
|
import userEvent from "@testing-library/user-event";
|
|
2
3
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
3
4
|
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
@@ -22,25 +23,56 @@ describe("<RuleImplementationsTable />", () => {
|
|
|
22
23
|
{ name: "result", sort: { name: "bar.raw" } },
|
|
23
24
|
];
|
|
24
25
|
const implementationsSort = [{ "name.raw": "desc" }];
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
const ruleImplementationsLoading = false;
|
|
27
28
|
const props = {
|
|
28
29
|
ruleImplementations,
|
|
29
30
|
columns,
|
|
30
31
|
ruleImplementationsLoading,
|
|
31
32
|
implementationsSort,
|
|
32
|
-
sortImplementations,
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
const mockState = {
|
|
36
|
+
sortColumn: "name.raw",
|
|
37
|
+
sortDirection: "descending",
|
|
38
|
+
rerenderFn: null,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handleSortSelection = jest.fn((columnName) => {
|
|
42
|
+
if (mockState.sortColumn !== columnName) {
|
|
43
|
+
mockState.sortColumn = columnName;
|
|
44
|
+
mockState.sortDirection = "ascending";
|
|
45
|
+
} else {
|
|
46
|
+
mockState.sortDirection =
|
|
47
|
+
mockState.sortDirection === "ascending" ? "descending" : "ascending";
|
|
48
|
+
}
|
|
49
|
+
// Update the mock return value
|
|
50
|
+
useSearchContext.mockReturnValue(createMockSearchContext());
|
|
51
|
+
// Re-render if component is already rendered
|
|
52
|
+
if (mockState.rerenderFn) {
|
|
53
|
+
mockState.rerenderFn(<RuleImplementationsTable {...props} />);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const createMockSearchContext = () => ({
|
|
58
|
+
searchData: {
|
|
59
|
+
data: ruleImplementations,
|
|
60
|
+
scroll_id: null,
|
|
61
|
+
},
|
|
62
|
+
loading: false,
|
|
63
|
+
searchMust: {},
|
|
64
|
+
sortColumn: mockState.sortColumn,
|
|
65
|
+
sortDirection: mockState.sortDirection,
|
|
66
|
+
handleSortSelection,
|
|
67
|
+
setOnSearchChange: jest.fn(),
|
|
68
|
+
});
|
|
69
|
+
|
|
35
70
|
beforeEach(() => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
searchMust: {},
|
|
42
|
-
setOnSearchChange: jest.fn(),
|
|
43
|
-
});
|
|
71
|
+
mockState.sortColumn = "name.raw";
|
|
72
|
+
mockState.sortDirection = "descending";
|
|
73
|
+
mockState.rerenderFn = null;
|
|
74
|
+
handleSortSelection.mockClear();
|
|
75
|
+
useSearchContext.mockReturnValue(createMockSearchContext());
|
|
44
76
|
});
|
|
45
77
|
|
|
46
78
|
it("matches the latest snapshot", async () => {
|
|
@@ -61,6 +93,7 @@ describe("<RuleImplementationsTable />", () => {
|
|
|
61
93
|
it("handles sort when column header is clicked", async () => {
|
|
62
94
|
const user = userEvent.setup({ delay: null });
|
|
63
95
|
const rendered = render(<RuleImplementationsTable {...props} />);
|
|
96
|
+
mockState.rerenderFn = rendered.rerender;
|
|
64
97
|
await waitForLoad(rendered);
|
|
65
98
|
|
|
66
99
|
const headerCells = rendered.container.querySelectorAll("th");
|
|
@@ -68,13 +101,24 @@ describe("<RuleImplementationsTable />", () => {
|
|
|
68
101
|
// Click on the second header cell
|
|
69
102
|
await user.click(headerCells[1]);
|
|
70
103
|
|
|
71
|
-
//
|
|
72
|
-
|
|
104
|
+
// Wait for the class to update after re-render
|
|
105
|
+
await waitFor(() => {
|
|
106
|
+
const updatedHeaderCells = rendered.container.querySelectorAll("th");
|
|
107
|
+
expect(updatedHeaderCells[1].getAttribute("class")).toContain(
|
|
108
|
+
"ascending sorted"
|
|
109
|
+
);
|
|
110
|
+
});
|
|
73
111
|
|
|
74
112
|
// Click again to sort descending
|
|
75
|
-
|
|
113
|
+
const updatedHeaderCells = rendered.container.querySelectorAll("th");
|
|
114
|
+
await user.click(updatedHeaderCells[1]);
|
|
76
115
|
|
|
77
|
-
//
|
|
78
|
-
|
|
116
|
+
// Wait for the class to update after re-render
|
|
117
|
+
await waitFor(() => {
|
|
118
|
+
const finalHeaderCells = rendered.container.querySelectorAll("th");
|
|
119
|
+
expect(finalHeaderCells[1].getAttribute("class")).toContain(
|
|
120
|
+
"descending sorted"
|
|
121
|
+
);
|
|
122
|
+
});
|
|
79
123
|
});
|
|
80
124
|
});
|
|
@@ -145,7 +145,7 @@ exports[`<Implementations /> matches the latest snapshot 1`] = `
|
|
|
145
145
|
class=""
|
|
146
146
|
>
|
|
147
147
|
<th
|
|
148
|
-
class="two wide"
|
|
148
|
+
class="two wide ascending sorted"
|
|
149
149
|
>
|
|
150
150
|
ruleImplementations.props.implementation_key
|
|
151
151
|
</th>
|
|
@@ -155,7 +155,7 @@ exports[`<Implementations /> matches the latest snapshot 1`] = `
|
|
|
155
155
|
ruleImplementations.props.rule
|
|
156
156
|
</th>
|
|
157
157
|
<th
|
|
158
|
-
class="two wide
|
|
158
|
+
class="two wide disabled"
|
|
159
159
|
>
|
|
160
160
|
ruleImplementations.props.business_concepts
|
|
161
161
|
</th>
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
toggleImplementationFilterValue,
|
|
6
6
|
searchImplementations,
|
|
7
7
|
selectImplementationPage,
|
|
8
|
-
sortImplementations,
|
|
9
8
|
} from "../../routines";
|
|
10
9
|
import { ruleImplementationQuery } from "..";
|
|
11
10
|
|
|
@@ -60,18 +59,6 @@ describe("reducers: ruleImplementationQuery", () => {
|
|
|
60
59
|
});
|
|
61
60
|
});
|
|
62
61
|
|
|
63
|
-
describe("action: sortImplementations.TRIGGER", () => {
|
|
64
|
-
it("should set sort from payload and set page to 1", () => {
|
|
65
|
-
const payload = [{ name2: "asc" }];
|
|
66
|
-
expect(
|
|
67
|
-
ruleImplementationQuery(fooState, {
|
|
68
|
-
type: sortImplementations.TRIGGER,
|
|
69
|
-
payload,
|
|
70
|
-
})
|
|
71
|
-
).toMatchObject({ sort: [{ name2: "asc" }] });
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
62
|
describe("action: searchImplementations.TRIGGER", () => {
|
|
76
63
|
const query = "some query";
|
|
77
64
|
it("should set the query from the payload", () => {
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
toggleImplementationFilterValue,
|
|
6
6
|
searchImplementations,
|
|
7
7
|
selectImplementationPage,
|
|
8
|
-
sortImplementations,
|
|
9
8
|
} from "../routines";
|
|
10
9
|
|
|
11
10
|
const defaultPage = 1;
|
|
@@ -43,10 +42,7 @@ const ruleImplementationQuery = (state = initialState, { type, payload }) => {
|
|
|
43
42
|
const { activePage } = payload;
|
|
44
43
|
return { ...state, page: activePage };
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
const sort = payload;
|
|
48
|
-
return { ...state, sort, page: defaultPage };
|
|
49
|
-
}
|
|
45
|
+
|
|
50
46
|
default:
|
|
51
47
|
return state;
|
|
52
48
|
}
|
package/src/routines.js
CHANGED
|
@@ -97,7 +97,7 @@ export const setImplementationDefaultFilters = createRoutine(
|
|
|
97
97
|
"SET_IMPLEMENTATION_DEFAULT_FILTRERS"
|
|
98
98
|
);
|
|
99
99
|
export const deleteImplementation = createRoutine("DELETE_IMPLEMENTATION");
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
export const sortRules = createRoutine("SORT_RULES");
|
|
102
102
|
export const submitImplementation = createRoutine("SUBMIT_IMPLEMENTATION");
|
|
103
103
|
export const toggleImplementationFilterValue = createRoutine(
|