@truedat/core 8.11.0 → 8.11.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/GlossaryMenu.js +0 -2
- package/src/components/SideMenu.js +2 -0
- package/src/components/__tests__/GlossaryMenu.spec.js +17 -0
- package/src/components/__tests__/SideMenu.spec.js +60 -0
- package/src/search/SearchContext.js +5 -0
- package/src/search/__tests__/SearchContext.spec.js +48 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "8.11.
|
|
3
|
+
"version": "8.11.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.11.
|
|
60
|
+
"@truedat/test": "8.11.2",
|
|
61
61
|
"identity-obj-proxy": "^3.0.0",
|
|
62
62
|
"jest": "^29.7.0",
|
|
63
63
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -98,5 +98,5 @@
|
|
|
98
98
|
"swr": "^2.3.3",
|
|
99
99
|
"turndown": "^7.2.2"
|
|
100
100
|
},
|
|
101
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "5c0ce3c555de4c9e89021b4d0ab785ed27a87305"
|
|
102
102
|
}
|
|
@@ -8,7 +8,6 @@ import { linkTo } from "@truedat/core/routes";
|
|
|
8
8
|
import { makeGetSubscopes } from "@truedat/core/selectors/subscopedTemplates";
|
|
9
9
|
import { getConceptSubscope } from "@truedat/core/selectors/getConceptSubscope";
|
|
10
10
|
import { getSidemenuGlossarySubscopes } from "@truedat/core/selectors/getSidemenuGlossarySubscopes";
|
|
11
|
-
import TemplatesLoader from "@truedat/core/components/TemplatesLoader";
|
|
12
11
|
import { useAuthorized } from "../hooks";
|
|
13
12
|
import {
|
|
14
13
|
CONCEPTS,
|
|
@@ -270,7 +269,6 @@ export const GlossaryMenu = ({ bgSubscopes, rootSubscopes }) => {
|
|
|
270
269
|
|
|
271
270
|
return (
|
|
272
271
|
<>
|
|
273
|
-
<TemplatesLoader />
|
|
274
272
|
<Submenu
|
|
275
273
|
icon={defaultIcon}
|
|
276
274
|
name="glossary"
|
|
@@ -14,6 +14,7 @@ import SidebarToggle from "./SidebarToggle";
|
|
|
14
14
|
import TaxonomyMenu from "./TaxonomyMenu";
|
|
15
15
|
import GrantMenu from "./GrantMenu";
|
|
16
16
|
import MembersMenu from "./MembersMenu";
|
|
17
|
+
import TemplatesLoader from "./TemplatesLoader";
|
|
17
18
|
|
|
18
19
|
export const SideMenu = ({
|
|
19
20
|
animation = "push",
|
|
@@ -35,6 +36,7 @@ export const SideMenu = ({
|
|
|
35
36
|
animation={animation}
|
|
36
37
|
>
|
|
37
38
|
<SearchMenu />
|
|
39
|
+
<TemplatesLoader />
|
|
38
40
|
<GlossaryMenu />
|
|
39
41
|
<CatalogMenu />
|
|
40
42
|
<GrantMenu />
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { render } from "@truedat/test/render";
|
|
2
|
+
import { fetchTemplates } from "@truedat/core/routines";
|
|
2
3
|
import GlossaryMenu from "../GlossaryMenu";
|
|
3
4
|
|
|
4
5
|
jest.mock("../../hooks", () => ({
|
|
@@ -77,4 +78,20 @@ describe("<GlossaryMenu />", () => {
|
|
|
77
78
|
expect(queryByRole("option", { name: "subscope1" })).toBeInTheDocument();
|
|
78
79
|
expect(queryByRole("option", { name: "subscope2" })).toBeInTheDocument();
|
|
79
80
|
});
|
|
81
|
+
|
|
82
|
+
it("does not dispatch fetchTemplates on mount (templates preload moved to SideMenu)", () => {
|
|
83
|
+
const dispatched = [];
|
|
84
|
+
render(<GlossaryMenu />, {
|
|
85
|
+
...renderOpts,
|
|
86
|
+
dispatch: jest.fn((action) => {
|
|
87
|
+
dispatched.push(action);
|
|
88
|
+
return action;
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const fetchTemplatesCalls = dispatched.filter(
|
|
93
|
+
(action) => action && action.type === fetchTemplates.TRIGGER,
|
|
94
|
+
);
|
|
95
|
+
expect(fetchTemplatesCalls).toHaveLength(0);
|
|
96
|
+
});
|
|
80
97
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { render, waitForLoad } from "@truedat/test/render";
|
|
2
2
|
import { CATALOG_VIEW_CONFIGS_QUERY } from "@truedat/core/api/queries";
|
|
3
|
+
import { fetchTemplates } from "@truedat/core/routines";
|
|
3
4
|
import SideMenu from "../SideMenu";
|
|
4
5
|
|
|
5
6
|
jest.mock("@truedat/core/hooks", () => ({
|
|
@@ -46,4 +47,63 @@ describe("<SideMenu />", () => {
|
|
|
46
47
|
await waitForLoad(rendered);
|
|
47
48
|
expect(rendered.container).toMatchSnapshot();
|
|
48
49
|
});
|
|
50
|
+
|
|
51
|
+
describe("global templates preload", () => {
|
|
52
|
+
let dispatched;
|
|
53
|
+
let useAuthorizedMock;
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
dispatched = [];
|
|
57
|
+
useAuthorizedMock = require("@truedat/core/hooks").useAuthorized;
|
|
58
|
+
useAuthorizedMock.mockReturnValue(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const renderWithDispatch = () =>
|
|
62
|
+
render(
|
|
63
|
+
<SideMenu>
|
|
64
|
+
<p>Hello</p>
|
|
65
|
+
</SideMenu>,
|
|
66
|
+
{
|
|
67
|
+
...renderOpts,
|
|
68
|
+
dispatch: jest.fn((action) => {
|
|
69
|
+
dispatched.push(action);
|
|
70
|
+
return action;
|
|
71
|
+
}),
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
it("dispatches fetchTemplates with no scope on mount", async () => {
|
|
76
|
+
const rendered = renderWithDispatch();
|
|
77
|
+
await waitForLoad(rendered);
|
|
78
|
+
expect(dispatched).toContainEqual(
|
|
79
|
+
expect.objectContaining({
|
|
80
|
+
type: fetchTemplates.TRIGGER,
|
|
81
|
+
payload: { scope: undefined },
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("dispatches fetchTemplates even when user lacks business_glossary_view", async () => {
|
|
87
|
+
useAuthorizedMock.mockImplementation((allowedRoles) => {
|
|
88
|
+
const roles = Array.isArray(allowedRoles)
|
|
89
|
+
? allowedRoles
|
|
90
|
+
: [allowedRoles];
|
|
91
|
+
// Deny business_glossary_view/management but allow everything else.
|
|
92
|
+
const blocked = new Set([
|
|
93
|
+
"business_glossary_view",
|
|
94
|
+
"business_glossary_management",
|
|
95
|
+
]);
|
|
96
|
+
return roles.some((r) => r && !blocked.has(r));
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const rendered = renderWithDispatch();
|
|
100
|
+
await waitForLoad(rendered);
|
|
101
|
+
expect(dispatched).toContainEqual(
|
|
102
|
+
expect.objectContaining({
|
|
103
|
+
type: fetchTemplates.TRIGGER,
|
|
104
|
+
payload: { scope: undefined },
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
49
109
|
});
|
|
@@ -64,6 +64,9 @@ export const SearchContextProvider = (props) => {
|
|
|
64
64
|
const [count, setCount] = useState(0);
|
|
65
65
|
|
|
66
66
|
const [onSearchChange, setOnSearchChange] = useState();
|
|
67
|
+
const [refreshCounter, refreshToken] = useState(0);
|
|
68
|
+
|
|
69
|
+
const refreshSearch = useCallback(() => refreshToken((c) => c + 1), []);
|
|
67
70
|
|
|
68
71
|
const debouncedTriggerSearch = useCallback(
|
|
69
72
|
_.debounce(debounceQueryTime)((filterParam) => {
|
|
@@ -270,6 +273,7 @@ export const SearchContextProvider = (props) => {
|
|
|
270
273
|
page,
|
|
271
274
|
size,
|
|
272
275
|
enrichSearchPayload,
|
|
276
|
+
refreshCounter,
|
|
273
277
|
]);
|
|
274
278
|
|
|
275
279
|
const mapDomainFilterKey = (key) => {
|
|
@@ -410,6 +414,7 @@ export const SearchContextProvider = (props) => {
|
|
|
410
414
|
searchFiltersPropsMapping,
|
|
411
415
|
|
|
412
416
|
setOnSearchChange,
|
|
417
|
+
refreshSearch,
|
|
413
418
|
};
|
|
414
419
|
|
|
415
420
|
return <SearchContext value={context}>{children}</SearchContext>;
|
|
@@ -508,4 +508,52 @@ describe("<SearchContextProvider />", () => {
|
|
|
508
508
|
|
|
509
509
|
jest.useRealTimers();
|
|
510
510
|
});
|
|
511
|
+
|
|
512
|
+
it("re-executes the search when refreshSearch is called", async () => {
|
|
513
|
+
jest.useFakeTimers();
|
|
514
|
+
const user = userEvent.setup({
|
|
515
|
+
delay: null,
|
|
516
|
+
advanceTimers: jest.advanceTimersByTime,
|
|
517
|
+
});
|
|
518
|
+
const triggerSearchSpy = jest.fn().mockReturnValue({
|
|
519
|
+
then: (callback) =>
|
|
520
|
+
callback({
|
|
521
|
+
data,
|
|
522
|
+
headers: {},
|
|
523
|
+
}),
|
|
524
|
+
});
|
|
525
|
+
const useSearchLocal = () => ({ trigger: triggerSearchSpy });
|
|
526
|
+
|
|
527
|
+
const RefreshConsumer = () => {
|
|
528
|
+
const { refreshSearch } = useSearchContext();
|
|
529
|
+
return <button onClick={() => refreshSearch()}>refresh</button>;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const rendered = render(
|
|
533
|
+
<SearchContextProvider {...searchProps} useSearch={useSearchLocal}>
|
|
534
|
+
<RefreshConsumer />
|
|
535
|
+
</SearchContextProvider>,
|
|
536
|
+
renderOpts,
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
jest.runAllTimers();
|
|
540
|
+
|
|
541
|
+
expect(triggerSearchSpy).toHaveBeenCalledTimes(1);
|
|
542
|
+
const firstCallArgs = triggerSearchSpy.mock.calls[0][0];
|
|
543
|
+
|
|
544
|
+
await user.click(rendered.getByText(/refresh/i));
|
|
545
|
+
|
|
546
|
+
jest.runAllTimers();
|
|
547
|
+
|
|
548
|
+
expect(triggerSearchSpy).toHaveBeenCalledTimes(2);
|
|
549
|
+
expect(triggerSearchSpy).toHaveBeenLastCalledWith(
|
|
550
|
+
expect.objectContaining({
|
|
551
|
+
must: firstCallArgs.must,
|
|
552
|
+
page: firstCallArgs.page,
|
|
553
|
+
size: firstCallArgs.size,
|
|
554
|
+
}),
|
|
555
|
+
);
|
|
556
|
+
|
|
557
|
+
jest.useRealTimers();
|
|
558
|
+
});
|
|
511
559
|
});
|