@uxland/primary-shell 1.1.0 → 2.0.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/README.md +231 -0
- package/dist/UI/components/clinical-monitoring/clinical-monitoring.d.ts +11 -0
- package/dist/UI/components/clinical-monitoring/template.d.ts +3 -0
- package/dist/UI/components/index.d.ts +1 -0
- package/dist/UI/components/primaria-breadcumbs/primaria-breadcumbs.d.ts +9 -0
- package/dist/UI/components/primaria-breadcumbs/template.d.ts +3 -0
- package/dist/UI/components/primaria-shell/primaria-shell.d.ts +14 -0
- package/dist/UI/components/primaria-shell/template.d.ts +3 -0
- package/dist/UI/components/title-view/template.d.ts +3 -0
- package/dist/UI/components/title-view/title-view.d.ts +9 -0
- package/dist/UI/index.d.ts +2 -0
- package/dist/UI/shared-components/dss-container/dss-container.d.ts +7 -0
- package/dist/UI/shared-components/index.d.ts +2 -0
- package/dist/UI/shared-components/primaria-content-switcher/primaria-content-switcher.d.ts +14 -0
- package/dist/UI/shared-components/primaria-interaction/components/dialog-component.d.ts +20 -0
- package/dist/UI/shared-components/primaria-interaction/components/notifier-component.d.ts +12 -0
- package/dist/UI/shared-components/primaria-interaction/confirm-mixin.d.ts +16 -0
- package/dist/UI/shared-components/primaria-interaction/confirm.d.ts +3 -0
- package/dist/UI/shared-components/primaria-interaction/index.d.ts +4 -0
- package/dist/UI/shared-components/primaria-interaction/notify.d.ts +4 -0
- package/dist/UI/shared-components/primaria-interaction/typings.d.ts +28 -0
- package/dist/UI/shared-components/primaria-menu-item/primaria-menu-item.d.ts +10 -0
- package/dist/UI/shared-components/primaria-menu-item/template.d.ts +3 -0
- package/dist/UI/shared-components/primaria-text-editor/primaria-rich-text-editor.d.ts +57 -0
- package/dist/UI/shared-components/primaria-text-editor/template.d.ts +1 -0
- package/dist/UI/shared-components/primaria-text-editor/utils.d.ts +1 -0
- package/dist/UI/styles/theme/apply-theme.d.ts +1 -0
- package/dist/api/api.d.ts +27 -0
- package/dist/api/broker/factory.d.ts +3 -0
- package/dist/api/broker/factory.test.d.ts +1 -0
- package/dist/api/broker/primaria-broker.d.ts +5 -0
- package/dist/api/global-state/global-state.d.ts +35 -0
- package/dist/api/global-state/global-state.test.d.ts +1 -0
- package/dist/api/interaction-manager/interaction.d.ts +8 -0
- package/dist/api/localization/localization.test.d.ts +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +26335 -239
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +8647 -0
- package/dist/index.umd.cjs.map +1 -0
- package/dist/initializer.d.ts +1 -0
- package/dist/locales.d.ts +15 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/region-manager.d.ts +16 -0
- package/dist/regions.d.ts +14 -0
- package/dist/style.css +3 -0
- package/package.json +23 -15
- package/src/UI/components/clinical-monitoring/clinical-monitoring.ts +28 -0
- package/src/UI/components/clinical-monitoring/styles.scss +29 -0
- package/src/UI/components/clinical-monitoring/template.ts +12 -0
- package/src/UI/components/index.ts +5 -0
- package/src/UI/components/primaria-breadcumbs/primaria-breadcumbs.ts +27 -0
- package/src/UI/components/primaria-breadcumbs/styles.scss +25 -0
- package/src/UI/components/primaria-breadcumbs/template.ts +15 -0
- package/src/UI/components/primaria-shell/primaria-shell.ts +37 -0
- package/src/UI/components/primaria-shell/styles.scss +68 -0
- package/src/UI/components/primaria-shell/template.ts +94 -0
- package/src/UI/components/title-view/styles.scss +5 -0
- package/src/UI/components/title-view/template.ts +6 -0
- package/src/UI/components/title-view/title-view.ts +23 -0
- package/src/UI/images/Gencat_Logotip.svg +70 -0
- package/src/UI/images/Salut_Logotip.svg +8 -0
- package/src/UI/index.ts +2 -0
- package/src/UI/shared-components/design-system.css +1 -0
- package/src/UI/shared-components/dss-container/dss-container.ts +32 -0
- package/src/UI/shared-components/dss-container/styles.scss +23 -0
- package/src/UI/shared-components/index.ts +5 -0
- package/src/UI/shared-components/primaria-content-switcher/primaria-content-switcher.ts +79 -0
- package/src/UI/shared-components/primaria-interaction/components/dialog-component-styles.scss +155 -0
- package/src/UI/shared-components/primaria-interaction/components/dialog-component.ts +120 -0
- package/src/UI/shared-components/primaria-interaction/components/notifier-component-styles.scss +128 -0
- package/src/UI/shared-components/primaria-interaction/components/notifier-component.ts +73 -0
- package/src/UI/shared-components/primaria-interaction/confirm-mixin.ts +39 -0
- package/src/UI/shared-components/primaria-interaction/confirm.ts +30 -0
- package/src/UI/shared-components/primaria-interaction/index.ts +4 -0
- package/src/UI/shared-components/primaria-interaction/notify.ts +153 -0
- package/src/UI/shared-components/primaria-interaction/typings.ts +32 -0
- package/src/UI/shared-components/primaria-menu-item/primaria-menu-item.ts +25 -0
- package/src/UI/shared-components/primaria-menu-item/styles.scss +10 -0
- package/src/UI/shared-components/primaria-menu-item/template.ts +8 -0
- package/src/UI/shared-components/primaria-text-editor/primaria-rich-text-editor.ts +230 -0
- package/src/UI/shared-components/primaria-text-editor/styles.scss +972 -0
- package/src/UI/shared-components/primaria-text-editor/template.ts +8 -0
- package/src/UI/shared-components/primaria-text-editor/utils.ts +39 -0
- package/src/UI/styles/_flex-layout.scss +203 -0
- package/src/UI/styles/_normalize.scss +3 -0
- package/src/UI/styles/_variables.scss +40 -0
- package/src/UI/styles/styles.scss +3 -0
- package/src/UI/styles/theme/apply-theme.ts +11 -0
- package/src/api/api.ts +63 -0
- package/src/api/broker/factory.test.ts +124 -0
- package/src/api/broker/factory.ts +122 -0
- package/src/api/broker/primaria-broker.ts +11 -0
- package/src/api/global-state/global-state.test.ts +53 -0
- package/src/api/global-state/global-state.ts +49 -0
- package/src/api/interaction-manager/interaction.ts +21 -0
- package/src/api/localization/localization.test.ts +61 -0
- package/src/api/localization/localization.ts +54 -0
- package/src/constants.ts +2 -0
- package/src/index.ts +12 -0
- package/src/initializer.ts +39 -4
- package/src/locales.ts +24 -0
- package/src/plugin.ts +9 -0
- package/src/region-manager.ts +155 -0
- package/src/regions.ts +17 -6
- package/dist/index.mjs +0 -3209
- package/index.ts +0 -3
- package/src/primary-shell.ts +0 -78
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//Hay una issue detectada en el component quilljs que borra algunas palabras/parrafos al corregir palabras con el corrector del navegador
|
|
2
|
+
//Sólo pasa cuando el texto se ha copiado y enganchado de una fuente externa y contiene estilos(negritas, colores, etc).
|
|
3
|
+
//https://github.com/quilljs/quill/issues/2096
|
|
4
|
+
//Este fix corrige este comportamiento.
|
|
5
|
+
export const fixSpellCheckerIssue = (Quill) => {
|
|
6
|
+
const Inline = Quill.import("blots/inline");
|
|
7
|
+
|
|
8
|
+
class CustomAttributes extends Inline {
|
|
9
|
+
constructor(domNode, value) {
|
|
10
|
+
super(domNode, value);
|
|
11
|
+
|
|
12
|
+
const span = this.replaceWith(new Inline(Inline.create()));
|
|
13
|
+
|
|
14
|
+
span.children.forEach((child) => {
|
|
15
|
+
if (child.attributes) child.attributes.copy(span);
|
|
16
|
+
if (child.unwrap) child.unwrap();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// here we apply every attribute from <font> tag to span as a style
|
|
20
|
+
Object.keys(domNode.attributes).forEach(function (key) {
|
|
21
|
+
if (domNode.attributes[key].name != "style") {
|
|
22
|
+
const val = domNode.attributes[key].value;
|
|
23
|
+
let name = domNode.attributes[key].name;
|
|
24
|
+
if (name == "face") name = "font-family";
|
|
25
|
+
span.format(name, val);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.remove();
|
|
30
|
+
|
|
31
|
+
return span;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
CustomAttributes.blotName = "customAttributes";
|
|
36
|
+
CustomAttributes.tagName = "FONT";
|
|
37
|
+
|
|
38
|
+
Quill.register(CustomAttributes, true);
|
|
39
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
@mixin layout {
|
|
2
|
+
display: flex;
|
|
3
|
+
}
|
|
4
|
+
@mixin layout-inline {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
}
|
|
7
|
+
@mixin layout-horizontal {
|
|
8
|
+
@include layout;
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
}
|
|
11
|
+
@mixin layout-horizontal-reverse {
|
|
12
|
+
@include layout;
|
|
13
|
+
flex-direction: row-reverse;
|
|
14
|
+
}
|
|
15
|
+
@mixin layout-vertical {
|
|
16
|
+
@include layout;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
}
|
|
19
|
+
@mixin layout-vertical-reverse {
|
|
20
|
+
@include layout;
|
|
21
|
+
flex-direction: column-reverse;
|
|
22
|
+
}
|
|
23
|
+
@mixin layout-wrap {
|
|
24
|
+
flex-wrap: wrap;
|
|
25
|
+
}
|
|
26
|
+
@mixin layout-wrap-reverse {
|
|
27
|
+
flex-wrap: wrap-reverse;
|
|
28
|
+
}
|
|
29
|
+
@mixin layout-flex-auto {
|
|
30
|
+
flex: 1 1 auto;
|
|
31
|
+
}
|
|
32
|
+
@mixin layout-flex-none {
|
|
33
|
+
flex: none;
|
|
34
|
+
}
|
|
35
|
+
@mixin layout-flex {
|
|
36
|
+
flex: 1;
|
|
37
|
+
}
|
|
38
|
+
@mixin layout-flex-2 {
|
|
39
|
+
flex: 2;
|
|
40
|
+
}
|
|
41
|
+
@mixin layout-flex-3 {
|
|
42
|
+
flex: 3;
|
|
43
|
+
}
|
|
44
|
+
@mixin layout-flex-4 {
|
|
45
|
+
flex: 4;
|
|
46
|
+
}
|
|
47
|
+
@mixin layout-flex-5 {
|
|
48
|
+
flex: 5;
|
|
49
|
+
}
|
|
50
|
+
@mixin layout-flex-6 {
|
|
51
|
+
flex: 6;
|
|
52
|
+
}
|
|
53
|
+
@mixin layout-flex-7 {
|
|
54
|
+
flex: 7;
|
|
55
|
+
}
|
|
56
|
+
@mixin layout-flex-8 {
|
|
57
|
+
flex: 8;
|
|
58
|
+
}
|
|
59
|
+
@mixin layout-flex-9 {
|
|
60
|
+
flex: 9;
|
|
61
|
+
}
|
|
62
|
+
@mixin layout-flex-10 {
|
|
63
|
+
flex: 10;
|
|
64
|
+
}
|
|
65
|
+
@mixin layout-flex-11 {
|
|
66
|
+
flex: 11;
|
|
67
|
+
}
|
|
68
|
+
@mixin layout-flex-12 {
|
|
69
|
+
flex: 12;
|
|
70
|
+
}
|
|
71
|
+
@mixin layout-start {
|
|
72
|
+
align-items: flex-start;
|
|
73
|
+
}
|
|
74
|
+
@mixin layout-center {
|
|
75
|
+
align-items: center;
|
|
76
|
+
}
|
|
77
|
+
@mixin layout-end {
|
|
78
|
+
align-items: flex-end;
|
|
79
|
+
}
|
|
80
|
+
@mixin layout-baseline {
|
|
81
|
+
align-items: baseline;
|
|
82
|
+
}
|
|
83
|
+
@mixin layout-stretch {
|
|
84
|
+
align-items: stretch;
|
|
85
|
+
}
|
|
86
|
+
@mixin layout-start-justified {
|
|
87
|
+
justify-content: flex-start;
|
|
88
|
+
}
|
|
89
|
+
@mixin layout-center-justified {
|
|
90
|
+
justify-content: center;
|
|
91
|
+
}
|
|
92
|
+
@mixin layout-end-justified {
|
|
93
|
+
justify-content: flex-end;
|
|
94
|
+
}
|
|
95
|
+
@mixin layout-around-justified {
|
|
96
|
+
justify-content: space-around;
|
|
97
|
+
}
|
|
98
|
+
@mixin layout-justified {
|
|
99
|
+
justify-content: space-between;
|
|
100
|
+
}
|
|
101
|
+
@mixin layout-center-center {
|
|
102
|
+
@include layout-center;
|
|
103
|
+
@include layout-center-justified;
|
|
104
|
+
}
|
|
105
|
+
@mixin layout-self-start {
|
|
106
|
+
align-self: flex-start;
|
|
107
|
+
}
|
|
108
|
+
@mixin layout-self-center {
|
|
109
|
+
align-self: center;
|
|
110
|
+
}
|
|
111
|
+
@mixin layout-self-end {
|
|
112
|
+
align-self: flex-end;
|
|
113
|
+
}
|
|
114
|
+
@mixin layout-self-stretch {
|
|
115
|
+
align-self: stretch;
|
|
116
|
+
}
|
|
117
|
+
@mixin layout-self-baseline {
|
|
118
|
+
align-self: baseline;
|
|
119
|
+
}
|
|
120
|
+
@mixin layout-start-aligned {
|
|
121
|
+
align-content: flex-start;
|
|
122
|
+
}
|
|
123
|
+
@mixin layout-end-aligned {
|
|
124
|
+
align-content: flex-end;
|
|
125
|
+
}
|
|
126
|
+
@mixin layout-center-aligned {
|
|
127
|
+
align-content: center;
|
|
128
|
+
}
|
|
129
|
+
@mixin layout-between-aligned {
|
|
130
|
+
align-content: space-between;
|
|
131
|
+
}
|
|
132
|
+
@mixin layout-around-aligned {
|
|
133
|
+
align-content: space-around;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@mixin layout-block {
|
|
137
|
+
display: block;
|
|
138
|
+
}
|
|
139
|
+
@mixin layout-invisible {
|
|
140
|
+
visibility: hidden !important;
|
|
141
|
+
}
|
|
142
|
+
@mixin layout-relative {
|
|
143
|
+
position: relative;
|
|
144
|
+
}
|
|
145
|
+
@mixin layout-fit {
|
|
146
|
+
position: absolute;
|
|
147
|
+
top: 0;
|
|
148
|
+
right: 0;
|
|
149
|
+
bottom: 0;
|
|
150
|
+
left: 0;
|
|
151
|
+
}
|
|
152
|
+
@mixin layout-scroll {
|
|
153
|
+
overflow: auto;
|
|
154
|
+
}
|
|
155
|
+
@mixin layout-fullbleed {
|
|
156
|
+
margin: 0;
|
|
157
|
+
height: 100vh;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@mixin layout-fixed-top {
|
|
161
|
+
position: fixed;
|
|
162
|
+
top: 0;
|
|
163
|
+
left: 0;
|
|
164
|
+
right: 0;
|
|
165
|
+
}
|
|
166
|
+
@mixin layout-fixed-right {
|
|
167
|
+
position: fixed;
|
|
168
|
+
top: 0;
|
|
169
|
+
right: 0;
|
|
170
|
+
bottom: 0;
|
|
171
|
+
}
|
|
172
|
+
@mixin layout-fixed-bottom {
|
|
173
|
+
position: fixed;
|
|
174
|
+
right: 0;
|
|
175
|
+
bottom: 0;
|
|
176
|
+
left: 0;
|
|
177
|
+
}
|
|
178
|
+
@mixin layout-fixed-left {
|
|
179
|
+
position: fixed;
|
|
180
|
+
top: 0;
|
|
181
|
+
bottom: 0;
|
|
182
|
+
left: 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@mixin horizontal-center {
|
|
186
|
+
@include layout-horizontal;
|
|
187
|
+
@include layout-center;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@mixin vertical-center {
|
|
191
|
+
@include layout-vertical;
|
|
192
|
+
@include layout-center;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@mixin horizontal-center-justified {
|
|
196
|
+
@include horizontal-center;
|
|
197
|
+
@include layout-justified;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@mixin vertical-flex {
|
|
201
|
+
@include layout-vertical;
|
|
202
|
+
@include layout-flex;
|
|
203
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
$font-weight-light: 300;
|
|
2
|
+
$font-weight-regular: 400;
|
|
3
|
+
$font-weight-medium: 500;
|
|
4
|
+
$font-weight-semi-bold: 600;
|
|
5
|
+
$font-weight-bold: 700;
|
|
6
|
+
|
|
7
|
+
$font-size-4: 0.285714285714286rem;
|
|
8
|
+
$font-size-5: 0.357142857142857rem;
|
|
9
|
+
$font-size-8: 0.5714rem;
|
|
10
|
+
$font-size-9: 0.6429rem;
|
|
11
|
+
$font-size-10: 0.7143rem;
|
|
12
|
+
$font-size-11: 0.7857rem;
|
|
13
|
+
$font-size-12: 0.8571rem;
|
|
14
|
+
$font-size-13: 0.9286rem;
|
|
15
|
+
$font-size-14: 1rem;
|
|
16
|
+
$font-size-15: 1.071rem;
|
|
17
|
+
$font-size-16: 1.143rem;
|
|
18
|
+
$font-size-18: 1.286rem;
|
|
19
|
+
$font-size-20: 1.429rem;
|
|
20
|
+
$font-size-22: 1.571rem;
|
|
21
|
+
$font-size-24: 1.714rem;
|
|
22
|
+
$font-size-26: 1.857rem;
|
|
23
|
+
$font-size-28: 2rem;
|
|
24
|
+
$font-size-30: 2.143rem;
|
|
25
|
+
$font-size-32: 2.286rem;
|
|
26
|
+
$font-size-34: 2.429rem;
|
|
27
|
+
$font-size-36: 2.571rem;
|
|
28
|
+
$font-size-38: 2.714rem;
|
|
29
|
+
$font-size-40: 2.857rem;
|
|
30
|
+
$font-size-42: 3rem;
|
|
31
|
+
$font-size-44: 3.143rem;
|
|
32
|
+
$font-size-46: 3.286rem;
|
|
33
|
+
$font-size-48: 3.429rem;
|
|
34
|
+
$font-size-50: 3.571rem;
|
|
35
|
+
$font-size-52: 3.714rem;
|
|
36
|
+
$font-size-54: 3.857rem;
|
|
37
|
+
$font-size-56: 4rem;
|
|
38
|
+
$font-size-58: 4.143rem;
|
|
39
|
+
$font-size-60: 4.286rem;
|
|
40
|
+
$font-size-120: 8.571428571428571rem;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const themeCSSVariables = `
|
|
2
|
+
:root{
|
|
3
|
+
--primaria-primary-color: #0054A8;
|
|
4
|
+
}
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
export const appendTheme = () => {
|
|
8
|
+
const styleElement = document.createElement("style");
|
|
9
|
+
styleElement.appendChild(document.createTextNode(themeCSSVariables));
|
|
10
|
+
document.head.appendChild(styleElement);
|
|
11
|
+
};
|
package/src/api/api.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiFactory,
|
|
3
|
+
HarmonixApi,
|
|
4
|
+
IRegionManager,
|
|
5
|
+
PluginInfo,
|
|
6
|
+
createRegionHost,
|
|
7
|
+
createRegionManager,
|
|
8
|
+
} from "@uxland/harmonix";
|
|
9
|
+
import { createLocaleManager } from "./localization/localization";
|
|
10
|
+
import { PrimariaRegionManager, createRegionManagerProxy } from "../region-manager";
|
|
11
|
+
import {
|
|
12
|
+
PrimariaInteractionManager,
|
|
13
|
+
createInteractionManager,
|
|
14
|
+
} from "./interaction-manager/interaction";
|
|
15
|
+
import { PrimariaGlobalStateManager, createGlobalStateManager } from "./global-state/global-state";
|
|
16
|
+
import { PrimariaBroker } from "./broker/primaria-broker";
|
|
17
|
+
import { createBroker } from "./broker/factory";
|
|
18
|
+
const broker = createBroker();
|
|
19
|
+
|
|
20
|
+
interface PrimariaHttpClient {
|
|
21
|
+
get(url: string): Promise<any>;
|
|
22
|
+
post(url: string, data: any): Promise<any>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PrimariaApi extends HarmonixApi {
|
|
26
|
+
httpClient: PrimariaHttpClient;
|
|
27
|
+
interactionManager: PrimariaInteractionManager;
|
|
28
|
+
broker: PrimariaBroker;
|
|
29
|
+
regionManager: PrimariaRegionManager;
|
|
30
|
+
globalStateManager: PrimariaGlobalStateManager;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const regionManager: IRegionManager = createRegionManager("primaria");
|
|
34
|
+
export const PrimariaRegionHost: any = createRegionHost(regionManager as any);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Factory function that creates a Primaria API instance.
|
|
38
|
+
*
|
|
39
|
+
* @param {PluginInfo} pluginInfo - Information about the plugin
|
|
40
|
+
* @return {PrimariaApi} The created Primaria API instance
|
|
41
|
+
*/
|
|
42
|
+
export const primariaApiFactory: ApiFactory<PrimariaApi> = (
|
|
43
|
+
pluginInfo: PluginInfo,
|
|
44
|
+
): PrimariaApi => {
|
|
45
|
+
return {
|
|
46
|
+
pluginInfo: pluginInfo,
|
|
47
|
+
regionManager: createRegionManagerProxy(pluginInfo, regionManager),
|
|
48
|
+
httpClient: {
|
|
49
|
+
get: (url: string) => fetch(url).then((r) => r.json()),
|
|
50
|
+
post: (url: string, data: any) =>
|
|
51
|
+
fetch(url, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
body: JSON.stringify(data),
|
|
54
|
+
}).then((r) => r.json()),
|
|
55
|
+
},
|
|
56
|
+
interactionManager: { ...createInteractionManager() },
|
|
57
|
+
broker: broker,
|
|
58
|
+
createLocaleManager: createLocaleManager(pluginInfo.pluginId) as any,
|
|
59
|
+
globalStateManager: createGlobalStateManager(broker),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const shellApi = primariaApiFactory({ pluginId: "primaria-shell" }) as PrimariaApi;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { beforeEach, describe, Mock, vi, it, expect } from "vitest";
|
|
2
|
+
import { PrimariaBroker } from "./primaria-broker";
|
|
3
|
+
import { createBroker } from "./factory";
|
|
4
|
+
import { IEvent, IRequest } from "@uxland/harmonix";
|
|
5
|
+
|
|
6
|
+
describe("Broker test", () => {
|
|
7
|
+
let sut: PrimariaBroker;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
sut = createBroker();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe("Event bus test", () => {
|
|
14
|
+
describe("Test by Event instance", () => {
|
|
15
|
+
class MyEvent implements IEvent {
|
|
16
|
+
constructor(public greeting: string) {}
|
|
17
|
+
}
|
|
18
|
+
describe("Given some subscriptions for an event", () => {
|
|
19
|
+
let handlers: Mock[];
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
handlers = Array.from({ length: 5 }).map(() => {
|
|
22
|
+
const handler = vi.fn();
|
|
23
|
+
sut.subscribe(MyEvent, handler);
|
|
24
|
+
return handler;
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("When event is published", () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
sut.publish(new MyEvent("Hello"));
|
|
30
|
+
});
|
|
31
|
+
it("Then handler is called", () => {
|
|
32
|
+
for (const handler of handlers) {
|
|
33
|
+
expect(handler).toBeCalledWith({ greeting: "Hello" });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("Test by event name", () => {
|
|
40
|
+
describe("Given some subscriptions for an event", () => {
|
|
41
|
+
let handlers: Mock[];
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
handlers = Array.from({ length: 5 }).map(() => {
|
|
44
|
+
const handler = vi.fn();
|
|
45
|
+
sut.subscribe("MyEvent", handler);
|
|
46
|
+
return handler;
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("When event is published", () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
sut.publish("MyEvent", { greeting: "Hello" });
|
|
52
|
+
});
|
|
53
|
+
it("Then handler is called", () => {
|
|
54
|
+
for (const handler of handlers) {
|
|
55
|
+
expect(handler).toBeCalledWith({ greeting: "Hello" });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("Message broker test", () => {
|
|
63
|
+
describe("Test by Request instance", () => {
|
|
64
|
+
class MyRequest implements IRequest<string> {
|
|
65
|
+
constructor(public greeting: string) {}
|
|
66
|
+
}
|
|
67
|
+
describe("Given a handler for a request", () => {
|
|
68
|
+
let handler: Mock;
|
|
69
|
+
const greeting = "World!";
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
handler = vi.fn();
|
|
72
|
+
handler.mockResolvedValue(`Hello ${greeting}`);
|
|
73
|
+
sut.registerRequest(MyRequest, handler);
|
|
74
|
+
});
|
|
75
|
+
describe("When request is sent", () => {
|
|
76
|
+
let result: string;
|
|
77
|
+
beforeEach(async () => {
|
|
78
|
+
result = await sut.send(new MyRequest(greeting));
|
|
79
|
+
});
|
|
80
|
+
it("Then handler is called", () => {
|
|
81
|
+
expect(handler).toBeCalledWith({ greeting });
|
|
82
|
+
});
|
|
83
|
+
it("Then result is returned", () => {
|
|
84
|
+
expect(result).toBe(`Hello ${greeting}`);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it("Should fail if a request is registered twice", () => {
|
|
89
|
+
sut.registerRequest(MyRequest, () => {});
|
|
90
|
+
expect(() => sut.registerRequest(MyRequest, () => {})).toThrowError();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("Test by request name", () => {
|
|
95
|
+
const requestName = "MyRequest";
|
|
96
|
+
describe("Given a handler for a request", () => {
|
|
97
|
+
let handler: Mock;
|
|
98
|
+
const greeting = "World!";
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
handler = vi.fn();
|
|
102
|
+
handler.mockResolvedValue(`Hello ${greeting}`);
|
|
103
|
+
sut.registerRequest(requestName, handler);
|
|
104
|
+
});
|
|
105
|
+
describe("When request is sent", () => {
|
|
106
|
+
let result: string;
|
|
107
|
+
beforeEach(async () => {
|
|
108
|
+
result = await sut.send(requestName, { greeting });
|
|
109
|
+
});
|
|
110
|
+
it("Then handler is called", () => {
|
|
111
|
+
expect(handler).toBeCalledWith({ greeting });
|
|
112
|
+
});
|
|
113
|
+
it("Then result is returned", () => {
|
|
114
|
+
expect(result).toBe(`Hello ${greeting}`);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it("Should fail if a request is registered twice", () => {
|
|
119
|
+
sut.registerRequest(requestName, () => {});
|
|
120
|
+
expect(() => sut.registerRequest(requestName, () => {})).toThrowError();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { HarmonixBroker, IEvent, IEventClass, IRequest, IRequestClass } from "@uxland/harmonix";
|
|
2
|
+
import { Mediator, mediatorSettings, notificationHandler, requestHandler } from "mediatr-ts";
|
|
3
|
+
import { PrimariaBroker } from "./primaria-broker";
|
|
4
|
+
|
|
5
|
+
type messageHandler = (payload: unknown) => unknown | Promise<unknown>;
|
|
6
|
+
|
|
7
|
+
class Broker implements PrimariaBroker {
|
|
8
|
+
private mediator: Mediator;
|
|
9
|
+
constructor() {
|
|
10
|
+
this.mediator = new Mediator();
|
|
11
|
+
mediatorSettings.resolver.clear();
|
|
12
|
+
}
|
|
13
|
+
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
14
|
+
private eventConstructorMap: Map<string, Function> = new Map();
|
|
15
|
+
|
|
16
|
+
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
17
|
+
private requestConstructorMap: Map<string, Function> = new Map();
|
|
18
|
+
|
|
19
|
+
send<TRequest extends IRequest<TResponse>, TResponse>(message: TRequest): Promise<TResponse>;
|
|
20
|
+
send<TPayload, TResponse>(requestName: string, payload: TPayload): Promise<TResponse>;
|
|
21
|
+
send<TResponse>(request: IRequest<TResponse> | string, payload?: unknown): Promise<TResponse> {
|
|
22
|
+
const eventPayload =
|
|
23
|
+
typeof request === "string"
|
|
24
|
+
? this.getRequest<TResponse>(request as string, payload)
|
|
25
|
+
: request;
|
|
26
|
+
return this.mediator.send(eventPayload);
|
|
27
|
+
}
|
|
28
|
+
publish<TEvent extends IEvent>(event: TEvent): Promise<void>;
|
|
29
|
+
publish<TPayload>(eventName: string, payload: TPayload): Promise<void>;
|
|
30
|
+
publish(event: string | IEvent, payload?: unknown): Promise<void> {
|
|
31
|
+
const eventPayload =
|
|
32
|
+
typeof event === "string" ? this.getEvent(event as string, payload) : event;
|
|
33
|
+
return this.mediator.publish(eventPayload);
|
|
34
|
+
}
|
|
35
|
+
subscribe<TEvent extends IEvent>(
|
|
36
|
+
event: TEvent,
|
|
37
|
+
handler: (message: TEvent) => void,
|
|
38
|
+
): HarmonixBroker;
|
|
39
|
+
subscribe<TPayload>(eventName: string, handler: (message: TPayload) => void): HarmonixBroker;
|
|
40
|
+
subscribe(event: string | IEventClass, handler: messageHandler): HarmonixBroker {
|
|
41
|
+
const eventType = typeof event === "function" ? event : this.getEventType(event as string);
|
|
42
|
+
notificationHandler(eventType)(createDynamicEventHandler(handler));
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
registerRequest<TRequest extends IRequest<TResponse>, TResponse>(
|
|
46
|
+
request: TRequest,
|
|
47
|
+
handler: (message: TRequest) => TResponse,
|
|
48
|
+
): HarmonixBroker;
|
|
49
|
+
registerRequest<TPayload, TResponse>(
|
|
50
|
+
requestName: string,
|
|
51
|
+
handler: (message: TPayload) => TResponse,
|
|
52
|
+
): HarmonixBroker;
|
|
53
|
+
registerRequest(
|
|
54
|
+
request: string | IRequestClass<unknown>,
|
|
55
|
+
handler: messageHandler,
|
|
56
|
+
): HarmonixBroker {
|
|
57
|
+
const requestType =
|
|
58
|
+
typeof request === "function" ? request : this.getRequestType(request as string);
|
|
59
|
+
requestHandler(requestType)(createDynamicRequestHandler(handler));
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private getEvent(eventName: string, payload: unknown): IEvent {
|
|
64
|
+
const eventConstructor = this.getEventType(eventName);
|
|
65
|
+
return new eventConstructor(payload) as IEvent;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private getRequest<TResponse>(requestName: string, payload: unknown): IRequest<TResponse> {
|
|
69
|
+
const requestConstructor = this.getRequestType(requestName);
|
|
70
|
+
return new requestConstructor(payload) as IRequest<unknown>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private getEventType(eventName: string): IEventClass {
|
|
74
|
+
if (!this.eventConstructorMap.has(eventName)) {
|
|
75
|
+
const clazz = createDynamicEventClass(eventName);
|
|
76
|
+
this.eventConstructorMap.set(eventName, clazz);
|
|
77
|
+
}
|
|
78
|
+
return this.eventConstructorMap.get(eventName) as IEventClass;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private getRequestType(requestName: string): IRequestClass<unknown> {
|
|
82
|
+
if (!this.requestConstructorMap.has(requestName)) {
|
|
83
|
+
const clazz = createDynamicRequestClass(requestName);
|
|
84
|
+
this.requestConstructorMap.set(requestName, clazz);
|
|
85
|
+
}
|
|
86
|
+
return this.requestConstructorMap.get(requestName) as IRequestClass<unknown>;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const createDynamicEventClass = (eventName: string) =>
|
|
91
|
+
createDynamicMessageClass(eventName, "Event");
|
|
92
|
+
|
|
93
|
+
const createDynamicRequestClass = (requestName: string) =>
|
|
94
|
+
createDynamicMessageClass(requestName, "Request");
|
|
95
|
+
|
|
96
|
+
const createDynamicMessageClass = (eventName: string, classPrefix: string) => {
|
|
97
|
+
return new Function(`return class ${classPrefix}_${eventName} {
|
|
98
|
+
constructor(payload) {
|
|
99
|
+
Object.assign(this, payload);
|
|
100
|
+
}
|
|
101
|
+
}`)();
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const createDynamicRequestHandler = (handler: messageHandler) =>
|
|
105
|
+
createDynamicMessageHandler(handler, "RequestHandler");
|
|
106
|
+
const createDynamicEventHandler = (handler: messageHandler) =>
|
|
107
|
+
createDynamicMessageHandler(handler, "EventHandler");
|
|
108
|
+
|
|
109
|
+
const createDynamicMessageHandler = (handler: messageHandler, classPrefix: string) => {
|
|
110
|
+
const className = `${classPrefix}_${Math.floor(Math.random() * 10000)}`; // Generate a random class name
|
|
111
|
+
return new Function(
|
|
112
|
+
"handler",
|
|
113
|
+
`return class ${className}{
|
|
114
|
+
handle(notification){
|
|
115
|
+
const handlerResult = handler({...notification});
|
|
116
|
+
return handlerResult instanceof Promise ? handlerResult : Promise.resolve(handlerResult);
|
|
117
|
+
}
|
|
118
|
+
}`,
|
|
119
|
+
)(handler);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const createBroker = (): PrimariaBroker => new Broker();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
2
|
+
import { PrimariaGlobalStateManager, createGlobalStateManager } from "./global-state";
|
|
3
|
+
import { PrimariaBroker } from "../broker/primaria-broker";
|
|
4
|
+
|
|
5
|
+
describe("PrimariaGlobalStateManagerImpl", () => {
|
|
6
|
+
let globalStateManager: PrimariaGlobalStateManager;
|
|
7
|
+
let brokerMock: PrimariaBroker;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
brokerMock = {
|
|
11
|
+
publish: vi.fn(),
|
|
12
|
+
} as any;
|
|
13
|
+
globalStateManager = createGlobalStateManager(brokerMock);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should set and get data correctly", () => {
|
|
17
|
+
globalStateManager.setData("key1", "value1");
|
|
18
|
+
const result = globalStateManager.getData("key1");
|
|
19
|
+
expect(result).toBe("value1");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should set data and publish an event", () => {
|
|
23
|
+
const key = "key1";
|
|
24
|
+
const value = "value1";
|
|
25
|
+
globalStateManager.setData(key, value);
|
|
26
|
+
|
|
27
|
+
expect(globalStateManager.getData(key)).toBe(value);
|
|
28
|
+
expect(brokerMock.publish).toHaveBeenCalledWith("data-setted", {
|
|
29
|
+
key: key,
|
|
30
|
+
value: value,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should return undefined for non-existent key", () => {
|
|
35
|
+
const result = globalStateManager.getData("nonExistentKey");
|
|
36
|
+
expect(result).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should overwrite existing key with new value", () => {
|
|
40
|
+
globalStateManager.setData("key1", "value1");
|
|
41
|
+
globalStateManager.setData("key1", "newValue");
|
|
42
|
+
const result = globalStateManager.getData("key1");
|
|
43
|
+
expect(result).toBe("newValue");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should clear all data", () => {
|
|
47
|
+
globalStateManager.setData("key1", "value1");
|
|
48
|
+
globalStateManager.setData("key2", "value2");
|
|
49
|
+
globalStateManager.clearData();
|
|
50
|
+
expect(globalStateManager.getData("key1")).toBeUndefined();
|
|
51
|
+
expect(globalStateManager.getData("key2")).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
});
|