@beinformed/ui 1.27.6 → 1.28.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/CHANGELOG.md +11 -1
- package/esm/constants/LayoutHintConfig.js +0 -9
- package/esm/constants/LayoutHintConfig.js.map +1 -1
- package/esm/constants/LayoutHints.js +0 -4
- package/esm/constants/LayoutHints.js.map +1 -1
- package/esm/constants/Settings.js +0 -4
- package/esm/constants/Settings.js.map +1 -1
- package/esm/models/attributes/DatetimeAttributeModel.js +3 -29
- package/esm/models/attributes/DatetimeAttributeModel.js.map +1 -1
- package/esm/react-client/Init.js +2 -2
- package/esm/react-client/Init.js.map +1 -1
- package/esm/react-client/client.js +80 -52
- package/esm/react-client/client.js.map +1 -1
- package/esm/redux/store/configureStore.js +4 -4
- package/esm/redux/store/configureStore.js.map +1 -1
- package/lib/constants/LayoutHintConfig.js +0 -9
- package/lib/constants/LayoutHintConfig.js.flow +0 -9
- package/lib/constants/LayoutHintConfig.js.map +1 -1
- package/lib/constants/LayoutHints.js +2 -7
- package/lib/constants/LayoutHints.js.flow +0 -4
- package/lib/constants/LayoutHints.js.map +1 -1
- package/lib/constants/Settings.js +0 -4
- package/lib/constants/Settings.js.flow +0 -6
- package/lib/constants/Settings.js.map +1 -1
- package/lib/models/attributes/DatetimeAttributeModel.js +3 -29
- package/lib/models/attributes/DatetimeAttributeModel.js.flow +7 -41
- package/lib/models/attributes/DatetimeAttributeModel.js.map +1 -1
- package/lib/models/attributes/__tests__/DateAttributeModel.spec.js.flow +1 -35
- package/lib/models/attributes/__tests__/DatetimeAttributeModel.spec.js.flow +158 -216
- package/lib/models/attributes/__tests__/TimestampModel.spec.js.flow +0 -5
- package/lib/react-client/Init.js +2 -2
- package/lib/react-client/Init.js.flow +3 -3
- package/lib/react-client/Init.js.map +1 -1
- package/lib/react-client/client.js +83 -53
- package/lib/react-client/client.js.flow +106 -67
- package/lib/react-client/client.js.map +1 -1
- package/lib/redux/store/configureStore.js +4 -4
- package/lib/redux/store/configureStore.js.flow +5 -5
- package/lib/redux/store/configureStore.js.map +1 -1
- package/package.json +17 -19
- package/src/constants/LayoutHintConfig.js +0 -9
- package/src/constants/LayoutHints.js +0 -4
- package/src/constants/Settings.js +0 -6
- package/src/models/attributes/DatetimeAttributeModel.js +7 -41
- package/src/models/attributes/__tests__/DateAttributeModel.spec.js +1 -35
- package/src/models/attributes/__tests__/DatetimeAttributeModel.spec.js +158 -216
- package/src/models/attributes/__tests__/TimestampModel.spec.js +0 -5
- package/src/react-client/Init.js +3 -3
- package/src/react-client/client.js +106 -67
- package/src/redux/store/configureStore.js +5 -5
- package/types/constants/LayoutHintConfig.d.ts +8 -23
- package/types/constants/LayoutHints.d.ts +0 -4
- package/types/models/actions/ActionCollection.d.ts +1 -1
- package/types/models/attributes/DatetimeAttributeModel.d.ts +8 -2
- package/types/redux/_modularui/types.d.ts +4 -0
- package/types/redux/types.d.ts +1 -1
|
@@ -1,226 +1,168 @@
|
|
|
1
1
|
import DatetimeAttributeModel from "../DatetimeAttributeModel";
|
|
2
|
-
import { setSettings } from "../../../constants/Settings";
|
|
3
2
|
import { ATTRIBUTE_WIDTH } from "../../../constants";
|
|
4
3
|
|
|
5
4
|
describe("datetimeAttributeModel", () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
expect(attribute.format).toBe("yyyy-MM-dd'T'HH:mm:ss");
|
|
20
|
-
expect(attribute.getInputValue()).toBe("");
|
|
21
|
-
expect(attribute.inputvalue).toBe("");
|
|
22
|
-
expect(attribute.readonlyvalue).toBe("");
|
|
23
|
-
|
|
24
|
-
attribute.addConstraints();
|
|
25
|
-
expect(attribute.constraintCollection).toHaveLength(1);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("should be able to update", () => {
|
|
29
|
-
const attribute = new DatetimeAttributeModel(
|
|
30
|
-
{},
|
|
31
|
-
{
|
|
32
|
-
type: "datetime",
|
|
33
|
-
format: "dd-MM-yyyy HH:mm",
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
attribute.update("18-08-2016 13:45");
|
|
38
|
-
expect(attribute.getInputValue()).toBe("18-08-2016 13:45");
|
|
39
|
-
expect(attribute.getInitialInputValue("2016-08-18T13:45:23")).toBe(
|
|
40
|
-
"18-08-2016 13:45"
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
expect(attribute.readonlyvalue).toBe("18-08-2016 13:45");
|
|
44
|
-
|
|
45
|
-
attribute.update(null);
|
|
46
|
-
expect(attribute.getInputValue()).toBe("");
|
|
47
|
-
|
|
48
|
-
attribute.update("");
|
|
49
|
-
expect(attribute.value).toBeNull();
|
|
50
|
-
|
|
51
|
-
attribute.update("aaaa");
|
|
52
|
-
expect(attribute.value).toBe("Invalid Date");
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("should be able to handle min and max date in only date format and renders in format", () => {
|
|
56
|
-
const attribute = new DatetimeAttributeModel(
|
|
57
|
-
{},
|
|
58
|
-
{
|
|
59
|
-
type: "datetime",
|
|
60
|
-
format: "dd-MM-yyyy HH:mm",
|
|
61
|
-
mindate: "2010-10-01T00:00:00",
|
|
62
|
-
maxdate: "2010-10-31T23:59:59",
|
|
63
|
-
}
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
attribute.update("18-08-2016 13:45");
|
|
67
|
-
|
|
68
|
-
expect(attribute.isValid).toBe(false);
|
|
69
|
-
expect(attribute.formatValue(attribute.mindate)).toBe("01-10-2010 00:00");
|
|
70
|
-
expect(attribute.formatValue(attribute.maxdate)).toBe("31-10-2010 23:59");
|
|
71
|
-
});
|
|
5
|
+
it("should be able to create an empty DatetimeAttribute object", () => {
|
|
6
|
+
const attribute = new DatetimeAttributeModel({}, { type: "datetime" });
|
|
7
|
+
|
|
8
|
+
expect(attribute).toBeInstanceOf(DatetimeAttributeModel);
|
|
9
|
+
|
|
10
|
+
expect(attribute.type).toBe("datetime");
|
|
11
|
+
expect(attribute.format).toBe("yyyy-MM-dd'T'HH:mm:ss");
|
|
12
|
+
expect(attribute.getInputValue()).toBe("");
|
|
13
|
+
expect(attribute.inputvalue).toBe("");
|
|
14
|
+
expect(attribute.readonlyvalue).toBe("");
|
|
15
|
+
|
|
16
|
+
attribute.addConstraints();
|
|
17
|
+
expect(attribute.constraintCollection).toHaveLength(1);
|
|
72
18
|
});
|
|
73
19
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
20
|
+
it("should be able to update", () => {
|
|
21
|
+
const attribute = new DatetimeAttributeModel(
|
|
22
|
+
{},
|
|
23
|
+
{
|
|
24
|
+
type: "datetime",
|
|
25
|
+
format: "dd-MM-yyyy HH:mm",
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
attribute.update("18-08-2016 13:45");
|
|
30
|
+
expect(attribute.getInputValue()).toBe("18-08-2016 13:45");
|
|
31
|
+
expect(attribute.getInitialInputValue("2016-08-18T13:45:23")).toBe(
|
|
32
|
+
"18-08-2016 13:45"
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(attribute.readonlyvalue).toBe("18-08-2016 13:45");
|
|
36
|
+
|
|
37
|
+
attribute.update(null);
|
|
38
|
+
expect(attribute.getInputValue()).toBe("");
|
|
39
|
+
|
|
40
|
+
attribute.update("");
|
|
41
|
+
expect(attribute.value).toBeNull();
|
|
42
|
+
|
|
43
|
+
attribute.update("aaaa");
|
|
44
|
+
expect(attribute.value).toBe("Invalid Date");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should be able to handle min and max date in only date format and renders in format", () => {
|
|
48
|
+
const attribute = new DatetimeAttributeModel(
|
|
49
|
+
{},
|
|
50
|
+
{
|
|
51
|
+
type: "datetime",
|
|
52
|
+
format: "dd-MM-yyyy HH:mm",
|
|
53
|
+
mindate: "2010-10-01T00:00:00",
|
|
54
|
+
maxdate: "2010-10-31T23:59:59",
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
attribute.update("18-08-2016 13:45");
|
|
59
|
+
|
|
60
|
+
expect(attribute.isValid).toBe(false);
|
|
61
|
+
expect(attribute.formatValue(attribute.mindate)).toBe("01-10-2010 00:00");
|
|
62
|
+
expect(attribute.formatValue(attribute.maxdate)).toBe("31-10-2010 23:59");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should return AttributeWidth for dates", () => {
|
|
66
|
+
const attribute = new DatetimeAttributeModel(
|
|
67
|
+
{},
|
|
68
|
+
{
|
|
69
|
+
type: "date",
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
expect(attribute.readonlyWidth).toBe(ATTRIBUTE_WIDTH.SMALL);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should return AttributeWidth for times", () => {
|
|
76
|
+
const attribute = new DatetimeAttributeModel(
|
|
77
|
+
{},
|
|
78
|
+
{
|
|
79
|
+
type: "time",
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
expect(attribute.readonlyWidth).toBe(ATTRIBUTE_WIDTH.SMALL);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should return AttributeWidth for datetime", () => {
|
|
86
|
+
const attribute = new DatetimeAttributeModel(
|
|
87
|
+
{},
|
|
88
|
+
{
|
|
89
|
+
type: "datetime",
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
expect(attribute.readonlyWidth).toBe(ATTRIBUTE_WIDTH.MEDIUM);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("can validate datetime with datetime format", () => {
|
|
96
|
+
const datetimeFormat = new DatetimeAttributeModel(
|
|
97
|
+
{},
|
|
98
|
+
{
|
|
99
|
+
type: "datetime",
|
|
100
|
+
format: "dd-MM-yyyy HH:mm",
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect(datetimeFormat.validate("19-10-2010 1:45")).toBe(true);
|
|
105
|
+
expect(datetimeFormat.validate("19-10-2010 13:45")).toBe(true);
|
|
106
|
+
|
|
107
|
+
expect(datetimeFormat.validate("19-10-2010")).toBe(false);
|
|
108
|
+
expect(datetimeFormat.validate("13:45")).toBe(false);
|
|
109
|
+
expect(datetimeFormat.validate("19-10-2010 1:45 am")).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("can validate datetime with only date format", () => {
|
|
113
|
+
const dateFormat = new DatetimeAttributeModel(
|
|
114
|
+
{},
|
|
115
|
+
{
|
|
116
|
+
type: "datetime",
|
|
117
|
+
format: "dd-MM-yyyy",
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(dateFormat.validate("19-10-2010")).toBe(true);
|
|
122
|
+
|
|
123
|
+
expect(dateFormat.validate("19-10-2010 1:45")).toBe(false);
|
|
124
|
+
expect(dateFormat.validate("13:45")).toBe(false);
|
|
125
|
+
expect(dateFormat.validate("19-10-2010 1:45 am")).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("can validate datetime with datetime am/pm format", () => {
|
|
129
|
+
const datetimeAmPmFormat = new DatetimeAttributeModel(
|
|
130
|
+
{},
|
|
131
|
+
{
|
|
132
|
+
type: "datetime",
|
|
133
|
+
format: "dd-MM-yyyy hh:mm a",
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
expect(datetimeAmPmFormat.validate("19-10-2010 1:45 am")).toBe(true);
|
|
138
|
+
expect(datetimeAmPmFormat.validate("19-10-2010 1:45 pm")).toBe(true);
|
|
139
|
+
|
|
140
|
+
expect(datetimeAmPmFormat.validate("19-10-2010 1:45")).toBe(false);
|
|
141
|
+
expect(datetimeAmPmFormat.validate("19-10-2010 13:45")).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("can handle old datetime format with ms", () => {
|
|
145
|
+
const attribute = new DatetimeAttributeModel(
|
|
146
|
+
{ value: "2031-12-21T17:41:21.000" },
|
|
147
|
+
{
|
|
148
|
+
type: "datetime",
|
|
149
|
+
format: "dd-MM-yyyy HH:mm",
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(attribute.readonlyvalue).toBe("21-12-2031 17:41");
|
|
204
154
|
});
|
|
205
155
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
type: "datetime",
|
|
218
|
-
format: "dd-MM-yyyy HH:mm",
|
|
219
|
-
formatlabel: "dd-MM-yyyy HH:mm",
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
expect(attribute.placeholder).toBe("dd-MM-yyyy");
|
|
224
|
-
});
|
|
156
|
+
it("returns date part of formatlabel as placeholder if attribute has date and time", () => {
|
|
157
|
+
const attribute = new DatetimeAttributeModel(
|
|
158
|
+
{},
|
|
159
|
+
{
|
|
160
|
+
type: "datetime",
|
|
161
|
+
format: "dd-MM-yyyy HH:mm",
|
|
162
|
+
formatlabel: "dd-MM-yyyy HH:mm",
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(attribute.placeholder).toBe("dd-MM-yyyy");
|
|
225
167
|
});
|
|
226
168
|
});
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import DatetimeAttributeModel from "../DatetimeAttributeModel";
|
|
2
|
-
import { setSettings } from "../../../constants/Settings";
|
|
3
|
-
|
|
4
2
|
describe("timestampAttributeModel", () => {
|
|
5
|
-
beforeAll(() => {
|
|
6
|
-
setSettings({ DATE_INPUT_FORMAT: "dd-MM-yyyy" });
|
|
7
|
-
});
|
|
8
3
|
it("should be able to create an empty TimestampAttribute object", () => {
|
|
9
4
|
const attribute = new DatetimeAttributeModel({}, { type: "timestamp" });
|
|
10
5
|
|
package/src/react-client/Init.js
CHANGED
|
@@ -14,7 +14,7 @@ import type { Props as FallbackProps } from "../react/ErrorBoundaryFallback";
|
|
|
14
14
|
|
|
15
15
|
export type Props = {
|
|
16
16
|
+store: ReduxStore,
|
|
17
|
-
+
|
|
17
|
+
+routerHistory: RouterHistory,
|
|
18
18
|
+contextPath: string,
|
|
19
19
|
+theme?: Theme | Array<Theme>,
|
|
20
20
|
+children: ?Node,
|
|
@@ -25,7 +25,7 @@ export type Props = {
|
|
|
25
25
|
*/
|
|
26
26
|
const Init = ({
|
|
27
27
|
store,
|
|
28
|
-
|
|
28
|
+
routerHistory,
|
|
29
29
|
contextPath,
|
|
30
30
|
theme,
|
|
31
31
|
children,
|
|
@@ -35,7 +35,7 @@ const Init = ({
|
|
|
35
35
|
<ThemeProvider theme={theme}>
|
|
36
36
|
<HelmetProvider>
|
|
37
37
|
<ErrorBoundary FallbackComponent={ErrorFallbackComponent}>
|
|
38
|
-
<Router history={
|
|
38
|
+
<Router history={routerHistory} basename={contextPath}>
|
|
39
39
|
{children}
|
|
40
40
|
</Router>
|
|
41
41
|
</ErrorBoundary>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
|
|
3
|
-
import elementClosest from "element-closest";
|
|
4
|
-
elementClosest(window);
|
|
5
|
-
|
|
6
|
-
/* polyfill for focus-visible */
|
|
7
|
-
import "focus-visible";
|
|
8
|
-
|
|
9
|
-
import { hydrate, render as reactRender } from "react-dom";
|
|
2
|
+
import { hydrate, render } from "react-dom";
|
|
10
3
|
|
|
11
4
|
import { has } from "../utils/helpers/objects";
|
|
12
5
|
import setImmediate from "setimmediate";
|
|
@@ -36,12 +29,17 @@ import Init from "./Init";
|
|
|
36
29
|
|
|
37
30
|
import { handleBeforeRenderHooks } from "../redux/store/beforeRenderHooks";
|
|
38
31
|
|
|
39
|
-
import type {
|
|
32
|
+
import type {
|
|
33
|
+
ComponentType,
|
|
34
|
+
Element as ReactElement,
|
|
35
|
+
ElementType,
|
|
36
|
+
} from "react";
|
|
40
37
|
import type { Theme } from "../react-theme/types";
|
|
41
38
|
import type { CustomReducers, ReduxStore } from "../redux/types";
|
|
42
39
|
import type { RouterHistory } from "react-router";
|
|
43
40
|
import type { BeforeRenderHook } from "../redux/store/beforeRenderHooks";
|
|
44
41
|
import type { Props as FallbackProps } from "../react/ErrorBoundaryFallback";
|
|
42
|
+
|
|
45
43
|
export type Props = {
|
|
46
44
|
customReducers?: CustomReducers,
|
|
47
45
|
theme?: Theme | Array<Theme>,
|
|
@@ -53,8 +51,6 @@ export type Props = {
|
|
|
53
51
|
/*
|
|
54
52
|
* deserialize serialized data from the server to provide a smooth dehydration.
|
|
55
53
|
*/
|
|
56
|
-
/**
|
|
57
|
-
*/
|
|
58
54
|
const parseDataToJSON = (data: string) => {
|
|
59
55
|
try {
|
|
60
56
|
return JSON.parse(data);
|
|
@@ -63,24 +59,48 @@ const parseDataToJSON = (data: string) => {
|
|
|
63
59
|
}
|
|
64
60
|
};
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
* Mount the webapplication to the DOM, used client side when JavaScript is enabled.
|
|
68
|
-
*/
|
|
69
|
-
const client = (props: Props) => {
|
|
70
|
-
if (typeof window.contextPath === "undefined") {
|
|
71
|
-
throw new Error("Missing contextPath on window object");
|
|
72
|
-
}
|
|
73
|
-
|
|
62
|
+
const getDataFromServer = () => {
|
|
74
63
|
const dataElement = document.querySelector(
|
|
75
64
|
'script[type="application/json"][data-app-state="app-json"]'
|
|
76
65
|
);
|
|
66
|
+
|
|
77
67
|
if (!dataElement) {
|
|
78
68
|
throw new Error("Error loading state, json not found");
|
|
79
69
|
} else if (dataElement.textContent.trim() === "") {
|
|
80
|
-
return;
|
|
70
|
+
return {};
|
|
81
71
|
}
|
|
82
72
|
|
|
83
|
-
|
|
73
|
+
return parseDataToJSON(dataElement.textContent);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
*/
|
|
78
|
+
export const setUnhandledRejectionEvent = (store: ReduxStore) => {
|
|
79
|
+
window.onunhandledrejection = (event) => {
|
|
80
|
+
if (event.detail) {
|
|
81
|
+
return setImmediate(() => {
|
|
82
|
+
const errorMessage = event.detail.reason.message.toString();
|
|
83
|
+
|
|
84
|
+
store.dispatch(showXHRErrorNotification(errorMessage));
|
|
85
|
+
throw event.detail.reason;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return event;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
*/
|
|
95
|
+
export const setupClient = (
|
|
96
|
+
customReducers: CustomReducers = {},
|
|
97
|
+
beforeRenderHooks: ?Array<BeforeRenderHook>
|
|
98
|
+
): { store: ReduxStore, routerHistory: RouterHistory } => {
|
|
99
|
+
if (typeof window.contextPath === "undefined") {
|
|
100
|
+
throw new Error("Missing contextPath on window object");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const data = getDataFromServer();
|
|
84
104
|
|
|
85
105
|
// remove all resources from cache
|
|
86
106
|
Cache.clear("^res:");
|
|
@@ -89,9 +109,9 @@ const client = (props: Props) => {
|
|
|
89
109
|
const browserHistory: RouterHistory = createBrowserHistory({
|
|
90
110
|
basename: getBasePath(),
|
|
91
111
|
});
|
|
92
|
-
const {
|
|
112
|
+
const { routerHistory, store } = configureStore(
|
|
93
113
|
browserHistory,
|
|
94
|
-
|
|
114
|
+
customReducers,
|
|
95
115
|
rehydrate(data)
|
|
96
116
|
);
|
|
97
117
|
|
|
@@ -106,7 +126,7 @@ const client = (props: Props) => {
|
|
|
106
126
|
});
|
|
107
127
|
|
|
108
128
|
if (has(data, "error.name")) {
|
|
109
|
-
const error = new FetchException(data
|
|
129
|
+
const error = new FetchException(data?.error?.response);
|
|
110
130
|
store.dispatch(handleError(error));
|
|
111
131
|
}
|
|
112
132
|
|
|
@@ -115,74 +135,93 @@ const client = (props: Props) => {
|
|
|
115
135
|
}
|
|
116
136
|
|
|
117
137
|
// listen to history change and update the redux router store
|
|
118
|
-
|
|
138
|
+
routerHistory.listen((location, action) => {
|
|
119
139
|
store.dispatch(locationChange(location, action));
|
|
120
140
|
});
|
|
121
141
|
|
|
122
|
-
|
|
123
|
-
*/
|
|
124
|
-
window.onunhandledrejection = (event) => {
|
|
125
|
-
if (event.detail) {
|
|
126
|
-
return setImmediate(() => {
|
|
127
|
-
const errorMessage = event.detail.reason.message.toString();
|
|
128
|
-
|
|
129
|
-
store.dispatch(showXHRErrorNotification(errorMessage));
|
|
130
|
-
throw event.detail.reason;
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return event;
|
|
135
|
-
};
|
|
142
|
+
setUnhandledRejectionEvent(store);
|
|
136
143
|
|
|
137
144
|
if (document.body) {
|
|
138
145
|
document.body.className = "js";
|
|
139
146
|
}
|
|
140
147
|
|
|
141
|
-
if (
|
|
142
|
-
handleBeforeRenderHooks(
|
|
148
|
+
if (beforeRenderHooks) {
|
|
149
|
+
handleBeforeRenderHooks(beforeRenderHooks, { store });
|
|
143
150
|
}
|
|
144
151
|
|
|
145
|
-
|
|
146
|
-
store,
|
|
147
|
-
history,
|
|
148
|
-
props.theme,
|
|
149
|
-
props.render,
|
|
150
|
-
props.ErrorFallbackComponent
|
|
151
|
-
);
|
|
152
|
+
return { store, routerHistory };
|
|
152
153
|
};
|
|
153
154
|
|
|
154
155
|
/**
|
|
155
156
|
*/
|
|
156
|
-
const addContentLoadedEvent = (
|
|
157
|
+
export const addContentLoadedEvent = (
|
|
157
158
|
store: ReduxStore,
|
|
158
|
-
|
|
159
|
+
routerHistory: RouterHistory,
|
|
159
160
|
theme?: Theme | Array<Theme>,
|
|
160
161
|
render: Function,
|
|
161
|
-
ErrorFallbackComponent?: ComponentType<FallbackProps
|
|
162
|
+
ErrorFallbackComponent?: ComponentType<FallbackProps>,
|
|
163
|
+
mount: Function
|
|
162
164
|
) => {
|
|
163
165
|
window.addEventListener("DOMContentLoaded", () => {
|
|
164
166
|
const applicationNode = document.querySelector("#application");
|
|
165
|
-
if (applicationNode) {
|
|
166
|
-
const isSSR = applicationNode.querySelector(".application");
|
|
167
|
-
const mount = isSSR ? hydrate : reactRender;
|
|
168
|
-
mount(
|
|
169
|
-
<Init
|
|
170
|
-
store={store}
|
|
171
|
-
history={history}
|
|
172
|
-
contextPath={window.contextPath}
|
|
173
|
-
theme={theme}
|
|
174
|
-
ErrorFallbackComponent={ErrorFallbackComponent}
|
|
175
|
-
>
|
|
176
|
-
{render()}
|
|
177
|
-
</Init>,
|
|
178
|
-
applicationNode
|
|
179
|
-
);
|
|
180
|
-
} else {
|
|
167
|
+
if (!applicationNode) {
|
|
181
168
|
throw new Error(
|
|
182
169
|
"No DOM element with id application found to attach client to"
|
|
183
170
|
);
|
|
184
171
|
}
|
|
172
|
+
|
|
173
|
+
mount(
|
|
174
|
+
applicationNode,
|
|
175
|
+
<Init
|
|
176
|
+
store={store}
|
|
177
|
+
routerHistory={routerHistory}
|
|
178
|
+
contextPath={window.contextPath}
|
|
179
|
+
theme={theme}
|
|
180
|
+
ErrorFallbackComponent={ErrorFallbackComponent}
|
|
181
|
+
>
|
|
182
|
+
{render()}
|
|
183
|
+
</Init>
|
|
184
|
+
);
|
|
185
185
|
});
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
+
/**
|
|
189
|
+
*/
|
|
190
|
+
const mountClient = (
|
|
191
|
+
applicationNode: Element,
|
|
192
|
+
initComponent: ReactElement<ElementType>
|
|
193
|
+
) => {
|
|
194
|
+
const isSSR = applicationNode.querySelector(".application");
|
|
195
|
+
if (isSSR) {
|
|
196
|
+
hydrate(initComponent, applicationNode);
|
|
197
|
+
} else {
|
|
198
|
+
render(initComponent, applicationNode);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Mount the webapplication to the DOM, setup redux store and caches, add unhandledRejectionEvent, used client side when JavaScript is enabled.
|
|
204
|
+
*/
|
|
205
|
+
const client = ({
|
|
206
|
+
customReducers,
|
|
207
|
+
theme,
|
|
208
|
+
render,
|
|
209
|
+
beforeRenderHooks,
|
|
210
|
+
ErrorFallbackComponent,
|
|
211
|
+
}: Props) => {
|
|
212
|
+
const { store, routerHistory } = setupClient(
|
|
213
|
+
customReducers,
|
|
214
|
+
beforeRenderHooks
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
addContentLoadedEvent(
|
|
218
|
+
store,
|
|
219
|
+
routerHistory,
|
|
220
|
+
theme,
|
|
221
|
+
render,
|
|
222
|
+
ErrorFallbackComponent,
|
|
223
|
+
mountClient
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
188
227
|
export default client;
|