@beinformed/ui 1.65.9 → 1.65.11

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/esm/hooks/useDeepCompareEffect.js +22 -8
  3. package/esm/hooks/useDeepCompareEffect.js.flow +26 -10
  4. package/esm/hooks/useDeepCompareEffect.js.map +1 -1
  5. package/esm/hooks/useList.js +18 -15
  6. package/esm/hooks/useList.js.flow +17 -16
  7. package/esm/hooks/useList.js.map +1 -1
  8. package/esm/hooks/useModularUIBasic.js +10 -3
  9. package/esm/hooks/useModularUIBasic.js.flow +11 -1
  10. package/esm/hooks/useModularUIBasic.js.map +1 -1
  11. package/esm/hooks/usePanel.js.flow +1 -1
  12. package/esm/hooks/usePanel.js.map +1 -1
  13. package/esm/hooks/useRouter.js +12 -6
  14. package/esm/hooks/useRouter.js.flow +29 -23
  15. package/esm/hooks/useRouter.js.map +1 -1
  16. package/esm/models/attributes/AttributeModel.js +14 -0
  17. package/esm/models/attributes/AttributeModel.js.flow +14 -0
  18. package/esm/models/attributes/AttributeModel.js.map +1 -1
  19. package/esm/models/attributes/CompositeAttributeModel.js +11 -11
  20. package/esm/models/attributes/CompositeAttributeModel.js.flow +11 -11
  21. package/esm/models/attributes/CompositeAttributeModel.js.map +1 -1
  22. package/esm/models/attributes/PasswordAttributeModel.js +3 -3
  23. package/esm/models/attributes/PasswordAttributeModel.js.flow +3 -3
  24. package/esm/models/attributes/PasswordAttributeModel.js.map +1 -1
  25. package/esm/models/filters/FilterModel.js +1 -1
  26. package/esm/models/filters/FilterModel.js.flow +1 -1
  27. package/esm/models/filters/FilterModel.js.map +1 -1
  28. package/esm/models/filters/RangeFilterModel.js +1 -1
  29. package/esm/models/filters/RangeFilterModel.js.flow +1 -1
  30. package/esm/models/filters/RangeFilterModel.js.map +1 -1
  31. package/esm/models/href/Href.js +27 -2
  32. package/esm/models/href/Href.js.flow +30 -2
  33. package/esm/models/href/Href.js.map +1 -1
  34. package/esm/models/href/ListHref.js +3 -2
  35. package/esm/models/href/ListHref.js.flow +4 -2
  36. package/esm/models/href/ListHref.js.map +1 -1
  37. package/esm/models/list/ListModel.js +7 -1
  38. package/esm/models/list/ListModel.js.flow +8 -2
  39. package/esm/models/list/ListModel.js.map +1 -1
  40. package/esm/models/parameter/Parameter.js +6 -6
  41. package/esm/models/parameter/Parameter.js.flow +6 -6
  42. package/esm/models/parameter/Parameter.js.map +1 -1
  43. package/lib/hooks/useDeepCompareEffect.js +22 -11
  44. package/lib/hooks/useDeepCompareEffect.js.map +1 -1
  45. package/lib/hooks/useList.js +18 -15
  46. package/lib/hooks/useList.js.map +1 -1
  47. package/lib/hooks/useModularUIBasic.js +9 -2
  48. package/lib/hooks/useModularUIBasic.js.map +1 -1
  49. package/lib/hooks/usePanel.js.map +1 -1
  50. package/lib/hooks/useRouter.js +12 -6
  51. package/lib/hooks/useRouter.js.map +1 -1
  52. package/lib/models/attributes/AttributeModel.js +14 -0
  53. package/lib/models/attributes/AttributeModel.js.map +1 -1
  54. package/lib/models/attributes/CompositeAttributeModel.js +11 -11
  55. package/lib/models/attributes/CompositeAttributeModel.js.map +1 -1
  56. package/lib/models/attributes/PasswordAttributeModel.js +3 -3
  57. package/lib/models/attributes/PasswordAttributeModel.js.map +1 -1
  58. package/lib/models/filters/FilterModel.js +1 -1
  59. package/lib/models/filters/FilterModel.js.map +1 -1
  60. package/lib/models/filters/RangeFilterModel.js +1 -1
  61. package/lib/models/filters/RangeFilterModel.js.map +1 -1
  62. package/lib/models/href/Href.js +27 -2
  63. package/lib/models/href/Href.js.map +1 -1
  64. package/lib/models/href/ListHref.js +3 -2
  65. package/lib/models/href/ListHref.js.map +1 -1
  66. package/lib/models/list/ListModel.js +7 -1
  67. package/lib/models/list/ListModel.js.map +1 -1
  68. package/lib/models/parameter/Parameter.js +6 -6
  69. package/lib/models/parameter/Parameter.js.map +1 -1
  70. package/package.json +4 -4
  71. package/src/hooks/useDeepCompareEffect.js +26 -10
  72. package/src/hooks/useList.js +17 -16
  73. package/src/hooks/useModularUIBasic.js +11 -1
  74. package/src/hooks/usePanel.js +1 -1
  75. package/src/hooks/useRouter.js +29 -23
  76. package/src/models/attributes/AttributeModel.js +14 -0
  77. package/src/models/attributes/CompositeAttributeModel.js +11 -11
  78. package/src/models/attributes/PasswordAttributeModel.js +3 -3
  79. package/src/models/filters/FilterModel.js +1 -1
  80. package/src/models/filters/RangeFilterModel.js +1 -1
  81. package/src/models/href/Href.js +30 -2
  82. package/src/models/href/ListHref.js +4 -2
  83. package/src/models/list/ListModel.js +8 -2
  84. package/src/models/parameter/Parameter.js +6 -6
