@beinformed/ui 1.61.0 → 1.62.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/esm/models/attributes/__tests__/AttributeContent.spec.js.flow +1 -1
  3. package/esm/models/concepts/ConceptIndexModel.js +1 -1
  4. package/esm/models/concepts/ConceptIndexModel.js.flow +3 -1
  5. package/esm/models/concepts/ConceptIndexModel.js.map +1 -1
  6. package/esm/models/concepts/ConceptLinkModel.d.ts +15 -0
  7. package/esm/models/concepts/ConceptLinkModel.js +14 -0
  8. package/esm/models/concepts/ConceptLinkModel.js.flow +21 -0
  9. package/esm/models/concepts/ConceptLinkModel.js.map +1 -1
  10. package/esm/models/concepts/SourceReferenceModel.d.ts +9 -0
  11. package/esm/models/concepts/SourceReferenceModel.js +14 -0
  12. package/esm/models/concepts/SourceReferenceModel.js.flow +15 -1
  13. package/esm/models/concepts/SourceReferenceModel.js.map +1 -1
  14. package/esm/models/concepts/__mock__/related_concepts.js.flow +12 -0
  15. package/esm/models/concepts/__tests__/RelatedConcepts.spec.js.flow +60 -0
  16. package/esm/models/concepts/__tests__/SourceReferenceModel.spec.js.flow +58 -0
  17. package/esm/models/content/ContentLinkModel.d.ts +8 -0
  18. package/esm/models/content/ContentLinkModel.js +20 -0
  19. package/esm/models/content/ContentLinkModel.js.flow +22 -0
  20. package/esm/models/content/ContentLinkModel.js.map +1 -1
  21. package/esm/models/content/ContentTOCModel.d.ts +3 -0
  22. package/esm/models/content/ContentTOCModel.js +6 -0
  23. package/esm/models/content/ContentTOCModel.js.flow +6 -0
  24. package/esm/models/content/ContentTOCModel.js.map +1 -1
  25. package/esm/models/content/__tests__/ContentIndexModel.spec.js.flow +3 -0
  26. package/esm/models/content/__tests__/ContentModel.spec.js.flow +5 -5
  27. package/esm/models/content/__tests__/Formalsource.spec.js.flow +4 -0
  28. package/esm/models/form/FormObjectModel.js +5 -3
  29. package/esm/models/form/FormObjectModel.js.flow +12 -11
  30. package/esm/models/form/FormObjectModel.js.map +1 -1
  31. package/esm/models/types.d.ts +6 -0
  32. package/esm/models/types.js.flow +7 -0
  33. package/esm/models/types.js.map +1 -1
  34. package/esm/utils/helpers/__tests__/createHash.spec.js.flow +5 -5
  35. package/esm/utils/helpers/createHash.d.ts +2 -1
  36. package/esm/utils/helpers/createHash.js +10 -9
  37. package/esm/utils/helpers/createHash.js.flow +10 -10
  38. package/esm/utils/helpers/createHash.js.map +1 -1
  39. package/lib/models/concepts/ConceptIndexModel.js +1 -1
  40. package/lib/models/concepts/ConceptIndexModel.js.map +1 -1
  41. package/lib/models/concepts/ConceptLinkModel.d.ts +15 -0
  42. package/lib/models/concepts/ConceptLinkModel.js +14 -0
  43. package/lib/models/concepts/ConceptLinkModel.js.map +1 -1
  44. package/lib/models/concepts/SourceReferenceModel.d.ts +9 -0
  45. package/lib/models/concepts/SourceReferenceModel.js +14 -0
  46. package/lib/models/concepts/SourceReferenceModel.js.map +1 -1
  47. package/lib/models/content/ContentLinkModel.d.ts +8 -0
  48. package/lib/models/content/ContentLinkModel.js +20 -0
  49. package/lib/models/content/ContentLinkModel.js.map +1 -1
  50. package/lib/models/content/ContentTOCModel.d.ts +3 -0
  51. package/lib/models/content/ContentTOCModel.js +6 -0
  52. package/lib/models/content/ContentTOCModel.js.map +1 -1
  53. package/lib/models/form/FormObjectModel.js +5 -3
  54. package/lib/models/form/FormObjectModel.js.map +1 -1
  55. package/lib/models/types.d.ts +6 -0
  56. package/lib/models/types.js.map +1 -1
  57. package/lib/utils/helpers/createHash.d.ts +2 -1
  58. package/lib/utils/helpers/createHash.js +11 -9
  59. package/lib/utils/helpers/createHash.js.map +1 -1
  60. package/package.json +3 -1
  61. package/src/models/attributes/__tests__/AttributeContent.spec.js +1 -1
  62. package/src/models/concepts/ConceptIndexModel.js +3 -1
  63. package/src/models/concepts/ConceptLinkModel.js +21 -0
  64. package/src/models/concepts/SourceReferenceModel.js +15 -1
  65. package/src/models/concepts/__mock__/related_concepts.js +12 -0
  66. package/src/models/concepts/__mock__/related_concepts_contributions.json +41 -0
  67. package/src/models/concepts/__mock__/related_concepts_data.json +2292 -0
  68. package/src/models/concepts/__tests__/RelatedConcepts.spec.js +60 -0
  69. package/src/models/concepts/__tests__/SourceReferenceModel.spec.js +58 -0
  70. package/src/models/content/ContentLinkModel.js +22 -0
  71. package/src/models/content/ContentTOCModel.js +6 -0
  72. package/src/models/content/__tests__/ContentIndexModel.spec.js +3 -0
  73. package/src/models/content/__tests__/ContentModel.spec.js +5 -5
  74. package/src/models/content/__tests__/Formalsource.spec.js +4 -0
  75. package/src/models/content/__tests__/content-index.json +1 -0
  76. package/src/models/content/__tests__/formalsource-complete.json +1 -0
  77. package/src/models/form/FormObjectModel.js +12 -11
  78. package/src/models/types.js +7 -0
  79. package/src/utils/helpers/__tests__/createHash.spec.js +5 -5
  80. package/src/utils/helpers/createHash.js +10 -10
