orc-shared 5.4.0-dev.0 → 5.5.1-dev.0
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/dist/actions/navigation.js +14 -1
- package/dist/actions/tasks.js +170 -0
- package/dist/buildStore.js +3 -1
- package/dist/components/AppFrame/Sidebar.js +4 -8
- package/dist/components/MaterialUI/DataDisplay/PredefinedElements/InformationItem.js +13 -5
- package/dist/components/MaterialUI/DataDisplay/TooltippedElements/MultipleLinesText.js +4 -2
- package/dist/components/MaterialUI/Inputs/PredefinedElements/SearchControl.js +43 -46
- package/dist/components/MaterialUI/hocs/withDeferredTooltip.js +3 -1
- package/dist/components/Routing/Page.js +4 -1
- package/dist/components/Routing/SegmentPage.js +4 -1
- package/dist/components/Routing/SubPage.js +21 -8
- package/dist/components/TaskDetailsModal.js +191 -0
- package/dist/constants.js +18 -2
- package/dist/content/iconsSheet.svg +22 -0
- package/dist/content/orckestra-logo-white.png +0 -0
- package/dist/hooks/useEditState.js +4 -2
- package/dist/reducers/navigation.js +16 -0
- package/dist/reducers/request.js +4 -0
- package/dist/reducers/tasks.js +98 -0
- package/dist/selectors/authentication.js +15 -1
- package/dist/selectors/tasks.js +64 -0
- package/dist/sharedMessages.js +17 -1
- package/dist/utils/propertyHelper.js +33 -0
- package/package.json +1 -1
- package/src/actions/navigation.js +7 -0
- package/src/actions/navigation.test.js +12 -0
- package/src/actions/tasks.js +77 -0
- package/src/actions/tasks.test.js +169 -0
- package/src/buildStore.js +2 -0
- package/src/components/AppFrame/About.test.js +3 -3
- package/src/components/AppFrame/Sidebar.js +4 -3
- package/src/components/MaterialUI/DataDisplay/PredefinedElements/InformationItem.js +15 -3
- package/src/components/MaterialUI/DataDisplay/TooltippedElements/MultipleLinesText.js +2 -1
- package/src/components/MaterialUI/Inputs/PredefinedElements/SearchControl.js +39 -27
- package/src/components/MaterialUI/Inputs/PredefinedElements/SearchControl.test.js +39 -34
- package/src/components/MaterialUI/hocs/withDeferredTooltip.js +2 -1
- package/src/components/MaterialUI/hocs/withDeferredTooltip.test.js +52 -0
- package/src/components/Routing/Page.js +12 -1
- package/src/components/Routing/SegmentPage.js +12 -1
- package/src/components/Routing/SubPage.js +21 -9
- package/src/components/Routing/SubPage.test.js +213 -0
- package/src/components/TaskDetailsModal.js +132 -0
- package/src/components/TaskDetailsModal.test.js +317 -0
- package/src/components/Text.test.js +44 -59
- package/src/constants.js +15 -0
- package/src/content/iconsSheet.svg +22 -0
- package/src/content/orckestra-logo-white.png +0 -0
- package/src/hooks/useEditState.js +12 -2
- package/src/hooks/useEditState.test.js +1 -1
- package/src/hooks/useLabelMessage.test.js +16 -10
- package/src/reducers/navigation.js +24 -0
- package/src/reducers/navigation.test.js +38 -0
- package/src/reducers/request.js +4 -0
- package/src/reducers/request.test.js +11 -0
- package/src/reducers/tasks.js +56 -0
- package/src/reducers/tasks.test.js +404 -0
- package/src/selectors/authentication.js +13 -0
- package/src/selectors/authentication.test.js +322 -0
- package/src/selectors/tasks.js +16 -0
- package/src/selectors/tasks.test.js +60 -0
- package/src/sharedMessages.js +17 -1
- package/src/translations/en-US.json +16 -12
- package/src/translations/fr-CA.json +16 -12
- package/src/utils/propertyHelper.js +38 -0
- package/src/utils/propertyHelper.test.js +160 -0
- package/src/utils/timezoneHelper.test.js +4 -2
|
@@ -25,6 +25,13 @@ export const removeTab = (module, path) => ({
|
|
|
25
25
|
payload: { module, path },
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
export const REMOVE_MODULE_TABS = "REMOVE_MODULE_TABS";
|
|
29
|
+
|
|
30
|
+
export const removeModuleTabs = module => ({
|
|
31
|
+
type: REMOVE_MODULE_TABS,
|
|
32
|
+
payload: { module },
|
|
33
|
+
});
|
|
34
|
+
|
|
28
35
|
export const SET_HREF_CONFIG = "SET_HREF_CONFIG";
|
|
29
36
|
|
|
30
37
|
export const setHrefConfig = (prependPath, prependHref, otherConfigs = {}) => ({
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
SET_HREF_CONFIG,
|
|
6
6
|
setClosingTabHandlerActions,
|
|
7
7
|
SET_CLOSING_TAB_HANDLER_ACTIONS,
|
|
8
|
+
removeModuleTabs,
|
|
9
|
+
REMOVE_MODULE_TABS,
|
|
8
10
|
} from "./navigation";
|
|
9
11
|
|
|
10
12
|
describe("removeTab", () => {
|
|
@@ -18,6 +20,16 @@ describe("removeTab", () => {
|
|
|
18
20
|
}));
|
|
19
21
|
});
|
|
20
22
|
|
|
23
|
+
describe("removeModuleTabs", () => {
|
|
24
|
+
it("creates a remove module tabs action", () =>
|
|
25
|
+
expect(removeModuleTabs, "when called with", ["module"], "to equal", {
|
|
26
|
+
type: REMOVE_MODULE_TABS,
|
|
27
|
+
payload: {
|
|
28
|
+
module: "module",
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
});
|
|
32
|
+
|
|
21
33
|
describe("setHrefConfig", () => {
|
|
22
34
|
it("set href config action", () =>
|
|
23
35
|
expect(setHrefConfig, "when called with", ["/:scope/", "/scope/"], "to equal", {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { makeActionTypes } from "./makeApiAction";
|
|
2
|
+
import makeOrcApiAction from "./makeOrcApiAction";
|
|
3
|
+
import {
|
|
4
|
+
deleteTaskInfoRequest,
|
|
5
|
+
getRequesterTasksInfoRequest,
|
|
6
|
+
getTaskExecutionLogsRequest,
|
|
7
|
+
getTaskInfoRequest,
|
|
8
|
+
} from "./requestsApi";
|
|
9
|
+
|
|
10
|
+
const GET_TASKINFO = "GET_TASKINFO";
|
|
11
|
+
|
|
12
|
+
export const [GET_TASKINFO_REQUEST, GET_TASKINFO_SUCCESS, GET_TASKINFO_FAILURE] = makeActionTypes(GET_TASKINFO);
|
|
13
|
+
|
|
14
|
+
export const getTaskInfo = taskId => makeOrcApiAction(GET_TASKINFO, getTaskInfoRequest.buildUrl(taskId));
|
|
15
|
+
|
|
16
|
+
export const GET_TASK_LIST = "GET_TASK_LIST";
|
|
17
|
+
|
|
18
|
+
export const ssrsDownloadFilterTaskNames = [
|
|
19
|
+
"Orckestra.Overture.Providers.CommerceEngine.Profiles.ProfileSchemaExportTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
20
|
+
"Orckestra.Overture.Providers.CommerceEngine.Profiles.ProfileSchemaImportTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
21
|
+
"Orckestra.Overture.Providers.CommerceEngine.Orders.ExportOrderSchemaTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
22
|
+
"Orckestra.Overture.Providers.CommerceEngine.Orders.ImportOrderSchemaTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
23
|
+
"Orckestra.Overture.Providers.CommerceEngine.Products.ImportExport.ExportProductsTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
24
|
+
"Orckestra.Overture.Providers.CommerceEngine.Products.ImportExport.ProductSchemaExportTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
25
|
+
"Orckestra.Overture.Providers.CommerceEngine.Products.ImportExport.ImportProductsTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
26
|
+
"OrckestraCommerce.DataExchange.Product.Tasks.ProductExportTask, OrckestraCommerce.DataExchange",
|
|
27
|
+
"Orckestra.Overture.Providers.CommerceEngine.Marketing.ExportCouponCodesTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
28
|
+
"Orckestra.Overture.Providers.CommerceEngine.Marketing.ImportCouponCodesTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
29
|
+
"Orckestra.Overture.Providers.CommerceEngine.Marketing.GenerateCouponTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
30
|
+
"Orckestra.Overture.Providers.CommerceEngine.Reporting.ReportExportTask, Orckestra.Overture.Providers.CommerceEngine",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export const [GET_TASK_LIST_REQUEST, GET_TASK_LIST_SUCCESS, GET_TASK_LIST_FAILURE] = makeActionTypes(GET_TASK_LIST);
|
|
34
|
+
|
|
35
|
+
export const getTaskList = (requester, filterTaskNames, lastModified = null, addToActiveRequests = true) =>
|
|
36
|
+
makeOrcApiAction(
|
|
37
|
+
GET_TASK_LIST,
|
|
38
|
+
getRequesterTasksInfoRequest.buildUrl({
|
|
39
|
+
filterTaskNames: filterTaskNames,
|
|
40
|
+
requester: requester,
|
|
41
|
+
lastModified: lastModified,
|
|
42
|
+
}),
|
|
43
|
+
getRequesterTasksInfoRequest.verb,
|
|
44
|
+
{
|
|
45
|
+
meta: {
|
|
46
|
+
addToActiveRequests,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const DELETE_TASK = "DELETE_TASK";
|
|
52
|
+
|
|
53
|
+
export const [DELETE_TASK_REQUEST, DELETE_TASK_SUCCESS, DELETE_TASK_FAILURE] = makeActionTypes(DELETE_TASK);
|
|
54
|
+
|
|
55
|
+
export const deleteTask = taskId =>
|
|
56
|
+
makeOrcApiAction(DELETE_TASK, deleteTaskInfoRequest.buildUrl(taskId), deleteTaskInfoRequest.verb, {
|
|
57
|
+
meta: { taskId },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const GET_TASK_LOG = "GET_TASK_LOG";
|
|
61
|
+
|
|
62
|
+
export const [GET_TASK_LOG_REQUEST, GET_TASK_LOG_SUCCESS, GET_TASK_LOG_FAILURE] = makeActionTypes(GET_TASK_LOG);
|
|
63
|
+
|
|
64
|
+
export const getTaskLog = (taskId, addToActiveRequests = true) =>
|
|
65
|
+
makeOrcApiAction(GET_TASK_LOG, getTaskExecutionLogsRequest.buildUrl(taskId), getTaskExecutionLogsRequest.verb, {
|
|
66
|
+
meta: {
|
|
67
|
+
taskId,
|
|
68
|
+
addToActiveRequests,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const CLEAR_TASK_LOG = "CLEAR_TASK_LOG";
|
|
73
|
+
|
|
74
|
+
export const clearTaskLog = taskId => ({
|
|
75
|
+
type: CLEAR_TASK_LOG,
|
|
76
|
+
meta: { taskId },
|
|
77
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { RSAA } from "redux-api-middleware";
|
|
2
|
+
import {
|
|
3
|
+
GET_TASKINFO_REQUEST,
|
|
4
|
+
GET_TASKINFO_SUCCESS,
|
|
5
|
+
GET_TASKINFO_FAILURE,
|
|
6
|
+
getTaskInfo,
|
|
7
|
+
getTaskList,
|
|
8
|
+
getTaskLog,
|
|
9
|
+
ssrsDownloadFilterTaskNames,
|
|
10
|
+
deleteTask,
|
|
11
|
+
} from "./tasks";
|
|
12
|
+
|
|
13
|
+
jest.mock("../utils/buildUrl", () => {
|
|
14
|
+
const modExport = {};
|
|
15
|
+
modExport.loadConfig = () => Promise.resolve({});
|
|
16
|
+
modExport.buildUrl = (path = [], params = "") => "URL: " + path.join("/") + " " + JSON.stringify(params);
|
|
17
|
+
return modExport;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("getTaskInfo", () => {
|
|
21
|
+
it("creates a RSAA to get task info", () =>
|
|
22
|
+
expect(getTaskInfo, "when called with", ["1234"], "to exhaustively satisfy", {
|
|
23
|
+
[RSAA]: {
|
|
24
|
+
types: [GET_TASKINFO_REQUEST, GET_TASKINFO_SUCCESS, GET_TASKINFO_FAILURE],
|
|
25
|
+
endpoint: 'URL: tasks/1234 ""',
|
|
26
|
+
method: "GET",
|
|
27
|
+
body: undefined,
|
|
28
|
+
credentials: "include",
|
|
29
|
+
bailout: expect.it("to be a function"),
|
|
30
|
+
headers: {
|
|
31
|
+
Accept: "application/json; charset=utf-8",
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
},
|
|
34
|
+
options: { redirect: "follow" },
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("getTaskLog", () => {
|
|
40
|
+
it("creates a RSAA to get task info", () =>
|
|
41
|
+
expect(getTaskLog, "when called with", ["1234"], "to exhaustively satisfy", {
|
|
42
|
+
[RSAA]: {
|
|
43
|
+
types: [
|
|
44
|
+
{ type: "GET_TASK_LOG_REQUEST", meta: { taskId: "1234", addToActiveRequests: true } },
|
|
45
|
+
{ type: "GET_TASK_LOG_SUCCESS", meta: { taskId: "1234", addToActiveRequests: true } },
|
|
46
|
+
{ type: "GET_TASK_LOG_FAILURE", meta: { taskId: "1234", addToActiveRequests: true } },
|
|
47
|
+
],
|
|
48
|
+
endpoint: 'URL: tasks/1234/logs ""',
|
|
49
|
+
method: "GET",
|
|
50
|
+
body: undefined,
|
|
51
|
+
credentials: "include",
|
|
52
|
+
bailout: expect.it("to be a function"),
|
|
53
|
+
headers: {
|
|
54
|
+
Accept: "application/json; charset=utf-8",
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
},
|
|
57
|
+
options: { redirect: "follow" },
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
it("creates a RSAA to get task info with addToActiveRequests false", () =>
|
|
62
|
+
expect(getTaskLog, "when called with", ["1234", false], "to exhaustively satisfy", {
|
|
63
|
+
[RSAA]: {
|
|
64
|
+
types: [
|
|
65
|
+
{ type: "GET_TASK_LOG_REQUEST", meta: { taskId: "1234", addToActiveRequests: false } },
|
|
66
|
+
{ type: "GET_TASK_LOG_SUCCESS", meta: { taskId: "1234", addToActiveRequests: false } },
|
|
67
|
+
{ type: "GET_TASK_LOG_FAILURE", meta: { taskId: "1234", addToActiveRequests: false } },
|
|
68
|
+
],
|
|
69
|
+
endpoint: 'URL: tasks/1234/logs ""',
|
|
70
|
+
method: "GET",
|
|
71
|
+
body: undefined,
|
|
72
|
+
credentials: "include",
|
|
73
|
+
bailout: expect.it("to be a function"),
|
|
74
|
+
headers: {
|
|
75
|
+
Accept: "application/json; charset=utf-8",
|
|
76
|
+
"Content-Type": "application/json",
|
|
77
|
+
},
|
|
78
|
+
options: { redirect: "follow" },
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("getTaskList", () => {
|
|
84
|
+
it("creates a RSAA to get task info", () => {
|
|
85
|
+
const expectedParameters = {
|
|
86
|
+
filterTaskNames: ssrsDownloadFilterTaskNames,
|
|
87
|
+
requester: "freddie",
|
|
88
|
+
lastModified: "date value",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
expect(
|
|
92
|
+
getTaskList,
|
|
93
|
+
"when called with",
|
|
94
|
+
["freddie", ssrsDownloadFilterTaskNames, "date value", false],
|
|
95
|
+
"to exhaustively satisfy",
|
|
96
|
+
{
|
|
97
|
+
[RSAA]: {
|
|
98
|
+
types: [
|
|
99
|
+
{ type: "GET_TASK_LIST_REQUEST", meta: { addToActiveRequests: false } },
|
|
100
|
+
{ type: "GET_TASK_LIST_SUCCESS", meta: { addToActiveRequests: false } },
|
|
101
|
+
{ type: "GET_TASK_LIST_FAILURE", meta: { addToActiveRequests: false } },
|
|
102
|
+
],
|
|
103
|
+
endpoint: "URL: tasks " + JSON.stringify(expectedParameters),
|
|
104
|
+
method: "GET",
|
|
105
|
+
body: undefined,
|
|
106
|
+
credentials: "include",
|
|
107
|
+
bailout: expect.it("to be a function"),
|
|
108
|
+
headers: {
|
|
109
|
+
Accept: "application/json; charset=utf-8",
|
|
110
|
+
"Content-Type": "application/json",
|
|
111
|
+
},
|
|
112
|
+
options: { redirect: "follow" },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("creates a RSAA to get task info with null lastModified and true addToActiveRequests", () => {
|
|
119
|
+
const expectedParameters = {
|
|
120
|
+
filterTaskNames: ssrsDownloadFilterTaskNames,
|
|
121
|
+
requester: "freddie",
|
|
122
|
+
lastModified: null,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
expect(getTaskList, "when called with", ["freddie", ssrsDownloadFilterTaskNames], "to exhaustively satisfy", {
|
|
126
|
+
[RSAA]: {
|
|
127
|
+
types: [
|
|
128
|
+
{ type: "GET_TASK_LIST_REQUEST", meta: { addToActiveRequests: true } },
|
|
129
|
+
{ type: "GET_TASK_LIST_SUCCESS", meta: { addToActiveRequests: true } },
|
|
130
|
+
{ type: "GET_TASK_LIST_FAILURE", meta: { addToActiveRequests: true } },
|
|
131
|
+
],
|
|
132
|
+
endpoint: "URL: tasks " + JSON.stringify(expectedParameters),
|
|
133
|
+
method: "GET",
|
|
134
|
+
body: undefined,
|
|
135
|
+
credentials: "include",
|
|
136
|
+
bailout: expect.it("to be a function"),
|
|
137
|
+
headers: {
|
|
138
|
+
Accept: "application/json; charset=utf-8",
|
|
139
|
+
"Content-Type": "application/json",
|
|
140
|
+
},
|
|
141
|
+
options: { redirect: "follow" },
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("deleteTask", () => {
|
|
148
|
+
it("creates a RSAA to delete a task", () => {
|
|
149
|
+
expect(deleteTask, "when called with", ["1234"], "to exhaustively satisfy", {
|
|
150
|
+
[RSAA]: {
|
|
151
|
+
types: [
|
|
152
|
+
{ type: "DELETE_TASK_REQUEST", meta: { taskId: "1234" } },
|
|
153
|
+
{ type: "DELETE_TASK_SUCCESS", meta: { taskId: "1234" } },
|
|
154
|
+
{ type: "DELETE_TASK_FAILURE", meta: { taskId: "1234" } },
|
|
155
|
+
],
|
|
156
|
+
endpoint: 'URL: tasks/1234 ""',
|
|
157
|
+
method: "DELETE",
|
|
158
|
+
body: undefined,
|
|
159
|
+
credentials: "include",
|
|
160
|
+
bailout: expect.it("to be a function"),
|
|
161
|
+
headers: {
|
|
162
|
+
Accept: "application/json; charset=utf-8",
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
},
|
|
165
|
+
options: { redirect: "follow" },
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
package/src/buildStore.js
CHANGED
|
@@ -20,6 +20,7 @@ import timezonesReducer from "./reducers/timezones";
|
|
|
20
20
|
import modulesReducer from "./reducers/modules";
|
|
21
21
|
import metadataReducer from "./reducers/metadata";
|
|
22
22
|
import requestStatesReducer from "./reducers/requestStates";
|
|
23
|
+
import tasksReducer from "./reducers/tasks";
|
|
23
24
|
|
|
24
25
|
window.BUILD_ID = BUILD_ID;
|
|
25
26
|
window.BUILD_NUMBER = BUILD_NUMBER;
|
|
@@ -65,6 +66,7 @@ const buildStore = (reducers, devOptions = {}) => {
|
|
|
65
66
|
modules: modulesReducer,
|
|
66
67
|
metadata: metadataReducer,
|
|
67
68
|
requestStates: requestStatesReducer,
|
|
69
|
+
tasks: tasksReducer,
|
|
68
70
|
});
|
|
69
71
|
const rootReducer = buildReducer(reducers);
|
|
70
72
|
|
|
@@ -79,7 +79,7 @@ describe("About", () => {
|
|
|
79
79
|
</AboutLink>
|
|
80
80
|
</AboutParagraph>
|
|
81
81
|
<AboutParagraph>
|
|
82
|
-
{stringifyWithoutQuotes(messages["orc-shared.copyright"])}
|
|
82
|
+
{stringifyWithoutQuotes(messages["orc-shared.copyright"]).replace("{year}", new Date().getFullYear())}
|
|
83
83
|
<br />
|
|
84
84
|
{stringifyWithoutQuotes(messages["orc-shared.allRightsReserved"])}
|
|
85
85
|
</AboutParagraph>
|
|
@@ -130,7 +130,7 @@ describe("About", () => {
|
|
|
130
130
|
</AboutLink>
|
|
131
131
|
</AboutParagraph>
|
|
132
132
|
<AboutParagraph>
|
|
133
|
-
{stringifyWithoutQuotes(messages["orc-shared.copyright"])}
|
|
133
|
+
{stringifyWithoutQuotes(messages["orc-shared.copyright"]).replace("{year}", new Date().getFullYear())}
|
|
134
134
|
<br />
|
|
135
135
|
{stringifyWithoutQuotes(messages["orc-shared.allRightsReserved"])}
|
|
136
136
|
</AboutParagraph>
|
|
@@ -165,7 +165,7 @@ describe("About", () => {
|
|
|
165
165
|
</AboutLink>
|
|
166
166
|
</AboutParagraph>
|
|
167
167
|
<AboutParagraph>
|
|
168
|
-
{stringifyWithoutQuotes(messages["orc-shared.copyright"])}
|
|
168
|
+
{stringifyWithoutQuotes(messages["orc-shared.copyright"]).replace("{year}", new Date().getFullYear())}
|
|
169
169
|
<br />
|
|
170
170
|
{stringifyWithoutQuotes(messages["orc-shared.allRightsReserved"])}
|
|
171
171
|
</AboutParagraph>
|
|
@@ -60,9 +60,10 @@ const LogoSvg = styled.svg`
|
|
|
60
60
|
`;
|
|
61
61
|
|
|
62
62
|
export const Logo = () => (
|
|
63
|
-
<LogoSvg viewBox="0 0
|
|
64
|
-
<
|
|
65
|
-
|
|
63
|
+
<LogoSvg viewBox="0 0 354 354">
|
|
64
|
+
<g>
|
|
65
|
+
<path d="M0 241.41c0-65.49 50.53-111.98 119.66-111.98s119.25 46.49 119.25 111.98c0 65.49-50.13 111.97-119.25 111.97S0 306.9 0 241.41Zm175.04 0c0-37.6-23.85-60.23-55.38-60.23s-55.79 22.64-55.79 60.23c0 37.59 24.26 60.23 55.79 60.23 31.53 0 55.38-22.64 55.38-60.23Zm178.1-76.35h-77.48c0-48.29-39.29-87.58-87.58-87.58V0c91.02 0 165.07 74.05 165.07 165.06h-.01Z" />
|
|
66
|
+
</g>
|
|
66
67
|
</LogoSvg>
|
|
67
68
|
);
|
|
68
69
|
|
|
@@ -7,6 +7,7 @@ import TextProps from "../../textProps";
|
|
|
7
7
|
import { isReactComponent } from "../../../../utils/propertyValidator";
|
|
8
8
|
import sharedMessages from "../../../../sharedMessages";
|
|
9
9
|
import { useIntl } from "react-intl";
|
|
10
|
+
import classNames from "classnames";
|
|
10
11
|
|
|
11
12
|
const useStyles = makeStyles(theme => ({
|
|
12
13
|
title: {
|
|
@@ -53,7 +54,14 @@ const useStyles = makeStyles(theme => ({
|
|
|
53
54
|
},
|
|
54
55
|
}));
|
|
55
56
|
|
|
56
|
-
const InformationItemChildren = ({
|
|
57
|
+
const InformationItemChildren = ({
|
|
58
|
+
classes,
|
|
59
|
+
children,
|
|
60
|
+
showNotAvailable,
|
|
61
|
+
isMaxLineCountEnabled = true,
|
|
62
|
+
tooltipClasses,
|
|
63
|
+
valueClasses,
|
|
64
|
+
}) => {
|
|
57
65
|
const { formatMessage } = useIntl();
|
|
58
66
|
|
|
59
67
|
if (isReactComponent(children)) {
|
|
@@ -62,11 +70,11 @@ const InformationItemChildren = ({ classes, children, showNotAvailable, isMaxLin
|
|
|
62
70
|
|
|
63
71
|
const multipleLinesTextProps = new TextProps();
|
|
64
72
|
if (isMaxLineCountEnabled) multipleLinesTextProps.set(TextProps.propNames.lineCount, 2);
|
|
65
|
-
multipleLinesTextProps.set(TextProps.propNames.classes, classes.value);
|
|
73
|
+
multipleLinesTextProps.set(TextProps.propNames.classes, classNames(classes.value, valueClasses));
|
|
66
74
|
|
|
67
75
|
const value = children ?? (showNotAvailable ? formatMessage(sharedMessages.notAvailable) : "");
|
|
68
76
|
|
|
69
|
-
return <MultipleLinesText textProps={multipleLinesTextProps} children={value} />;
|
|
77
|
+
return <MultipleLinesText textProps={multipleLinesTextProps} children={value} tooltipClasses={tooltipClasses} />;
|
|
70
78
|
};
|
|
71
79
|
|
|
72
80
|
const InformationItemHeader = ({ classes, label, headerIcon }) => {
|
|
@@ -94,6 +102,8 @@ const InformationItem = ({
|
|
|
94
102
|
showNotAvailable = false,
|
|
95
103
|
marginTop = 0,
|
|
96
104
|
isMaxLineCountEnabled,
|
|
105
|
+
tooltipClasses,
|
|
106
|
+
valueClasses,
|
|
97
107
|
}) => {
|
|
98
108
|
const classes = useStyles({ required, error, marginTop });
|
|
99
109
|
|
|
@@ -105,6 +115,8 @@ const InformationItem = ({
|
|
|
105
115
|
children={children}
|
|
106
116
|
showNotAvailable={showNotAvailable}
|
|
107
117
|
isMaxLineCountEnabled={isMaxLineCountEnabled}
|
|
118
|
+
tooltipClasses={tooltipClasses}
|
|
119
|
+
valueClasses={valueClasses}
|
|
108
120
|
/>
|
|
109
121
|
</div>
|
|
110
122
|
);
|
|
@@ -11,7 +11,7 @@ const useStyles = makeStyles(theme => ({
|
|
|
11
11
|
},
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
const MultipleLinesText = ({ children, titleValue, textProps }) => {
|
|
14
|
+
const MultipleLinesText = ({ children, titleValue, textProps, tooltipClasses }) => {
|
|
15
15
|
const classes = useStyles();
|
|
16
16
|
|
|
17
17
|
const [isClamped, setIsClamped] = useState(false);
|
|
@@ -48,6 +48,7 @@ const MultipleLinesText = ({ children, titleValue, textProps }) => {
|
|
|
48
48
|
titleValue={title}
|
|
49
49
|
alwaysDisplay={isClamped}
|
|
50
50
|
onClampStart={event => clampHandler(event)}
|
|
51
|
+
tooltipClasses={tooltipClasses}
|
|
51
52
|
/>
|
|
52
53
|
);
|
|
53
54
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useRef, useEffect } from "react";
|
|
2
2
|
import { makeStyles } from "@material-ui/core/styles";
|
|
3
3
|
import SelectProps from "../SelectProps";
|
|
4
4
|
import Icon from "../../DataDisplay/Icon";
|
|
@@ -80,12 +80,9 @@ export const useStyles = makeStyles(theme => ({
|
|
|
80
80
|
},
|
|
81
81
|
parentInput: {
|
|
82
82
|
flex: "13 0 0",
|
|
83
|
-
zIndex:
|
|
84
|
-
border:
|
|
85
|
-
|
|
86
|
-
? `${theme.spacing(0.1)} solid ${theme.palette.focus}`
|
|
87
|
-
: `${theme.spacing(0.1)} solid ${theme.palette.grey.borders}`,
|
|
88
|
-
boxShadow: props => (props.focused ? `0 0 4px ${theme.palette.focus}` : "none"),
|
|
83
|
+
zIndex: 1,
|
|
84
|
+
border: `${theme.spacing(0.1)} solid ${theme.palette.grey.borders}`,
|
|
85
|
+
boxShadow: "none",
|
|
89
86
|
width: "100%",
|
|
90
87
|
display: "inherit",
|
|
91
88
|
marginLeft: theme.spacing(-0.1),
|
|
@@ -104,6 +101,11 @@ export const useStyles = makeStyles(theme => ({
|
|
|
104
101
|
borderBottomLeftRadius: 0,
|
|
105
102
|
},
|
|
106
103
|
},
|
|
104
|
+
"&:focus-within": {
|
|
105
|
+
zIndex: 99,
|
|
106
|
+
border: `${theme.spacing(0.1)} solid ${theme.palette.focus}`,
|
|
107
|
+
boxShadow: `0 0 4px ${theme.palette.focus}`,
|
|
108
|
+
},
|
|
107
109
|
},
|
|
108
110
|
selectRoot: {
|
|
109
111
|
zIndex: 10,
|
|
@@ -149,17 +151,30 @@ const SearchControl = ({
|
|
|
149
151
|
searchOption,
|
|
150
152
|
onSearch = () => {},
|
|
151
153
|
disabled,
|
|
154
|
+
focusAndSelectSearchFieldOnLoad = true,
|
|
155
|
+
focusSearchOnSearchOptionChange = false,
|
|
152
156
|
}) => {
|
|
153
157
|
searchOptions = !searchOptions?.length ? null : searchOptions;
|
|
154
158
|
searchOption = getSearchOptionValue(searchOptions, searchOption);
|
|
155
|
-
const [inputFocused, setInputFocused] = useState(false);
|
|
156
159
|
|
|
157
|
-
const classes = useStyles(
|
|
160
|
+
const classes = useStyles();
|
|
158
161
|
|
|
159
162
|
const inputRef = useRef();
|
|
160
163
|
|
|
161
164
|
const update = value => {
|
|
162
|
-
|
|
165
|
+
if (focusSearchOnSearchOptionChange && inputRef.current) {
|
|
166
|
+
onSearch(value, "");
|
|
167
|
+
setTimeout(() => {
|
|
168
|
+
/* istanbul ignore next */
|
|
169
|
+
if (inputRef.current) {
|
|
170
|
+
inputRef.current.value = "";
|
|
171
|
+
inputRef.current.focus();
|
|
172
|
+
inputRef.current.select();
|
|
173
|
+
}
|
|
174
|
+
}, 0);
|
|
175
|
+
} else {
|
|
176
|
+
onSearch(value, defaultValue);
|
|
177
|
+
}
|
|
163
178
|
};
|
|
164
179
|
|
|
165
180
|
const selectProps = new SelectProps();
|
|
@@ -178,28 +193,28 @@ const SearchControl = ({
|
|
|
178
193
|
selectProps.setStyle(SelectProps.ruleNames.root, classes.selectRoot);
|
|
179
194
|
selectProps.setStyle(SelectProps.ruleNames.paper, classes.selectPaper);
|
|
180
195
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
/* istanbul ignore next */
|
|
198
|
+
if (focusAndSelectSearchFieldOnLoad && inputRef.current) {
|
|
199
|
+
inputRef.current.focus();
|
|
200
|
+
inputRef.current.select();
|
|
186
201
|
}
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const onFocusedEvent = (event, focused) => {
|
|
190
|
-
setInputFocused(focused);
|
|
191
|
-
event.preventDefault();
|
|
192
|
-
event.stopPropagation();
|
|
193
|
-
};
|
|
202
|
+
}, [focusAndSelectSearchFieldOnLoad]);
|
|
194
203
|
|
|
195
204
|
const SelectSection = () => {
|
|
196
205
|
if (searchOptions === null) return null;
|
|
197
206
|
else return <Select className={classes.selectInput} options={searchOptions} selectProps={selectProps} />;
|
|
198
207
|
};
|
|
199
208
|
|
|
209
|
+
const onSubmit = event => {
|
|
210
|
+
// using form submit instead of a keydown (with key=enter) to allow the 'enter key' event to be canceled elsewhere to avoid the submit event
|
|
211
|
+
onSearch(searchOption, inputRef.current?.value);
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
};
|
|
214
|
+
|
|
200
215
|
const inputSection = (
|
|
201
|
-
<div data-qa="searchInput"
|
|
202
|
-
<form data-qa="searchForm" className={classes.fullWidth}>
|
|
216
|
+
<div data-qa="searchInput" className={classes.parentInput}>
|
|
217
|
+
<form data-qa="searchForm" className={classes.fullWidth} onSubmitCapture={onSubmit}>
|
|
203
218
|
<Input
|
|
204
219
|
placeholder={placeholder}
|
|
205
220
|
defaultValue={defaultValue}
|
|
@@ -207,10 +222,7 @@ const SearchControl = ({
|
|
|
207
222
|
type="text"
|
|
208
223
|
disabled={disabled}
|
|
209
224
|
classes={{ input: classes.controlInput }}
|
|
210
|
-
onKeyDown={handleKeyDown}
|
|
211
225
|
disableUnderline={true}
|
|
212
|
-
onFocus={e => onFocusedEvent(e, true)}
|
|
213
|
-
onBlur={e => onFocusedEvent(e, false)}
|
|
214
226
|
endAdornment={
|
|
215
227
|
<InputAdornment position="start">
|
|
216
228
|
<IconButton
|
|
@@ -53,10 +53,11 @@ describe("useStyles", () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
describe("SearchControl Component", () => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
jest.useFakeTimers();
|
|
58
|
+
});
|
|
59
59
|
afterEach(() => {
|
|
60
|
+
jest.useRealTimers();
|
|
60
61
|
jest.clearAllMocks();
|
|
61
62
|
});
|
|
62
63
|
|
|
@@ -232,8 +233,7 @@ describe("SearchControl Component", () => {
|
|
|
232
233
|
expect(searchInput.length, "to be", 1);
|
|
233
234
|
|
|
234
235
|
searchInput.instance().value = "abc";
|
|
235
|
-
|
|
236
|
-
searchInput.simulate("keydown", { key: "Enter" });
|
|
236
|
+
mountedComponent.find("form").simulate("submit", { preventDefault: () => {} });
|
|
237
237
|
|
|
238
238
|
expect(onSearchEvent, "to have calls satisfying", [{ args: ["aValue", "abc"] }]);
|
|
239
239
|
});
|
|
@@ -371,7 +371,7 @@ describe("SearchControl Component", () => {
|
|
|
371
371
|
expect(onSearchEvent, "to have calls satisfying", [{ args: ["anotherValue", "abcdef123"] }]);
|
|
372
372
|
});
|
|
373
373
|
|
|
374
|
-
it("Search Control should
|
|
374
|
+
it("Search Control should clear the search when changing the option", () => {
|
|
375
375
|
const options = [
|
|
376
376
|
{ value: "aValue", label: "aLabel" },
|
|
377
377
|
{ value: "anotherValue", label: "anotherLabel" },
|
|
@@ -385,8 +385,8 @@ describe("SearchControl Component", () => {
|
|
|
385
385
|
placeholder="placeHolderTest"
|
|
386
386
|
defaultValue={"abcdef123"}
|
|
387
387
|
searchOptions={options}
|
|
388
|
-
searchOption={"anotherValue"}
|
|
389
388
|
onSearch={onSearchEvent}
|
|
389
|
+
focusSearchOnSearchOptionChange={true}
|
|
390
390
|
/>
|
|
391
391
|
</TestWrapper>
|
|
392
392
|
);
|
|
@@ -395,48 +395,53 @@ describe("SearchControl Component", () => {
|
|
|
395
395
|
|
|
396
396
|
const selectMui = mountedComponent.find(SelectMUI);
|
|
397
397
|
|
|
398
|
-
|
|
399
|
-
|
|
398
|
+
const event = {
|
|
399
|
+
target: {
|
|
400
|
+
value: "anotherValue",
|
|
401
|
+
},
|
|
402
|
+
};
|
|
400
403
|
|
|
401
|
-
|
|
402
|
-
|
|
404
|
+
onSearchEvent.resetHistory();
|
|
405
|
+
|
|
406
|
+
selectMui.invoke("onChange")(event);
|
|
407
|
+
|
|
408
|
+
expect(onSearchEvent.callCount, "to equal", 1);
|
|
409
|
+
expect(onSearchEvent, "to have calls satisfying", [{ args: ["anotherValue", ""] }]);
|
|
410
|
+
|
|
411
|
+
const allInputs = mountedComponent.find("input");
|
|
412
|
+
const searchInput = allInputs.find("[placeholder='placeHolderTest']");
|
|
413
|
+
expect(searchInput.length, "to be", 1);
|
|
403
414
|
|
|
415
|
+
expect(searchInput.instance().value, "to be", "abcdef123");
|
|
416
|
+
jest.runOnlyPendingTimers();
|
|
417
|
+
expect(searchInput.instance().value, "to be", "");
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it("Search Control should render with the 2nd value", () => {
|
|
404
421
|
const options = [
|
|
405
422
|
{ value: "aValue", label: "aLabel" },
|
|
406
423
|
{ value: "anotherValue", label: "anotherLabel" },
|
|
407
424
|
];
|
|
408
425
|
|
|
426
|
+
const onSearchEvent = sinon.spy().named("search");
|
|
427
|
+
|
|
409
428
|
const component = (
|
|
410
429
|
<TestWrapper stylesProvider muiThemeProvider={{ theme }}>
|
|
411
|
-
<SearchControl
|
|
430
|
+
<SearchControl
|
|
431
|
+
placeholder="placeHolderTest"
|
|
432
|
+
defaultValue={"abcdef123"}
|
|
433
|
+
searchOptions={options}
|
|
434
|
+
searchOption={"anotherValue"}
|
|
435
|
+
onSearch={onSearchEvent}
|
|
436
|
+
/>
|
|
412
437
|
</TestWrapper>
|
|
413
438
|
);
|
|
414
439
|
|
|
415
440
|
const mountedComponent = mount(component);
|
|
416
441
|
|
|
417
|
-
const
|
|
418
|
-
const searchInput = allInputs.find("[placeholder='placeHolderTest']");
|
|
419
|
-
expect(searchInput.length, "to be", 1);
|
|
420
|
-
|
|
421
|
-
let searchEditParent = mountedComponent.find('[data-qa="searchInput"]');
|
|
422
|
-
expect(searchEditParent.length, "to be", 1);
|
|
423
|
-
|
|
424
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", false);
|
|
425
|
-
|
|
426
|
-
const event = {
|
|
427
|
-
preventDefault: () => {},
|
|
428
|
-
stopPropagation: () => {},
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
searchInput.invoke("onFocus")(event);
|
|
432
|
-
|
|
433
|
-
searchEditParent = mountedComponent.find('[data-qa="searchInput"]');
|
|
434
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", true);
|
|
435
|
-
|
|
436
|
-
searchInput.invoke("onBlur")(event);
|
|
442
|
+
const selectMui = mountedComponent.find(SelectMUI);
|
|
437
443
|
|
|
438
|
-
|
|
439
|
-
expect(searchEditParent.props()["data-qa-is-focused"], "to be", false);
|
|
444
|
+
expect(selectMui.props().value, "to equal", "anotherValue");
|
|
440
445
|
});
|
|
441
446
|
|
|
442
447
|
it("Renders Search Control component without errors when disabled", () => {
|
|
@@ -8,7 +8,7 @@ import { isString, isObject, isStringNullOrWhitespace, isReactComponent } from "
|
|
|
8
8
|
|
|
9
9
|
const withDeferredTooltip =
|
|
10
10
|
Comp =>
|
|
11
|
-
({ titleValue, alwaysDisplay, ...props }) => {
|
|
11
|
+
({ titleValue, alwaysDisplay, tooltipClasses, ...props }) => {
|
|
12
12
|
const [shouldBeTooltipped, setShouldBeTooltipped] = useState(false);
|
|
13
13
|
|
|
14
14
|
const defaultComponent = <Comp onMouseEnter={event => makeComponentTooltipped(event)} {...props} />;
|
|
@@ -32,6 +32,7 @@ const withDeferredTooltip =
|
|
|
32
32
|
return (
|
|
33
33
|
<MuiTooltip
|
|
34
34
|
arrow
|
|
35
|
+
classes={tooltipClasses ?? null}
|
|
35
36
|
title={titleValue}
|
|
36
37
|
disableHoverListener={false}
|
|
37
38
|
disableFocusListener={true}
|