@@ -4,7 +4,7 @@ import { useSelector } from "react-redux";
4
4
  import { useMemo } from "react";
5
5
  import { useModularUI } from "./useModularUI";
6
6
 
7
- import { MODULARUI_STATUS } from "../constants";
7
+ import { HTTP_METHODS, MODULARUI_STATUS } from "../constants";
8
8
  import { useModularUIKey } from "./useModularUIKey";
9
9
 
10
10
  import type { ModularUIModel, Href } from "../models";
@@ -13,6 +13,7 @@ export type HookOptions = {
13
13
  origin?: string,
14
14
  contextPath?: string,
15
15
  removeOnUnmount?: boolean,
16
+ formdata?: any,
16
17
  };
17
18
 
18
19
  export type UseModularUIBasicOptions<T: ModularUIModel> = {
@@ -25,6 +26,7 @@ export type UseModularUIBasicOptions<T: ModularUIModel> = {
25
26
  key?: string,
26
27
  isReload?: boolean,
27
28
  removeOnUnmount?: boolean,
29
+ formdata?: any,
28
30
  };
29
31
 
30
32
  // Helper to create useModularUI options
@@ -41,6 +43,8 @@ const createUseModularUIOptions = <T: ModularUIModel>(
41
43
  contextPath: undefined,
42
44
  cache: false,
43
45
  removeOnUnmount: false,
46
+ method: HTTP_METHODS.GET,
47
+ data: undefined,
44
48
  };
45
49
 
46
50
  // Handle targetModel and forceTargetModel
@@ -62,6 +66,11 @@ const createUseModularUIOptions = <T: ModularUIModel>(
62
66
  baseOptions.removeOnUnmount = true;
63
67
  }
64
68
 
69
+ if (options.formdata != null) {
70
+ baseOptions.method = HTTP_METHODS.POST;
71
+ baseOptions.data = options.formdata;
72
+ }
73
+
65
74
  // Handle origin and contextPath options
66
75
  baseOptions.origin = options.origin ?? baseOptions.origin;
67
76
  baseOptions.contextPath = options.contextPath ?? baseOptions.contextPath;
@@ -94,6 +103,7 @@ export const useModularUIBasic = <T: ModularUIModel>(
94
103
  origin: undefined,
95
104
  contextPath: undefined,
96
105
  key: undefined,
106
+ formdata: undefined,
97
107
  },
98
108
  ): T | null => {
99
109
  const memoizedHref = useMemo(() => href.toString(), [href]);
@@ -64,7 +64,7 @@ const useUrl = (href?: string | Href, fromRoute: boolean = false) => {
64
64
  */
65
65
  export const usePanel = (
66
66
  href?: string | Href,
67
- options?: HookOptions & { fromRoute?: boolean },
67
+ options?: { ...HookOptions, fromRoute?: boolean },
68
68
  ): ListModel | GroupingPanelModel | DetailModel | null => {
69
69
  const { fromRoute, ...hookOptions } = options || { fromRoute: false };
70
70
 
@@ -1,6 +1,6 @@
1
1
  // @flow
2
+ import { useMemo } from "react";
2
3
  import { useDispatch, useSelector } from "react-redux";
3
- import type { Location, LocationShape } from "react-router";
4
4
 
5
5
  import {
6
6
  push,
@@ -9,6 +9,8 @@ import {
9
9
  goBack,
10
10
  goForward,
11
11
  } from "../redux/_router/RouterActions";
12
+
13
+ import type { Location, LocationShape } from "react-router";
12
14
  import type {
13
15
  GoAction,
14
16
  GoBackAction,
@@ -17,48 +19,52 @@ import type {
17
19
  ReplaceAction,
18
20
  } from "../redux";
19
21
 
20
- type UseLocationHook = () => Location;
21
- type UseLocationKeyHook = () => string;
22
- type UseQuerystringHook = () => string;
23
- type UsePathnameHook = () => string;
24
- type UseNavigationHook = () => {
22
+ type NavigationAPI = {|
25
23
  push: (location: LocationShape | string, state?: { ... }) => PushAction,
26
24
  replace: (location: LocationShape | string, state?: { ... }) => ReplaceAction,
27
25
  go: (delta: number) => GoAction,
28
26
  goBack: () => GoBackAction,
29
27
  goForward: () => GoForwardAction,
30
- };
28
+ |};
31
29
 
32
30
  /**
31
+ * Returns the full location object from the router state.
33
32
  */
34
- export const useLocation: UseLocationHook = () =>
35
- useSelector((state) => state.router.location);
33
+ export const useLocation = (): Location =>
34
+ useSelector((state) => state.router?.location || {});
36
35
 
37
36
  /**
37
+ * Returns the unique key of the current location.
38
38
  */
39
- export const useLocationKey: UseLocationKeyHook = () =>
40
- useLocation()?.key ?? "";
39
+ export const useLocationKey = (): string =>
40
+ useSelector((state) => state.router?.location?.key ?? "");
41
41
 
42
42
  /**
43
+ * Returns the current search (querystring) portion of the URL.
43
44
  */
44
- export const useQuerystring: UseQuerystringHook = () => useLocation()?.search;
45
+ export const useQuerystring = (): string =>
46
+ useSelector((state) => state.router?.location?.search ?? "");
45
47
 
46
48
  /**
49
+ * Returns the current URL pathname.
47
50
  */
48
- export const usePathname: UsePathnameHook = () => useLocation()?.pathname;
51
+ export const usePathname = (): string =>
52
+ useSelector((state) => state.router?.location?.pathname ?? "");
49
53
 
50
54
  /**
55
+ * Provides navigation methods.
51
56
  */
52
- export const useNavigation: UseNavigationHook = () => {
57
+ export const useNavigation = (): NavigationAPI => {
53
58
  const dispatch = useDispatch();
54
59
 
55
- return {
56
- push: (location: LocationShape | string, state?: { ... }) =>
57
- dispatch(push(location, state)),
58
- replace: (location: LocationShape | string, state?: { ... }) =>
59
- dispatch(replace(location, state)),
60
- go: (delta: number) => dispatch(go(delta)),
61
- goBack: () => dispatch(goBack()),
62
- goForward: () => dispatch(goForward()),
63
- };
60
+ return useMemo(
61
+ () => ({
62
+ push: (location, state) => dispatch(push(location, state)),
63
+ replace: (location, state) => dispatch(replace(location, state)),
64
+ go: (delta) => dispatch(go(delta)),
65
+ goBack: () => dispatch(goBack()),
66
+ goForward: () => dispatch(goForward()),
67
+ }),
68
+ [dispatch],
69
+ );
64
70
  };
@@ -613,6 +613,20 @@ export default class AttributeModel
613
613
  return this.validate(this.validateValue);
614
614
  }
615
615
 
616
+ /**
617
+ * Get valid status
618
+ */
619
+ getIsValid(): boolean {
620
+ return this._isValid;
621
+ }
622
+
623
+ /**
624
+ * Set valid status
625
+ */
626
+ setIsValid(isValid: boolean) {
627
+ this._isValid = isValid;
628
+ }
629
+
616
630
  /**
617
631
  * Retrieve applicable constraint for this attribute
618
632
  */
@@ -155,13 +155,20 @@ class CompositeAttributeModel extends AttributeModel {
155
155
  return true;
156
156
  }
157
157
 
158
- this._isValid = this.children.validate();
158
+ let isValid = this.children.validate();
159
159
 
160
- if (this._isValid) {
161
- this._isValid = this.constraintCollection.validate();
160
+ if (isValid) {
161
+ isValid = this.constraintCollection.validate();
162
162
  }
163
163
 
164
- return this._isValid;
164
+ this.setIsValid(isValid);
165
+ return this.getIsValid();
166
+ }
167
+
168
+ /**
169
+ */
170
+ get isValid(): boolean {
171
+ return this.validate("");
165
172
  }
166
173
 
167
174
  /**
@@ -193,13 +200,6 @@ class CompositeAttributeModel extends AttributeModel {
193
200
  return constraints;
194
201
  }
195
202
 
196
- /**
197
- * Indicates if attribute input is valid
198
- */
199
- get isValid(): boolean {
200
- return this.validate("");
201
- }
202
-
203
203
  /**
204
204
  */
205
205
  hasServerErrors(): boolean {
@@ -222,13 +222,13 @@ export default class PasswordAttributeModel extends StringAttributeModel {
222
222
  }
223
223
 
224
224
  if (this.isOptionalAndEmpty(value)) {
225
- this._isValid = true;
225
+ this.setIsValid(true);
226
226
  } else if (this._validatedValue !== `${this.confirmValue}-${value}`) {
227
- this._isValid = this.constraintCollection.validate(value);
227
+ this.setIsValid(this.constraintCollection.validate(value));
228
228
  }
229
229
  this._validatedValue = `${this.confirmValue}-${value}`;
230
230
 
231
- return this._isValid;
231
+ return this.getIsValid();
232
232
  }
233
233
 
234
234
  /**
@@ -131,7 +131,7 @@ export default class FilterModel extends BaseFilterModel implements IFilter {
131
131
  * Inidiates if filter is valid
132
132
  */
133
133
  get isValid(): boolean {
134
- return this.attribute?.isValid || true;
134
+ return this.attribute?.isValid ?? true;
135
135
  }
136
136
 
137
137
  /**
@@ -13,7 +13,7 @@ export default class RangeFilterModel extends FilterModel implements IFilter {
13
13
  update(attribute: AttributeType, value: string) {
14
14
  if (this.attribute instanceof CompositeAttributeModel) {
15
15
  this.attribute.update(value, attribute);
16
- } else if (this.attribute !== null) {
16
+ } else if (this.attribute != null) {
17
17
  this.attribute.update(value);
18
18
  }
19
19
  }
@@ -322,7 +322,8 @@ class Href {
322
322
  (param) =>
323
323
  param.isModUIParameter &&
324
324
  (!prefix || !param.prefix || param.prefix === prefix) &&
325
- param.value != null,
325
+ param.value != null &&
326
+ param.value !== "",
326
327
  )
327
328
  .map((param) => param.toQuerystring(false))
328
329
  .join("&");
@@ -335,6 +336,15 @@ class Href {
335
336
  return this.getQuerystring(false);
336
337
  }
337
338
 
339
+ /**
340
+ * Retrieve all parameters from the parameter collection in a querystring style prefix~name1=value1&prefix~name2=value2, with the prefix
341
+ * The prefix is used to identify parameters per component on a grouping panel
342
+ * @returns {string}
343
+ */
344
+ get publicQuerystring(): string {
345
+ return this.getQuerystring(true);
346
+ }
347
+
338
348
  /**
339
349
  * Set the path of the Href, the part before the querystring question mark
340
350
  */
@@ -412,6 +422,23 @@ class Href {
412
422
  return this;
413
423
  }
414
424
 
425
+ /**
426
+ */
427
+ set formdata(formdata: any) {
428
+ const currentState = this.state ?? {};
429
+
430
+ this.state = {
431
+ ...currentState,
432
+ formdata,
433
+ };
434
+ }
435
+
436
+ /**
437
+ */
438
+ get formdata(): any {
439
+ return this.state?.formdata;
440
+ }
441
+
415
442
  /**
416
443
  * Set resourctype
417
444
  */
@@ -550,7 +577,8 @@ class Href {
550
577
  toLocation(): LocationShape {
551
578
  return {
552
579
  pathname: this.path,
553
- search: this.querystring.length > 0 ? `?${this.querystring}` : "",
580
+ search:
581
+ this.publicQuerystring.length > 0 ? `?${this.publicQuerystring}` : "",
554
582
  hash: this.hash.length > 0 ? `#${this.hash}` : "",
555
583
  state: {
556
584
  origin: this.origin,
@@ -28,7 +28,7 @@ export default class ListHref extends Href {
28
28
  this._isPrefixed = isPrefixed;
29
29
 
30
30
  if (list != null) {
31
- this.setParameterNamesFromListModel(list);
31
+ this.setParametersFromListModel(list);
32
32
  } else if (href != null && href instanceof ListHref) {
33
33
  this.setParameterNamesFromHref(href);
34
34
  }
@@ -47,7 +47,7 @@ export default class ListHref extends Href {
47
47
  /**
48
48
  * Retrieve parameter names and settings from List model
49
49
  */
50
- setParameterNamesFromListModel(list: ListModel) {
50
+ setParametersFromListModel(list: ListModel) {
51
51
  this._prefix = this._isPrefixed ? list.key : null;
52
52
 
53
53
  this._pagingName = list.paging ? list.paging.name : "";
@@ -65,6 +65,8 @@ export default class ListHref extends Href {
65
65
  this.sort = list.sorting && list.sorting.param ? list.sorting.param : null;
66
66
 
67
67
  this.filterCollection = list.filterCollection;
68
+
69
+ this.formdata = list.formdata;
68
70
  }
69
71
 
70
72
  /**
@@ -448,7 +448,13 @@ export default class ListModel extends ResourceModel {
448
448
 
449
449
  /**
450
450
  */
451
- get formdata(): string {
452
- return JSON.stringify(this.filterCollection.formdata);
451
+ get formdata(): string | null {
452
+ const { formdata } = this.filterCollection;
453
+
454
+ if (formdata != null) {
455
+ return JSON.stringify(formdata);
456
+ }
457
+
458
+ return null;
453
459
  }
454
460
  }
@@ -52,14 +52,14 @@ class Parameter {
52
52
  }
53
53
 
54
54
  // parameter has the structure prefix~name=value
55
- const namePart = parameter.substr(0, parameter.indexOf("="));
56
- const value = parameter.substr(parameter.indexOf("=") + 1);
55
+ const namePart = parameter.substring(0, parameter.indexOf("="));
56
+ const value = parameter.substring(parameter.indexOf("=") + 1);
57
57
 
58
58
  let prefix;
59
- let name = namePart;
60
- if (namePart.includes(PARAMETER_SEPARATOR)) {
61
- prefix = namePart.substr(0, namePart.indexOf("~"));
62
- name = namePart.substr(namePart.indexOf("~") + 1);
59
+ let name = decodeURIComponent(namePart);
60
+ if (name.includes(PARAMETER_SEPARATOR)) {
61
+ prefix = name.substring(0, name.indexOf("~"));
62
+ name = name.substring(name.indexOf("~") + 1);
63
63
  }
64
64
 
65
65
  if (name === "") {