@@ -0,0 +1,60 @@
1
+ import { relatedConcepts } from "../__mock__/related_concepts";
2
+ import ConceptIndexModel from "../ConceptIndexModel";
3
+
4
+ describe("Related concepts", () => {
5
+ it("Should be able to create a relatedConceptsModel from RelatedConcepts json", () => {
6
+ expect(relatedConcepts).toBeInstanceOf(ConceptIndexModel);
7
+
8
+ expect(relatedConcepts.label).toBe("Related concepts of content");
9
+
10
+ expect(relatedConcepts.label).toBe("Related concepts of content");
11
+ expect(relatedConcepts.selfhref.toString()).toBe(
12
+ "/content/bundle-com.beinformed.source.Highlevelrequirements/ResearchGrant/High%20level%20requirements.formalsource/relatedConcepts?entryDate=2025-06-03",
13
+ );
14
+
15
+ expect(relatedConcepts.entryDate).toBe("2025-06-03");
16
+ expect(relatedConcepts.modelCategoryFilter.label).toBe("Model category");
17
+
18
+ expect(relatedConcepts.items.size).toBe(116);
19
+
20
+ const firstItem = relatedConcepts.items.first;
21
+ expect(firstItem.key).toBe(
22
+ "SystemMustSendAutomatedNotificationsForStatusChanges",
23
+ );
24
+ expect(firstItem.label).toBe(
25
+ "System must send automated notifications for status changes.",
26
+ );
27
+ expect(firstItem.modelCategory).toBe("Requirements");
28
+ expect(firstItem.selfhref.toString()).toBe(
29
+ "/concepts/bundle-com.beinformed.frames.ResearchGrantRequirements/frames.beimodel.json/SystemMustSendAutomatedNotificationsForStatusChanges?entryDate=2025-06-03",
30
+ );
31
+ expect(firstItem.conceptTypeLink.href.toString()).toBe(
32
+ "/concepttypes/bundle-com.beinformed.research.grant.metamodels/High%20level%20requirements.bixml/ArchitecturalSignificantRequirement",
33
+ );
34
+
35
+ expect(firstItem.fragment.sectionId).toBe(
36
+ "AutomatedNotifications_Requirement",
37
+ );
38
+ expect(firstItem.fragment.text).toBeUndefined();
39
+
40
+ const secondItem = relatedConcepts.items.get(1);
41
+
42
+ expect(secondItem.key).toBe(
43
+ "n74UsersHaveMaximumFlexibilityWithinPolicyConstraints",
44
+ );
45
+ expect(secondItem.label).toBe(
46
+ "Users have maximum flexibility within policy constraints",
47
+ );
48
+
49
+ expect(secondItem.modelCategory).toBe("Requirements");
50
+
51
+ expect(secondItem.fragment.sectionId).toBe(
52
+ "MaximumFlexibilityWithinPolicyConstraints",
53
+ );
54
+ expect(secondItem.fragment.text).toBe(
55
+ "<p>Users have maximum flexibility within policy constraints</p>",
56
+ );
57
+ expect(secondItem.fragment.startOffset).toBe(0);
58
+ expect(secondItem.fragment.endOffset).toBe(56);
59
+ });
60
+ });
@@ -1,9 +1,67 @@
1
1
  import SourceReferenceModel from "../SourceReferenceModel";
