@truedat/core 8.12.0 → 8.12.2
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/FilterMultilevelDropdown.js +1 -1
- package/src/components/SelectedFilters.js +5 -5
- package/src/components/__tests__/AddMemberForm.spec.js +8 -9
- package/src/components/__tests__/ColoredEdge.spec.js +18 -10
- package/src/i18n/components/__tests__/EditableCell.spec.js +14 -3
- package/src/i18n/components/__tests__/__snapshots__/EditableCell.spec.js.snap +31 -19
- package/src/search/FilterMultilevelDropdown.js +1 -1
- package/src/search/__tests__/SearchContext.spec.js +16 -10
- package/src/search/__tests__/SearchWidget.spec.js +7 -0
- package/src/selectors/__tests__/makeActiveFiltersSelector.spec.js +20 -0
- package/src/selectors/__tests__/makeSearchQuerySelector.spec.js +38 -1
- package/src/selectors/makeActiveFiltersSelector.js +3 -6
- package/src/selectors/makeSearchQuerySelector.js +7 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "8.12.
|
|
3
|
+
"version": "8.12.2",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@testing-library/jest-dom": "^6.6.3",
|
|
58
58
|
"@testing-library/react": "^16.3.0",
|
|
59
59
|
"@testing-library/user-event": "^14.6.1",
|
|
60
|
-
"@truedat/test": "8.12.
|
|
60
|
+
"@truedat/test": "8.12.2",
|
|
61
61
|
"identity-obj-proxy": "^3.0.0",
|
|
62
62
|
"jest": "^29.7.0",
|
|
63
63
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
"swr": "^2.3.3",
|
|
100
100
|
"turndown": "^7.2.2"
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "b0000f1b2727cad43ce3c3eb2fa29681488dd2ec"
|
|
103
103
|
}
|
|
@@ -179,7 +179,7 @@ export const FilterMultilevelDropdown = ({
|
|
|
179
179
|
open={_.contains(option.id)(open)}
|
|
180
180
|
canOpen={_.negate(_.isEmpty)(option.children)}
|
|
181
181
|
selected={_.contains(option.id)(selected)}
|
|
182
|
-
{...option}
|
|
182
|
+
{..._.omit("key")(option)}
|
|
183
183
|
/>
|
|
184
184
|
))(filteredOptions)}
|
|
185
185
|
</Dropdown.Menu>
|
|
@@ -66,7 +66,6 @@ export const SelectedFilters = ({
|
|
|
66
66
|
const options = isSelectedFilter ? selectedFilterValues : null;
|
|
67
67
|
|
|
68
68
|
const props = {
|
|
69
|
-
key: filter,
|
|
70
69
|
activeValues,
|
|
71
70
|
closeFilter,
|
|
72
71
|
filter,
|
|
@@ -80,15 +79,16 @@ export const SelectedFilters = ({
|
|
|
80
79
|
switch (filterType) {
|
|
81
80
|
case "domain":
|
|
82
81
|
return useDomainSearchFilter ? (
|
|
83
|
-
<DomainSearchFilter {...props} />
|
|
82
|
+
<DomainSearchFilter key={filter} {...props} />
|
|
84
83
|
) : (
|
|
85
|
-
<FilterMultilevelDropdown {...props} />
|
|
84
|
+
<FilterMultilevelDropdown key={filter} {...props} />
|
|
86
85
|
);
|
|
87
86
|
case "hierarchy":
|
|
88
|
-
return <HierarchyFilterDropdown {...props} />;
|
|
87
|
+
return <HierarchyFilterDropdown key={filter} {...props} />;
|
|
89
88
|
case "search":
|
|
90
89
|
return (
|
|
91
90
|
<SearchFilterDropdown
|
|
91
|
+
key={filter}
|
|
92
92
|
{...props}
|
|
93
93
|
{...searchFiltersPropsMapping[filter]}
|
|
94
94
|
open={isSelectedFilter}
|
|
@@ -96,7 +96,7 @@ export const SelectedFilters = ({
|
|
|
96
96
|
/>
|
|
97
97
|
);
|
|
98
98
|
default:
|
|
99
|
-
return <FilterDropdown {...props} />;
|
|
99
|
+
return <FilterDropdown key={filter} {...props} />;
|
|
100
100
|
}
|
|
101
101
|
})}
|
|
102
102
|
<a className="resetFilters" onClick={() => resetFilters()}>
|
|
@@ -4,8 +4,6 @@ import { render, waitForLoad } from "@truedat/test/render";
|
|
|
4
4
|
import { apiJsonPost } from "@truedat/core/services/api";
|
|
5
5
|
import { AddMemberForm } from "../AddMemberForm";
|
|
6
6
|
|
|
7
|
-
const user = userEvent.setup({ delay: null });
|
|
8
|
-
|
|
9
7
|
jest.mock("@truedat/core/services/api", () => {
|
|
10
8
|
const originalModule = jest.requireActual("@truedat/core/services/api");
|
|
11
9
|
|
|
@@ -48,24 +46,23 @@ describe("<AddMemberForm />", () => {
|
|
|
48
46
|
});
|
|
49
47
|
|
|
50
48
|
it("calls onSuccess with acl data on submit correctly", async () => {
|
|
49
|
+
const user = userEvent.setup({ delay: null });
|
|
51
50
|
const rendered = render(<AddMemberForm {...props} />);
|
|
52
51
|
await waitForLoad(rendered);
|
|
53
52
|
|
|
54
53
|
// Submit button should initially be disabled
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
).toBeDisabled(),
|
|
59
|
-
);
|
|
54
|
+
expect(
|
|
55
|
+
rendered.getByRole("button", { name: /add_member/i }),
|
|
56
|
+
).toBeDisabled();
|
|
60
57
|
|
|
61
58
|
// Description
|
|
62
59
|
await user.click(await rendered.findByText(/john/i));
|
|
63
60
|
await user.click(await rendered.findByRole("option", { name: "role2" }));
|
|
64
61
|
|
|
65
62
|
// Submit button should now be enabled
|
|
66
|
-
await waitFor(
|
|
63
|
+
await waitFor(() =>
|
|
67
64
|
expect(
|
|
68
|
-
|
|
65
|
+
rendered.getByRole("button", { name: /add_member/i }),
|
|
69
66
|
).not.toBeDisabled(),
|
|
70
67
|
);
|
|
71
68
|
|
|
@@ -87,6 +84,7 @@ describe("<AddMemberForm />", () => {
|
|
|
87
84
|
});
|
|
88
85
|
|
|
89
86
|
it("displays group alias in dropdown when available", async () => {
|
|
87
|
+
const user = userEvent.setup({ delay: null });
|
|
90
88
|
const rendered = render(<AddMemberForm {...props} />);
|
|
91
89
|
await waitForLoad(rendered);
|
|
92
90
|
|
|
@@ -100,6 +98,7 @@ describe("<AddMemberForm />", () => {
|
|
|
100
98
|
});
|
|
101
99
|
|
|
102
100
|
it("displays group name when alias is not available", async () => {
|
|
101
|
+
const user = userEvent.setup({ delay: null });
|
|
103
102
|
const rendered = render(<AddMemberForm {...props} />);
|
|
104
103
|
await waitForLoad(rendered);
|
|
105
104
|
|
|
@@ -38,7 +38,9 @@ describe("<ColoredEdge /> metadata badge", () => {
|
|
|
38
38
|
const onClick = jest.fn();
|
|
39
39
|
const metadata = { source: "sales", relation: "derives" };
|
|
40
40
|
const rendered = render(
|
|
41
|
-
<
|
|
41
|
+
<svg>
|
|
42
|
+
<ColoredEdge {...baseProps} data={{ metadata, onClick }} />
|
|
43
|
+
</svg>,
|
|
42
44
|
);
|
|
43
45
|
const badge = rendered.container.querySelector(
|
|
44
46
|
".td-graph-edge-metadata-badge",
|
|
@@ -52,7 +54,9 @@ describe("<ColoredEdge /> metadata badge", () => {
|
|
|
52
54
|
it("does nothing when the edge has metadata but no click handler", () => {
|
|
53
55
|
const onClick = jest.fn();
|
|
54
56
|
const rendered = render(
|
|
55
|
-
<
|
|
57
|
+
<svg>
|
|
58
|
+
<ColoredEdge {...baseProps} data={{ metadata: { source: "sales" } }} />
|
|
59
|
+
</svg>,
|
|
56
60
|
);
|
|
57
61
|
const badge = rendered.container.querySelector(
|
|
58
62
|
".td-graph-edge-metadata-badge",
|
|
@@ -80,10 +84,12 @@ describe("<ColoredEdge /> arrow markers", () => {
|
|
|
80
84
|
|
|
81
85
|
it("draws the filled arrow at the target for impact edges", () => {
|
|
82
86
|
const rendered = render(
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
<svg>
|
|
88
|
+
<ColoredEdge
|
|
89
|
+
{...arrowProps}
|
|
90
|
+
data={{ edgePath: "orthogonal", markerPosition: "target" }}
|
|
91
|
+
/>
|
|
92
|
+
</svg>,
|
|
87
93
|
);
|
|
88
94
|
const arrow = rendered.container.querySelector(".td-graph-edge-arrow");
|
|
89
95
|
|
|
@@ -93,10 +99,12 @@ describe("<ColoredEdge /> arrow markers", () => {
|
|
|
93
99
|
|
|
94
100
|
it("draws the filled arrow at the source for traceability edges", () => {
|
|
95
101
|
const rendered = render(
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
<svg>
|
|
103
|
+
<ColoredEdge
|
|
104
|
+
{...arrowProps}
|
|
105
|
+
data={{ edgePath: "orthogonal", markerPosition: "source" }}
|
|
106
|
+
/>
|
|
107
|
+
</svg>,
|
|
100
108
|
);
|
|
101
109
|
const arrow = rendered.container.querySelector(".td-graph-edge-arrow");
|
|
102
110
|
|
|
@@ -7,6 +7,17 @@ describe("<EditableCell />", () => {
|
|
|
7
7
|
const onChange = jest.fn();
|
|
8
8
|
const value = "value";
|
|
9
9
|
const placeholder = "placeholder";
|
|
10
|
+
const renderCell = (props) =>
|
|
11
|
+
render(
|
|
12
|
+
<table>
|
|
13
|
+
<tbody>
|
|
14
|
+
<tr>
|
|
15
|
+
<EditableCell {...props} />
|
|
16
|
+
</tr>
|
|
17
|
+
</tbody>
|
|
18
|
+
</table>,
|
|
19
|
+
{ messages },
|
|
20
|
+
);
|
|
10
21
|
|
|
11
22
|
it("matches the latest snapshot", async () => {
|
|
12
23
|
const props = {
|
|
@@ -14,7 +25,7 @@ describe("<EditableCell />", () => {
|
|
|
14
25
|
value,
|
|
15
26
|
placeholder,
|
|
16
27
|
};
|
|
17
|
-
const rendered =
|
|
28
|
+
const rendered = renderCell(props);
|
|
18
29
|
await waitForLoad(rendered);
|
|
19
30
|
expect(rendered.container).toMatchSnapshot();
|
|
20
31
|
});
|
|
@@ -25,7 +36,7 @@ describe("<EditableCell />", () => {
|
|
|
25
36
|
value,
|
|
26
37
|
placeholder,
|
|
27
38
|
};
|
|
28
|
-
const rendered =
|
|
39
|
+
const rendered = renderCell(props);
|
|
29
40
|
await waitForLoad(rendered);
|
|
30
41
|
|
|
31
42
|
const user = userEvent.setup({ delay: null });
|
|
@@ -39,7 +50,7 @@ describe("<EditableCell />", () => {
|
|
|
39
50
|
value,
|
|
40
51
|
placeholder,
|
|
41
52
|
};
|
|
42
|
-
const rendered =
|
|
53
|
+
const rendered = renderCell(props);
|
|
43
54
|
await waitForLoad(rendered);
|
|
44
55
|
|
|
45
56
|
const user = userEvent.setup({ delay: null });
|
|
@@ -2,29 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`<EditableCell /> clicking the cell will enter edition mode and match snapshot 1`] = `
|
|
4
4
|
<div>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
<table>
|
|
6
|
+
<tbody>
|
|
7
|
+
<tr>
|
|
8
|
+
<td
|
|
9
|
+
class="five wide no-padding"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
class="ui fluid input"
|
|
13
|
+
>
|
|
14
|
+
<input
|
|
15
|
+
maxlength="255"
|
|
16
|
+
placeholder="placeholder"
|
|
17
|
+
type="text"
|
|
18
|
+
value="value"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
</td>
|
|
22
|
+
</tr>
|
|
23
|
+
</tbody>
|
|
24
|
+
</table>
|
|
19
25
|
</div>
|
|
20
26
|
`;
|
|
21
27
|
|
|
22
28
|
exports[`<EditableCell /> matches the latest snapshot 1`] = `
|
|
23
29
|
<div>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
<table>
|
|
31
|
+
<tbody>
|
|
32
|
+
<tr>
|
|
33
|
+
<td
|
|
34
|
+
class="five wide cursor-pointer"
|
|
35
|
+
>
|
|
36
|
+
value
|
|
37
|
+
</td>
|
|
38
|
+
</tr>
|
|
39
|
+
</tbody>
|
|
40
|
+
</table>
|
|
29
41
|
</div>
|
|
30
42
|
`;
|
|
@@ -185,7 +185,7 @@ export default function FilterMultilevelDropdown() {
|
|
|
185
185
|
open={_.contains(option.id)(open)}
|
|
186
186
|
canOpen={_.negate(_.isEmpty)(option.children)}
|
|
187
187
|
selected={_.contains(option.id)(selected)}
|
|
188
|
-
{...option}
|
|
188
|
+
{..._.omit("key")(option)}
|
|
189
189
|
/>
|
|
190
190
|
))(filteredOptions)}
|
|
191
191
|
</Dropdown.Menu>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { waitFor } from "@testing-library/react";
|
|
1
|
+
import { act, waitFor } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
3
|
import { render } from "@truedat/test/render";
|
|
4
4
|
import {
|
|
@@ -60,6 +60,12 @@ const renderOpts = {
|
|
|
60
60
|
},
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
const runAllTimers = async () => {
|
|
64
|
+
await act(async () => {
|
|
65
|
+
jest.runAllTimers();
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
|
|
63
69
|
describe("<SearchContextProvider />", () => {
|
|
64
70
|
const ChildComponent = () => <div>Child Component</div>;
|
|
65
71
|
const ContextConsumer = ({ onSearchChangeSpy }) => {
|
|
@@ -180,7 +186,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
180
186
|
renderOpts,
|
|
181
187
|
);
|
|
182
188
|
|
|
183
|
-
|
|
189
|
+
await runAllTimers();
|
|
184
190
|
|
|
185
191
|
expect(triggerFiltersSpy).toHaveBeenCalledWith(
|
|
186
192
|
expect.objectContaining({
|
|
@@ -215,7 +221,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
215
221
|
renderOpts,
|
|
216
222
|
);
|
|
217
223
|
|
|
218
|
-
|
|
224
|
+
await runAllTimers();
|
|
219
225
|
|
|
220
226
|
expect(triggerSearchSpy).toHaveBeenCalledWith(
|
|
221
227
|
expect.objectContaining({
|
|
@@ -253,7 +259,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
253
259
|
renderOpts,
|
|
254
260
|
);
|
|
255
261
|
|
|
256
|
-
|
|
262
|
+
await runAllTimers();
|
|
257
263
|
|
|
258
264
|
expect(triggerSearchSpy).toHaveBeenCalledWith(
|
|
259
265
|
expect.objectContaining({
|
|
@@ -302,7 +308,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
302
308
|
renderOpts,
|
|
303
309
|
);
|
|
304
310
|
|
|
305
|
-
|
|
311
|
+
await runAllTimers();
|
|
306
312
|
|
|
307
313
|
await waitFor(() =>
|
|
308
314
|
expect(
|
|
@@ -339,7 +345,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
339
345
|
renderOpts,
|
|
340
346
|
);
|
|
341
347
|
|
|
342
|
-
|
|
348
|
+
await runAllTimers();
|
|
343
349
|
|
|
344
350
|
await waitFor(() =>
|
|
345
351
|
expect(
|
|
@@ -363,7 +369,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
363
369
|
renderOpts,
|
|
364
370
|
);
|
|
365
371
|
|
|
366
|
-
|
|
372
|
+
await runAllTimers();
|
|
367
373
|
|
|
368
374
|
await user.click(rendered.getByText(/set-callback/i));
|
|
369
375
|
|
|
@@ -437,7 +443,7 @@ describe("<SearchContextProvider />", () => {
|
|
|
437
443
|
renderOpts,
|
|
438
444
|
);
|
|
439
445
|
|
|
440
|
-
|
|
446
|
+
await runAllTimers();
|
|
441
447
|
|
|
442
448
|
await user.click(rendered.getByText(/set-callback/i));
|
|
443
449
|
await user.click(rendered.getByText(/sort-empty/i));
|
|
@@ -536,14 +542,14 @@ describe("<SearchContextProvider />", () => {
|
|
|
536
542
|
renderOpts,
|
|
537
543
|
);
|
|
538
544
|
|
|
539
|
-
|
|
545
|
+
await runAllTimers();
|
|
540
546
|
|
|
541
547
|
expect(triggerSearchSpy).toHaveBeenCalledTimes(1);
|
|
542
548
|
const firstCallArgs = triggerSearchSpy.mock.calls[0][0];
|
|
543
549
|
|
|
544
550
|
await user.click(rendered.getByText(/refresh/i));
|
|
545
551
|
|
|
546
|
-
|
|
552
|
+
await runAllTimers();
|
|
547
553
|
|
|
548
554
|
expect(triggerSearchSpy).toHaveBeenCalledTimes(2);
|
|
549
555
|
expect(triggerSearchSpy).toHaveBeenLastCalledWith(
|
|
@@ -3,8 +3,14 @@ import { render } from "@truedat/test/render";
|
|
|
3
3
|
import { waitFor } from "@testing-library/react";
|
|
4
4
|
import userEvent from "@testing-library/user-event";
|
|
5
5
|
import SearchContextWrapper from "@truedat/core/components/common/SearchContextWrapper";
|
|
6
|
+
import { useUserFilters } from "@truedat/core/hooks/useUserFilters";
|
|
6
7
|
import SearchWidget from "../SearchWidget";
|
|
7
8
|
|
|
9
|
+
jest.mock("@truedat/core/hooks/useUserFilters", () => ({
|
|
10
|
+
...jest.requireActual("@truedat/core/hooks/useUserFilters"),
|
|
11
|
+
useUserFilters: jest.fn(() => ({ userFilters: [], loading: false })),
|
|
12
|
+
}));
|
|
13
|
+
|
|
8
14
|
const messages = {
|
|
9
15
|
en: {
|
|
10
16
|
"search.placeholder": "Search...",
|
|
@@ -40,6 +46,7 @@ describe("<SearchWidget/>", () => {
|
|
|
40
46
|
</SearchContextWrapper>,
|
|
41
47
|
renderOpts,
|
|
42
48
|
);
|
|
49
|
+
expect(useUserFilters).toHaveBeenCalledWith("foo", undefined);
|
|
43
50
|
expect(container).toMatchSnapshot();
|
|
44
51
|
});
|
|
45
52
|
|
|
@@ -18,4 +18,24 @@ describe("selectors: makeActiveFiltersSelector", () => {
|
|
|
18
18
|
makeActiveFiltersSelector("conceptActiveFilters")(state, props),
|
|
19
19
|
).toEqual({ foo: "bar", status: ["pending"] });
|
|
20
20
|
});
|
|
21
|
+
|
|
22
|
+
it("keeps the same result for equal filters and updates it when filters change", () => {
|
|
23
|
+
const selector = makeActiveFiltersSelector("conceptActiveFilters");
|
|
24
|
+
const first = selector(
|
|
25
|
+
{ conceptActiveFilters: { foo: "bar" } },
|
|
26
|
+
{ defaultFilters: { status: ["pending"] } },
|
|
27
|
+
);
|
|
28
|
+
const equal = selector(
|
|
29
|
+
{ conceptActiveFilters: { foo: "bar" } },
|
|
30
|
+
{ defaultFilters: { status: ["pending"] } },
|
|
31
|
+
);
|
|
32
|
+
const changed = selector(
|
|
33
|
+
{ conceptActiveFilters: { foo: "baz" } },
|
|
34
|
+
{ defaultFilters: { status: ["pending"] } },
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
expect(equal).toBe(first);
|
|
38
|
+
expect(changed).not.toBe(first);
|
|
39
|
+
expect(changed).toEqual({ foo: "baz", status: ["pending"] });
|
|
40
|
+
});
|
|
21
41
|
});
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
makeSearchQuerySelector,
|
|
3
|
+
queryPropsSelector,
|
|
4
|
+
} from "../makeSearchQuerySelector";
|
|
2
5
|
|
|
3
6
|
const searchQuerySelector = makeSearchQuerySelector(
|
|
4
7
|
"conceptQuery",
|
|
@@ -7,6 +10,40 @@ const searchQuerySelector = makeSearchQuerySelector(
|
|
|
7
10
|
);
|
|
8
11
|
|
|
9
12
|
describe("selectors: makeSearchQuerySelector", () => {
|
|
13
|
+
it("keeps equal query props referentially stable", () => {
|
|
14
|
+
const first = queryPropsSelector({}, { pageSize: 10, ignored: "first" });
|
|
15
|
+
const equal = queryPropsSelector({}, { pageSize: 10, ignored: "second" });
|
|
16
|
+
const changed = queryPropsSelector({}, { pageSize: 20 });
|
|
17
|
+
|
|
18
|
+
expect(equal).toBe(first);
|
|
19
|
+
expect(changed).not.toBe(first);
|
|
20
|
+
expect(changed).toEqual({ pageSize: 20 });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("keeps equal search payloads referentially stable", () => {
|
|
24
|
+
const selector = makeSearchQuerySelector(
|
|
25
|
+
"conceptQuery",
|
|
26
|
+
"conceptActiveFilters",
|
|
27
|
+
"dateFilter",
|
|
28
|
+
);
|
|
29
|
+
const first = selector({
|
|
30
|
+
conceptQuery: { query: "foo" },
|
|
31
|
+
conceptActiveFilters: { status: ["draft"] },
|
|
32
|
+
});
|
|
33
|
+
const equal = selector({
|
|
34
|
+
conceptQuery: { query: "foo" },
|
|
35
|
+
conceptActiveFilters: { status: ["draft"] },
|
|
36
|
+
});
|
|
37
|
+
const changed = selector({
|
|
38
|
+
conceptQuery: { query: "bar" },
|
|
39
|
+
conceptActiveFilters: { status: ["draft"] },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(equal).toBe(first);
|
|
43
|
+
expect(changed).not.toBe(first);
|
|
44
|
+
expect(changed).toMatchObject({ query: "bar" });
|
|
45
|
+
});
|
|
46
|
+
|
|
10
47
|
describe("with an empty query string", () => {
|
|
11
48
|
const conceptQuery = { query: " " };
|
|
12
49
|
const conceptActiveFilters = { foo: ["foo1"], bar: [] };
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import { createSelector,
|
|
2
|
+
import { createSelector, lruMemoize } from "reselect";
|
|
3
3
|
|
|
4
4
|
const defaultFilters = false;
|
|
5
5
|
|
|
6
6
|
export const makeActiveFiltersSelector = (activeFiltersProp) => {
|
|
7
|
-
|
|
7
|
+
return createSelector(
|
|
8
8
|
_.prop(activeFiltersProp),
|
|
9
9
|
(_state, props) => _.propOr(defaultFilters, "defaultFilters")(props),
|
|
10
10
|
(activeFilters, defaultFilters) =>
|
|
11
11
|
defaultFilters ? { ...defaultFilters, ...activeFilters } : activeFilters,
|
|
12
|
-
|
|
13
|
-
return createSelectorCreator(lruMemoize, _.isEqual)(
|
|
14
|
-
activeFiltersSelector,
|
|
15
|
-
_.identity,
|
|
12
|
+
{ memoize: lruMemoize, memoizeOptions: { resultEqualityCheck: _.isEqual } },
|
|
16
13
|
);
|
|
17
14
|
};
|
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
identity,
|
|
3
|
-
isEmpty,
|
|
4
|
-
isEqual,
|
|
5
|
-
mapKeys,
|
|
6
|
-
omitBy,
|
|
7
|
-
pick,
|
|
8
|
-
prop,
|
|
9
|
-
trim,
|
|
10
|
-
} from "lodash/fp";
|
|
1
|
+
import { isEmpty, isEqual, mapKeys, omitBy, pick, prop, trim } from "lodash/fp";
|
|
11
2
|
import { createSelector, createSelectorCreator, lruMemoize } from "reselect";
|
|
12
3
|
import { getSearchPayload } from "../services/filters";
|
|
13
4
|
import { makeDateFiltersSelector } from "./makeDateFiltersSelector";
|
|
14
5
|
|
|
15
|
-
export const queryPropsSelector =
|
|
16
|
-
(_state, props) =>
|
|
17
|
-
|
|
6
|
+
export const queryPropsSelector = createSelector(
|
|
7
|
+
(_state, props) => props,
|
|
8
|
+
(props) => pick(["defaultFilters", "linkable", "pageSize"])(props),
|
|
9
|
+
{ memoize: lruMemoize, memoizeOptions: { resultEqualityCheck: isEqual } },
|
|
18
10
|
);
|
|
19
11
|
|
|
20
12
|
export const makeSearchFiltersSelector = (activeFiltersProp, dateFilterProp) =>
|
|
@@ -38,7 +30,7 @@ export const makeSearchQuerySelector = (
|
|
|
38
30
|
activeFiltersProp,
|
|
39
31
|
dateFilterProp,
|
|
40
32
|
);
|
|
41
|
-
|
|
33
|
+
return createSelector(
|
|
42
34
|
prop(queryProp),
|
|
43
35
|
searchFiltersSelector,
|
|
44
36
|
queryPropsSelector,
|
|
@@ -61,9 +53,6 @@ export const makeSearchQuerySelector = (
|
|
|
61
53
|
: { must: filters, page: page - 1, sort: sort };
|
|
62
54
|
return getSearchPayload(q, ownProps);
|
|
63
55
|
},
|
|
64
|
-
|
|
65
|
-
return createSelectorCreator(lruMemoize, isEqual)(
|
|
66
|
-
searchQuerySelector,
|
|
67
|
-
identity,
|
|
56
|
+
{ memoize: lruMemoize, memoizeOptions: { resultEqualityCheck: isEqual } },
|
|
68
57
|
);
|
|
69
58
|
};
|