2
2
 
3
+ const data = {
4
+ label: "Requirement: Implement scoring systems based on predefined cr...",
5
+ type: "Reference",
6
+ sourceLabel: "High level requirements",
7
+ sourceAbbreviation: "HLR-01",
8
+ _links: {
9
+ self: {
10
+ href: "/content/bundle-com.beinformed.source.Highlevelrequirements/ResearchGrant/High%20level%20requirements.formalsource/ScoringAndEvaluationCriteria#ScoringAndEvaluationCriteria_Requirement",
11
+ },
12
+ content: {
13
+ href: "/content/bundle-com.beinformed.source.Highlevelrequirements/ResearchGrant/High%20level%20requirements.formalsource",
14
+ },
15
+ },
16
+ sectionFragment: {
17
+ text: "Implement scoring systems based on predefined criteria.",
18
+ startOffset: 12,
19
+ endOffset: 68,
20
+ },
21
+ };
22
+
3
23
  describe("sourceReferenceModel", () => {
4
24
  it("should be able to create an empty SourceReferenceModel object", () => {
5
25
  const sourceReference = new SourceReferenceModel();
6
26
 
7
27
  expect(sourceReference).toBeInstanceOf(SourceReferenceModel);
8
28
  });
29
+
30
+ it("can handle source reference data", () => {
31
+ const sourceReference = new SourceReferenceModel(data);
32
+
33
+ expect(sourceReference.label).toBe(
34
+ "Requirement: Implement scoring systems based on predefined cr...",
35
+ );
36
+ expect(sourceReference.sourceLabel).toBe("High level requirements");
37
+ expect(sourceReference.type).toBe("Reference");
38
+ expect(sourceReference.sourceAbbreviation).toBe("HLR-01");
39
+ expect(sourceReference.referenceHash).toBe(6767520005362);
40
+ expect(sourceReference.fragment.text).toBe(
41
+ "Implement scoring systems based on predefined criteria.",
42
+ );
43
+ expect(sourceReference.fragment.startOffset).toBe(12);
44
+ expect(sourceReference.fragment.endOffset).toBe(68);
45
+
46
+ expect(sourceReference.link.label).toBe(
47
+ "Requirement: Implement scoring systems based on predefined cr...",
48
+ );
49
+ expect(sourceReference.link.sourceLabel).toBe("High level requirements");
50
+ expect(sourceReference.link.abbreviation).toBe("HLR-01");
51
+ expect(sourceReference.link.selfhref.path).toBe(
52
+ "/content/bundle-com.beinformed.source.Highlevelrequirements/ResearchGrant/High%20level%20requirements.formalsource/ScoringAndEvaluationCriteria",
53
+ );
54
+
55
+ expect(sourceReference.link.fragment.text).toBe(
56
+ "Implement scoring systems based on predefined criteria.",
57
+ );
58
+ expect(sourceReference.link.fragment.startOffset).toBe(12);
59
+ expect(sourceReference.link.fragment.endOffset).toBe(68);
60
+
61
+ expect(sourceReference.link.selfhref.state.fragment.text).toBe(
62
+ "Implement scoring systems based on predefined criteria.",
63
+ );
64
+ expect(sourceReference.link.selfhref.state.fragment.startOffset).toBe(12);
65
+ expect(sourceReference.link.selfhref.state.fragment.endOffset).toBe(68);
66
+ });
9
67
  });
@@ -11,6 +11,7 @@ import type {
11
11
  ModularUIModel,
12
12
  IModelWithChildModels,
13
13
  ModelOptions,
14
+ SectionFragment,
14
15
  } from "../types";
15
16
 
16
17
  /**
@@ -107,6 +108,13 @@ export default class ContentLinkModel
107
108
  return this.getData("sourceLabel");
108
109
  }
109
110
 
111
+ /**
112
+ *
113
+ */
114
+ get abbreviation(): string | null {
115
+ return this.getData("abbreviation") || this.getData("sourceAbbreviation");
116
+ }
117
+
110
118
  /**
111
119
  */
112
120
  createEncodedHref(): Href {
@@ -177,6 +185,14 @@ export default class ContentLinkModel
177
185
  );
178
186
  }
179
187
 
188
+ if (!selflink.href.state) {
189
+ selflink.href.state = {
190
+ fragment: this.fragment,
191
+ };
192
+ } else {
193
+ selflink.href.state.fragment = this.fragment;
194
+ }
195
+
180
196
  return selflink;
181
197
  }
182
198
 
@@ -217,6 +233,12 @@ export default class ContentLinkModel
217
233
  return null;
218
234
  }
219
235
 
236
+ /**
237
+ */
238
+ get fragment(): SectionFragment | void {
239
+ return this.data.sectionFragment;
240
+ }
241
+
220
242
  /**
221
243
  * Children of link model in TOC
222
244
  */
@@ -92,6 +92,12 @@ export default class ContentTOCModel extends ResourceModel {
92
92
  return this.getData("label", "");
93
93
  }
94
94
 
95
+ /**
96
+ */
97
+ get abbreviation(): string | null {
98
+ return this.getData("abbreviation");
99
+ }
100
+
95
101
  /**
96
102
  * Getting the self link of this list
97
103
  */
@@ -30,6 +30,9 @@ describe("content index model", () => {
30
30
  const firstLink = contentIndexModel.items.first;
31
31
  expect(firstLink).toBeInstanceOf(ContentLinkModel);
32
32
 
33
+ expect(firstLink.label).toBe("Another formal content");
34
+ expect(firstLink.abbreviation).toBe("AFC-01");
35
+
33
36
  expect(firstLink.encodedHref.toString()).toBe(
34
37
  "/content/Content%2FSources%2FFormal%2FAnother%2520formal%2520content.formalsource",
35
38
  );
@@ -67,7 +67,7 @@ describe("contentmodel", () => {
67
67
  expect(contentModel.relatedConceptsHref.href.toString()).toBe(
68
68
  "/content/Incident/Business design/Content/Blaastest.bixml/67beed02/relatedConcepts?entryDate=2021-08-31",
69
69
  );
70
- expect(contentModel.referenceHash).toBe(-484527882);
70
+ expect(contentModel.referenceHash).toBe(9969574676612);
71
71
  });
72
72
 
73
73
  it("can handle content service with childsections", () => {
@@ -106,7 +106,7 @@ describe("contentmodel", () => {
106
106
  expect(contentModel.relatedConceptsHref.href.toString()).toBe(
107
107
  "/content/Incident/Business design/Content/Blaastest.textilesource/uitslag/relatedConcepts?entryDate=2021-08-31",
108
108
  );
109
- expect(contentModel.referenceHash).toBe(372690030);
109
+ expect(contentModel.referenceHash).toBe(8236987459042);
110
110
 
111
111
  const firstChildSectionLink = contentModel.childSectionLinks[0];
112
112
  expect(firstChildSectionLink instanceof ContentLinkModel).toBe(true);
@@ -174,7 +174,7 @@ describe("contentmodel", () => {
174
174
  expect(contentModel.subSections).toHaveLength(4);
175
175
  expect(contentModel.relatedConceptsHrefs).toHaveLength(4);
176
176
  expect(contentModel.relatedConceptsHref).toBeNull();
177
- expect(contentModel.referenceHash).toBe(-1980124898);
177
+ expect(contentModel.referenceHash).toBe(3949483866644);
178
178
 
179
179
  const firstSubSection = contentModel.subSections[0];
180
180
  expect(firstSubSection instanceof SubSectionModel).toBe(true);
@@ -199,8 +199,8 @@ describe("contentmodel", () => {
199
199
  "/content/Incident/Business design/Content/Blaastest subsections.formalsource/Pass/relatedConcepts?entryDate=2021-08-31",
200
200
  );
201
201
  expect(firstSubSection.relatedConceptsHref.getReferenceHash()).toBe(
202
- 145842294,
202
+ 7092890320518,
203
203
  );
204
- expect(firstSubSection.referenceHash).toBe(145842294);
204
+ expect(firstSubSection.referenceHash).toBe(7092890320518);
205
205
  });
206
206
  });
@@ -55,6 +55,10 @@ describe("formalsource", () => {
55
55
  expect(completeModel.sections[0].sections).toHaveLength(0);
56
56
  expect(completeModel.sections[1].sections).toHaveLength(2);
57
57
 
58
+ expect(completeModel.label).toBe(
59
+ "Grant Funding Agreement - Terms and Conditions",
60
+ );
61
+ expect(completeModel.abbreviation).toBe("GFA-TC-01");
58
62
  expect(completeModel.isCompleteSource).toBe(true);
59
63
 
60
64
  const firstSection = completeModel.sections[0];
@@ -147,6 +147,7 @@
147
147
  "content": {
148
148
  "_id": "/Content/Sources/Formal/Another formal content.formalsource",
149
149
  "label": "Another formal content",
150
+ "abbreviation": "AFC-01",
150
151
  "_links": {
151
152
  "self": {
152
153
  "href": "/content/Content/Sources/Formal/Another%20formal%20content.formalsource"
@@ -31,6 +31,7 @@
31
31
  }
32
32
  },
33
33
  "label": "Grant Funding Agreement - Terms and Conditions",
34
+ "abbreviation": "GFA-TC-01",
34
35
  "sections": [
35
36
  {
36
37
  "_links": {
@@ -541,17 +541,18 @@ export default class FormObjectModel extends BaseModel {
541
541
  }
542
542
  }
543
543
 
544
- errors
545
- .filter(
546
- (error) =>
547
- error.id === "Constraint.Mandatory" &&
548
- error.anchor?.objectid === this.key &&
549
- has(error.anchor, "elementid"),
550
- )
551
- .forEach((error) => {
552
- attributeErrors.push(error);
553
- });
554
-
544
+ if (Array.isArray(errors)) {
545
+ errors
546
+ .filter(
547
+ (error) =>
548
+ error.id === "Constraint.Mandatory" &&
549
+ error.anchor?.objectid === this.key &&
550
+ has(error.anchor, "elementid"),
551
+ )
552
+ .forEach((error) => {
553
+ attributeErrors.push(error);
554
+ });
555
+ }
555
556
  this.attributeCollection.updateValidations(attributeErrors);
556
557
  }
557
558
 
@@ -262,6 +262,13 @@ export type ContentData = {
262
262
  elements: Array<PropertyElement | TextFragmentElement | ContentElement>,
263
263
  };
264
264
 
265
+ export type SectionFragment = {
266
+ sectionId?: string,
267
+ text: string,
268
+ startOffset: number,
269
+ endOffset: number,
270
+ };
271
+
265
272
  export type ModelOptions = {
266
273
  origin?: ?string,
267
274
  contextPath?: ?string,
@@ -2,10 +2,10 @@ import { createHash } from "../createHash";
2
2
 
3
3
  describe("createHash", () => {
4
4
  it("creates hash from string", () => {
5
- expect(createHash("")).toBe(0);
6
- expect(createHash("abcdefgh")).toBe(1259673732);
7
- expect(createHash(123455)).toBe(0);
8
- expect(createHash(null)).toBe(0);
9
- expect(createHash()).toBe(0);
5
+ expect(createHash("")).toBe(729279156);
6
+ expect(createHash("abcdefgh")).toBe(17595859189820);
7
+ expect(createHash(123455)).toBe(15900277965517);
8
+ expect(createHash(null)).toBe(711079339769);
9
+ expect(createHash()).toBe(4721361581144);
10
10
  });
11
11
  });
@@ -1,28 +1,28 @@
1
1
  // @flow
2
+ import hash from "hash-it";
3
+
2
4
  import type Href from "../../models/href/Href";
5
+ import type { SectionFragment } from "../../models";
3
6
 
4
7
  /**
5
8
  * https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
6
9
  */
7
10
  const createHash = (str: string): number => {
8
- if (!str) return 0;
9
-
10
- let hash = 0;
11
- for (let i = 0; i < str.length; i++) {
12
- hash = (hash << 5) - hash + str.charCodeAt(i);
13
- hash = hash & hash;
14
- }
15
- return hash;
11
+ return hash(str);
16
12
  };
17
13
 
18
14
  /**
19
15
  */
20
- const createHashFromHref = (href: Href): number => {
16
+ const createHashFromHref = (href: Href, fragment?: SectionFragment): number => {
21
17
  const hrefString = href.hash
22
18
  ? [href.toString(), href.hash].join("#")
23
19
  : href.toString();
24
20
 
25
- return createHash(hrefString);
21
+ if (fragment) {
22
+ return hash({ hrefString, fragment });
23
+ }
24
+
25
+ return hash(hrefString);
26
26
  };
27
27
 
28
28
  export { createHash, createHashFromHref };