@uxland/primary-shell 7.46.13 → 7.46.15
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/{component-CQDFWF9Z.js → component-LekL_wPh.js} +2 -2
- package/dist/{component-CQDFWF9Z.js.map → component-LekL_wPh.js.map} +1 -1
- package/dist/{index-Dcg1Qboj.js → index-Dm3JkDtL.js} +10168 -10698
- package/dist/index-Dm3JkDtL.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +206 -232
- package/dist/index.umd.cjs.map +1 -1
- package/dist/{plugin-Ddy8HwLA.js → plugin-CVSTX5Ok.js} +2 -2
- package/dist/plugin-CVSTX5Ok.js.map +1 -0
- package/dist/primary/shell/src/UI/shared-components/primaria-text-editor/primaria-rich-text-editor.d.ts +7 -1
- package/dist/primary/shell/src/api/import-data-manager/component/component.d.ts +1 -0
- package/dist/primary/shell/src/features/get-user-info/backend-adapter.d.ts +4 -2
- package/dist/primary/shell/src/features/get-user-info/pds-token.d.ts +26 -0
- package/package.json +2 -2
- package/src/UI/components/quick-actions-menu/quick-actions-menu.ts +3 -3
- package/src/UI/shared-components/bootstrapper.ts +3 -1
- package/src/UI/shared-components/primaria-nav-item/primaria-nav-item.ts +3 -1
- package/src/UI/shared-components/primaria-text-editor/primaria-rich-text-editor.ts +34 -21
- package/src/api/ecap-event-manager/ecap-event-manager.test.ts +11 -4
- package/src/api/import-data-manager/component/component.ts +3 -0
- package/src/api/import-data-manager/import-data-manager-impl.test.ts +2 -0
- package/src/api/interaction-service/interaction-service-impl.tsx +37 -40
- package/src/api/localization/localization.ts +44 -40
- package/src/api/region-manager/region-manager.test.ts +1 -1
- package/src/api/region-manager/region-manager.ts +13 -3
- package/src/features/get-user-info/backend-adapter.ts +30 -18
- package/src/features/get-user-info/handler.test.ts +8 -2
- package/src/features/get-user-info/pds-token.ts +28 -0
- package/src/types/custom.d.ts +30 -0
- package/dist/index-Dcg1Qboj.js.map +0 -1
- package/dist/plugin-Ddy8HwLA.js.map +0 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
import { default as Quill } from 'uxl-quill/dist/quill';
|
|
3
|
+
/**
|
|
4
|
+
* Una opció de la barra d'eines de Quill: el nom solt (`"bold"`), un objecte de configuració
|
|
5
|
+
* (`{ header: 1 }`) o un grup d'opcions, que és com Quill separa els blocs de la barra.
|
|
6
|
+
*/
|
|
7
|
+
type ToolbarOption = string | Record<string, unknown> | (string | Record<string, unknown>)[];
|
|
3
8
|
export declare class PrimariaRichTextEditor extends LitElement {
|
|
4
9
|
private textChangeTimeout;
|
|
5
10
|
render(): import('lit').TemplateResult<1>;
|
|
@@ -19,7 +24,7 @@ export declare class PrimariaRichTextEditor extends LitElement {
|
|
|
19
24
|
_getOptions(): {
|
|
20
25
|
modules: {
|
|
21
26
|
toolbar: {
|
|
22
|
-
container:
|
|
27
|
+
container: ToolbarOption[];
|
|
23
28
|
handlers: {
|
|
24
29
|
redo(): void;
|
|
25
30
|
undo(): void;
|
|
@@ -57,3 +62,4 @@ export declare class PrimariaRichTextEditor extends LitElement {
|
|
|
57
62
|
};
|
|
58
63
|
getCursorPosition(): any;
|
|
59
64
|
}
|
|
65
|
+
export {};
|
|
@@ -5,6 +5,7 @@ export declare class ImportDataManagerModal extends LitElement implements Confir
|
|
|
5
5
|
setResult: (result: undefined) => void;
|
|
6
6
|
setIsValid: (isValid: boolean) => void;
|
|
7
7
|
confirm: () => void;
|
|
8
|
+
confirmResult: (result: undefined) => void;
|
|
8
9
|
cancel: () => void;
|
|
9
10
|
render(): import('lit').TemplateResult<1>;
|
|
10
11
|
static styles: import('lit').CSSResult;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { IUserInfo } from './model';
|
|
2
1
|
import { shellApi } from '../../api/api';
|
|
2
|
+
import { IUserInfo } from './model';
|
|
3
|
+
import { PdsAccessInfo } from './pds-token';
|
|
3
4
|
export declare abstract class UserInfoBackendAdapter {
|
|
4
5
|
abstract getUserInfo(): Promise<IUserInfo>;
|
|
5
6
|
}
|
|
@@ -7,5 +8,6 @@ export declare class GetUserInfoBackendAdapter implements UserInfoBackendAdapter
|
|
|
7
8
|
private api;
|
|
8
9
|
constructor(api: typeof shellApi);
|
|
9
10
|
getUserInfo(): Promise<IUserInfo>;
|
|
10
|
-
|
|
11
|
+
private findIdentifier;
|
|
12
|
+
getUserId(accessInfo: PdsAccessInfo | undefined): string | undefined;
|
|
11
13
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Els camps del token del PDS que aquest adaptador llegeix.
|
|
3
|
+
*
|
|
4
|
+
* Es declara aquí, i no s'importa `PDSToken` de `@pds/core`, per dues raons: el shell no depèn
|
|
5
|
+
* d'aquell package, i el seu `AccessInfo` no inclou `trace_user_last_name`, que sí que es fa
|
|
6
|
+
* servir. Si algun dia s'unifiquen els dos contractes, aquest fitxer hauria de desaparèixer.
|
|
7
|
+
*
|
|
8
|
+
* Tot és opcional perquè el token no en garanteix cap: fins ara el tipus era `any` i
|
|
9
|
+
* `IUserInfo` prometia `string` a tot arreu, cosa que no era certa en runtime.
|
|
10
|
+
*/
|
|
11
|
+
export interface PdsAccessInfo {
|
|
12
|
+
trace_user_given_name?: string;
|
|
13
|
+
trace_user_family_name?: string;
|
|
14
|
+
trace_user_last_name?: string;
|
|
15
|
+
center_code?: string;
|
|
16
|
+
role_type?: string;
|
|
17
|
+
professional_category?: string;
|
|
18
|
+
identifier?: PdsIdentifier[];
|
|
19
|
+
}
|
|
20
|
+
export interface PdsIdentifier {
|
|
21
|
+
type: string;
|
|
22
|
+
value: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PdsToken {
|
|
25
|
+
access_info?: PdsAccessInfo;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxland/primary-shell",
|
|
3
|
-
"version": "7.46.
|
|
3
|
+
"version": "7.46.15",
|
|
4
4
|
"description": "Primaria Shell",
|
|
5
5
|
"author": "UXLand <dev@uxland.es>",
|
|
6
6
|
"homepage": "https://github.com/uxland/harmonix/tree/app#readme",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"tslib": "^2.3.0",
|
|
48
48
|
"uxl-quill": "^1.0.1",
|
|
49
49
|
"vite": "^7.0.0",
|
|
50
|
-
"@primaria/plugins-core": "1.0.
|
|
50
|
+
"@primaria/plugins-core": "1.0.22"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"serve": "vite",
|
|
@@ -35,11 +35,11 @@ export class QuickActionsMenu extends LitElement {
|
|
|
35
35
|
|
|
36
36
|
// Obtener los elementos asignados al otro slot
|
|
37
37
|
const assignedElements = contentSlot?.assignedElements();
|
|
38
|
-
if (assignedElements[0])
|
|
39
|
-
this._addMenuCustomStyle(contentSlot as HTMLElement, actionMenu as HTMLElement);
|
|
38
|
+
if (assignedElements[0]) this._addMenuCustomStyle(contentSlot as HTMLElement, actionMenu as HTMLElement);
|
|
40
39
|
|
|
41
40
|
// Hacer target al elemento que deseas (por ejemplo, un <p>)
|
|
42
|
-
|
|
41
|
+
// Els components del DSS exposen `show()`, que no és a la interfície `Element`.
|
|
42
|
+
const targetElement = assignedElements.find((el): el is Element & { show(): void } => el.id === "content");
|
|
43
43
|
if (targetElement) {
|
|
44
44
|
// Modificar el contenido o estilo del elemento
|
|
45
45
|
targetElement.show();
|
|
@@ -12,5 +12,7 @@ export const useSharedUI = () => {
|
|
|
12
12
|
customElement("primaria-rich-text-editor")(PrimariaRichTextEditor);
|
|
13
13
|
customElement("primaria-nav-tree-menu")(PrimariaNavTreeMenu);
|
|
14
14
|
customElement("primaria-character-limit-badge")(PrimariaCharacterLimitBadge);
|
|
15
|
-
|
|
15
|
+
// @ts-ignore: `PrimariaRegion` estén el mixin `PrimariaRegionHost`, que està tipat com a
|
|
16
|
+
// `any`, així que TypeScript no el reconeix com a `CustomElementClass`.
|
|
17
|
+
customElement("primaria-region")(PrimariaRegion);
|
|
16
18
|
};
|
|
@@ -48,7 +48,9 @@ export class PrimariaNavItem extends regionView(LitElement) {
|
|
|
48
48
|
|
|
49
49
|
_subscribeEvents() {
|
|
50
50
|
const subscription = shellApi.broker.subscribe(BROKER_EVENTS.shell.mainViewChanged, (payload: { viewId: string }) => {
|
|
51
|
-
|
|
51
|
+
// `ViewDefinition` de @uxland/regions no declara `id`, però el shell només hi registra
|
|
52
|
+
// vistes que en porten.
|
|
53
|
+
this.isActive = payload.viewId === (this.view as { id?: string } | undefined)?.id;
|
|
52
54
|
});
|
|
53
55
|
this.subscriptions.push(subscription);
|
|
54
56
|
}
|
|
@@ -7,6 +7,31 @@ import { fixSpellCheckerIssue } from "./utils";
|
|
|
7
7
|
|
|
8
8
|
fixSpellCheckerIssue(Quill);
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Una opció de la barra d'eines de Quill: el nom solt (`"bold"`), un objecte de configuració
|
|
12
|
+
* (`{ header: 1 }`) o un grup d'opcions, que és com Quill separa els blocs de la barra.
|
|
13
|
+
*/
|
|
14
|
+
type ToolbarOption = string | Record<string, unknown> | (string | Record<string, unknown>)[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Opcions de la barra d'eines que Quill espera com a objecte de configuració en lloc del nom
|
|
18
|
+
* solt. Abans era una cadena d'`else if`.
|
|
19
|
+
*/
|
|
20
|
+
const TOOLBAR_OPTION_ALIASES: Record<string, ToolbarOption> = {
|
|
21
|
+
color: { color: [] },
|
|
22
|
+
ol: { list: "ordered" },
|
|
23
|
+
ul: { list: "bullet" },
|
|
24
|
+
subindex: { script: "sub" },
|
|
25
|
+
superindex: { script: "super" },
|
|
26
|
+
// outdent: { indent: "-1" },
|
|
27
|
+
// indent: { indent: "+1" },
|
|
28
|
+
size: { size: ["small", false, "large", "huge"] },
|
|
29
|
+
header: { header: [1, 2, 3, 4, 5, 6, false] },
|
|
30
|
+
background: { background: [] },
|
|
31
|
+
font: { font: [] },
|
|
32
|
+
align: { align: [] },
|
|
33
|
+
};
|
|
34
|
+
|
|
10
35
|
export class PrimariaRichTextEditor extends LitElement {
|
|
11
36
|
private textChangeTimeout: number | null = null;
|
|
12
37
|
|
|
@@ -124,7 +149,8 @@ export class PrimariaRichTextEditor extends LitElement {
|
|
|
124
149
|
formats: string;
|
|
125
150
|
|
|
126
151
|
_getOptions() {
|
|
127
|
-
|
|
152
|
+
// Sense anotar, `[]` s'infereix com a `never[]` i totes les assignacions posteriors fallen.
|
|
153
|
+
let toolbarOptions: ToolbarOption[] = [];
|
|
128
154
|
const availableOpts = this.availableOptions;
|
|
129
155
|
if (this.options === undefined || this.options.length === 0) {
|
|
130
156
|
toolbarOptions = [
|
|
@@ -145,26 +171,13 @@ export class PrimariaRichTextEditor extends LitElement {
|
|
|
145
171
|
// ["clean"],
|
|
146
172
|
];
|
|
147
173
|
} else {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
else if (option == "ul") return { list: "bullet" };
|
|
156
|
-
else if (option == "subindex") return { script: "sub" };
|
|
157
|
-
else if (option == "superindex") return { script: "super" };
|
|
158
|
-
// else if (option == 'outdent') return {indent: '-1'};
|
|
159
|
-
// else if (option == 'indent') return {indent: '+1'};
|
|
160
|
-
else if (option == "size") return { size: ["small", false, "large", "huge"] };
|
|
161
|
-
else if (option == "header") return { header: [1, 2, 3, 4, 5, 6, false] };
|
|
162
|
-
else if (option == "background") return { background: [] };
|
|
163
|
-
else if (option == "font") return { font: [] };
|
|
164
|
-
else if (option == "align") return { align: [] };
|
|
165
|
-
/* else if (option == 'undo') return {undo: undo_icon};
|
|
166
|
-
else if (option == 'redo') return {redo: redo_icon}; */ else return option;
|
|
167
|
-
});
|
|
174
|
+
// Abans això filtrava amb un `splice` dins d'un `forEach`, que salta elements quan n'hi ha
|
|
175
|
+
// dos d'invàlids seguits. Amb `filter` el resultat és el que la intenció demanava.
|
|
176
|
+
toolbarOptions = this.options
|
|
177
|
+
.split(",")
|
|
178
|
+
.filter((option) => availableOpts.indexOf(option) > -1)
|
|
179
|
+
// Les opcions amb configuració es tradueixen; la resta passen tal com són.
|
|
180
|
+
.map((option) => TOOLBAR_OPTION_ALIASES[option] ?? option);
|
|
168
181
|
// if (toolbarOptions.indexOf("clean") < 0) {
|
|
169
182
|
// toolbarOptions.push("clean");
|
|
170
183
|
// }
|
|
@@ -8,6 +8,13 @@ const createMockGlobalStateManager = (data: Record<string, unknown> = {}) =>
|
|
|
8
8
|
clearData: vi.fn(),
|
|
9
9
|
}) as any;
|
|
10
10
|
|
|
11
|
+
/** `mock.calls[0][0]` és `unknown | undefined` amb `noUncheckedIndexedAccess`. */
|
|
12
|
+
const firstPostedMessage = (spy: { mock: { calls: unknown[][] } }): string => {
|
|
13
|
+
const payload = spy.mock.calls[0]?.[0];
|
|
14
|
+
if (typeof payload !== "string") throw new Error("s'esperava un missatge publicat");
|
|
15
|
+
return payload;
|
|
16
|
+
};
|
|
17
|
+
|
|
11
18
|
describe("EcapEventManagerImpl", () => {
|
|
12
19
|
const mockPostMessage = vi.fn();
|
|
13
20
|
const mockConsoleLog = vi.fn();
|
|
@@ -31,7 +38,7 @@ describe("EcapEventManagerImpl", () => {
|
|
|
31
38
|
|
|
32
39
|
eventManager.publish("click", "navigate", payload);
|
|
33
40
|
|
|
34
|
-
const postedEvent = JSON.parse(mockPostMessage
|
|
41
|
+
const postedEvent = JSON.parse(firstPostedMessage(mockPostMessage));
|
|
35
42
|
expect(postedEvent.DIAGNOSTICS).toBeUndefined();
|
|
36
43
|
expect(globalStateManager.getData).not.toHaveBeenCalled();
|
|
37
44
|
});
|
|
@@ -43,7 +50,7 @@ describe("EcapEventManagerImpl", () => {
|
|
|
43
50
|
|
|
44
51
|
eventManager.publish("PRESCRIPCIO_ACTIVA", "NO_TANCAR", {});
|
|
45
52
|
|
|
46
|
-
const postedEvent = JSON.parse(mockPostMessage
|
|
53
|
+
const postedEvent = JSON.parse(firstPostedMessage(mockPostMessage));
|
|
47
54
|
expect(postedEvent.DIAGNOSTICS).toEqual(diagnostics);
|
|
48
55
|
expect(globalStateManager.getData).toHaveBeenCalledWith(LAST_WORKED_DIAGNOSTICS_KEY);
|
|
49
56
|
});
|
|
@@ -63,7 +70,7 @@ describe("EcapEventManagerImpl", () => {
|
|
|
63
70
|
|
|
64
71
|
eventManager.publish(eventType, "NO_TANCAR", {});
|
|
65
72
|
|
|
66
|
-
const postedEvent = JSON.parse(mockPostMessage
|
|
73
|
+
const postedEvent = JSON.parse(firstPostedMessage(mockPostMessage));
|
|
67
74
|
expect(postedEvent.DIAGNOSTICS).toEqual(diagnostics);
|
|
68
75
|
});
|
|
69
76
|
|
|
@@ -73,7 +80,7 @@ describe("EcapEventManagerImpl", () => {
|
|
|
73
80
|
|
|
74
81
|
eventManager.publish("ORDRE_TRACTAMENT", "NO_TANCAR", {});
|
|
75
82
|
|
|
76
|
-
const postedEvent = JSON.parse(mockPostMessage
|
|
83
|
+
const postedEvent = JSON.parse(firstPostedMessage(mockPostMessage));
|
|
77
84
|
expect(postedEvent.DIAGNOSTICS).toEqual([]);
|
|
78
85
|
});
|
|
79
86
|
|
|
@@ -10,6 +10,9 @@ export class ImportDataManagerModal extends LitElement implements ConfirmationCo
|
|
|
10
10
|
setResult: (result: undefined) => void;
|
|
11
11
|
setIsValid: (isValid: boolean) => void;
|
|
12
12
|
confirm: () => void;
|
|
13
|
+
// Injectat pel servei d'interacció igual que la resta; faltava des que es va afegir a la
|
|
14
|
+
// interfície.
|
|
15
|
+
confirmResult: (result: undefined) => void;
|
|
13
16
|
cancel: () => void;
|
|
14
17
|
|
|
15
18
|
render() {
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
class MockInteractionService extends PrimariaInteractionService {
|
|
12
12
|
private mockConfirmResult: { confirmed: boolean; result?: unknown } = { confirmed: true };
|
|
13
13
|
|
|
14
|
+
dispose(): void {}
|
|
15
|
+
|
|
14
16
|
// Mètode per configurar el resultat del mock
|
|
15
17
|
setMockConfirmResult(result: { confirmed: boolean; result?: unknown }) {
|
|
16
18
|
this.mockConfirmResult = result;
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConfirmationOptions,
|
|
3
|
-
ConfirmationResult,
|
|
4
|
-
ConfirmComponentUI,
|
|
5
|
-
PrimariaInteractionService,
|
|
6
|
-
} from "./interaction-service";
|
|
1
|
+
import { ConfirmationOptions, ConfirmationResult, ConfirmComponentUI, PrimariaInteractionService } from "./interaction-service";
|
|
7
2
|
import * as React from "react";
|
|
8
3
|
import { useEffect, useState, useRef } from "react";
|
|
9
4
|
import { createRoot } from "react-dom/client";
|
|
10
5
|
import { ConfirmationMessage } from "./confirmation-message.tsx";
|
|
11
|
-
import modalStyles from
|
|
6
|
+
import modalStyles from "./modal-styles.css?raw";
|
|
12
7
|
|
|
13
8
|
const defaultOptions: ConfirmationOptions = {
|
|
14
9
|
title: "Confirmació",
|
|
@@ -19,16 +14,24 @@ const defaultOptions: ConfirmationOptions = {
|
|
|
19
14
|
showCloseButton: true,
|
|
20
15
|
fullCustomization: false,
|
|
21
16
|
closeOnOutsideClick: false,
|
|
22
|
-
hideIcon: false
|
|
17
|
+
hideIcon: false,
|
|
23
18
|
};
|
|
24
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Un diàleg pot ser un component de React o un web component. Només el primer es pot renderitzar
|
|
22
|
+
* com a JSX, i cal un predicat de tipus perquè TypeScript ho estrenyi al punt d'ús: guardar el
|
|
23
|
+
* resultat en un booleà no li serveix.
|
|
24
|
+
*/
|
|
25
|
+
const isWebComponentConstructor = (component: unknown): component is new () => HTMLElement =>
|
|
26
|
+
typeof component === "function" && component.prototype instanceof HTMLElement;
|
|
27
|
+
|
|
25
28
|
export class ParimariaInteractionServiceImpl extends PrimariaInteractionService {
|
|
26
29
|
private readonly openDialogCancellers = new Set<() => void>();
|
|
27
30
|
|
|
28
31
|
confirm<TData = undefined, TResult = undefined>(
|
|
29
32
|
data: TData | undefined,
|
|
30
33
|
componentUI: ConfirmComponentUI<TData, TResult>,
|
|
31
|
-
options?: ConfirmationOptions | undefined
|
|
34
|
+
options?: ConfirmationOptions | undefined,
|
|
32
35
|
): Promise<ConfirmationResult<TResult | undefined>> {
|
|
33
36
|
const finalOptions: ConfirmationOptions = { ...defaultOptions, ...(options || {}) };
|
|
34
37
|
const { openDialogCancellers } = this;
|
|
@@ -42,26 +45,25 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
42
45
|
const DialogComponent = componentUI.component;
|
|
43
46
|
const DialogComponentStyles = componentUI.styles;
|
|
44
47
|
let componentHeadStyles;
|
|
45
|
-
if(DialogComponentStyles) {
|
|
48
|
+
if (DialogComponentStyles) {
|
|
46
49
|
componentHeadStyles = document.createElement("style");
|
|
47
50
|
componentHeadStyles.textContent = componentUI?.styles;
|
|
48
51
|
document.head.appendChild(componentHeadStyles);
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const DialogWrapper = () => {
|
|
52
|
-
const [result, setResult] = useState<
|
|
55
|
+
const [result, setResult] = useState<TResult>();
|
|
53
56
|
const [isValid, setIsValid] = useState(true);
|
|
54
|
-
const dialogComponentRef = useRef(null);
|
|
57
|
+
const dialogComponentRef = useRef<HTMLDivElement>(null);
|
|
55
58
|
const dialogRef = useRef<HTMLDivElement>(null);
|
|
56
59
|
const modalRef = useRef<HTMLDivElement>(null);
|
|
57
60
|
|
|
58
|
-
const isWebComponent =
|
|
59
|
-
typeof DialogComponent === "function" && DialogComponent.prototype instanceof HTMLElement;
|
|
61
|
+
const isWebComponent = isWebComponentConstructor(DialogComponent);
|
|
60
62
|
|
|
61
63
|
useEffect(() => {
|
|
62
|
-
window.addEventListener(
|
|
64
|
+
window.addEventListener("keydown", handleKeydown);
|
|
63
65
|
|
|
64
|
-
return () => window.removeEventListener(
|
|
66
|
+
return () => window.removeEventListener("keydown", handleKeydown);
|
|
65
67
|
}, []);
|
|
66
68
|
|
|
67
69
|
useEffect(() => {
|
|
@@ -75,11 +77,11 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
75
77
|
}, []);
|
|
76
78
|
|
|
77
79
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
78
|
-
if (event.key ===
|
|
80
|
+
if (event.key === "Escape") {
|
|
79
81
|
handleClose(false);
|
|
80
82
|
}
|
|
81
83
|
};
|
|
82
|
-
const handleOutsideClick = (event:
|
|
84
|
+
const handleOutsideClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
83
85
|
if (dialogRef.current) {
|
|
84
86
|
if (event.target === modalRef.current && finalOptions.closeOnOutsideClick) {
|
|
85
87
|
handleClose(false);
|
|
@@ -87,6 +89,9 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
87
89
|
}
|
|
88
90
|
};
|
|
89
91
|
|
|
92
|
+
// L'efecte només ha de crear el web component quan canvia el component o les dades.
|
|
93
|
+
// Afegir-hi els handlers i `isValid` el faria recrear a cada render, perdent l'estat.
|
|
94
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: recrear-lo perdria l'estat
|
|
90
95
|
useEffect(() => {
|
|
91
96
|
if (isWebComponent && dialogComponentRef.current) {
|
|
92
97
|
const parent = dialogComponentRef.current;
|
|
@@ -119,7 +124,7 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
119
124
|
resolvePromise(finalResult, true);
|
|
120
125
|
};
|
|
121
126
|
|
|
122
|
-
const resolvePromise = (finalResult: TResult, confirmed: boolean) => {
|
|
127
|
+
const resolvePromise = (finalResult: TResult | undefined, confirmed: boolean) => {
|
|
123
128
|
if (isClosing) return;
|
|
124
129
|
|
|
125
130
|
isClosing = true;
|
|
@@ -132,8 +137,7 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
132
137
|
root.unmount();
|
|
133
138
|
document.body.removeChild(div);
|
|
134
139
|
document.head.removeChild(wrapperHeadStyles);
|
|
135
|
-
if (DialogComponentStyles)
|
|
136
|
-
document.head.removeChild(componentHeadStyles);
|
|
140
|
+
if (DialogComponentStyles) document.head.removeChild(componentHeadStyles);
|
|
137
141
|
}, 300);
|
|
138
142
|
};
|
|
139
143
|
|
|
@@ -160,7 +164,7 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
160
164
|
};
|
|
161
165
|
|
|
162
166
|
const _renderContent = () => {
|
|
163
|
-
return
|
|
167
|
+
return isWebComponentConstructor(DialogComponent) ? (
|
|
164
168
|
<div ref={dialogComponentRef} />
|
|
165
169
|
) : (
|
|
166
170
|
<DialogComponent
|
|
@@ -176,7 +180,7 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
176
180
|
);
|
|
177
181
|
};
|
|
178
182
|
return (
|
|
179
|
-
<div className="modal" ref={modalRef} onClick={handleOutsideClick}
|
|
183
|
+
<div className="modal" ref={modalRef} onClick={handleOutsideClick}>
|
|
180
184
|
<div className="dialog" ref={dialogRef}>
|
|
181
185
|
{!finalOptions.fullCustomization && (
|
|
182
186
|
<div className="dss-dialog-header">
|
|
@@ -188,30 +192,27 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
188
192
|
fill
|
|
189
193
|
class={`dss-dialog-header-state--${getHeadIconVariantClass()}`}
|
|
190
194
|
icon={getHeadIcon()}
|
|
191
|
-
|
|
195
|
+
/>
|
|
192
196
|
)}
|
|
193
197
|
{finalOptions.title}
|
|
194
198
|
</div>
|
|
195
199
|
</div>
|
|
196
200
|
{finalOptions.showCloseButton && (
|
|
197
201
|
<dss-icon-button
|
|
198
|
-
class="dss-dialog-header-close"
|
|
199
|
-
size="md"
|
|
200
|
-
variant="neutral"
|
|
201
|
-
icon="close"
|
|
202
|
+
class="dss-dialog-header-close"
|
|
203
|
+
size="md"
|
|
204
|
+
variant="neutral"
|
|
205
|
+
icon="close"
|
|
202
206
|
onClick={() => handleClose(false)}
|
|
203
|
-
|
|
207
|
+
/>
|
|
204
208
|
)}
|
|
205
209
|
</div>
|
|
206
210
|
)}
|
|
207
|
-
<div className={`modal-content ${finalOptions.fullCustomization ?
|
|
211
|
+
<div className={`modal-content ${finalOptions.fullCustomization ? "full-customization" : ""}`}>
|
|
208
212
|
{_renderContent()}
|
|
209
213
|
</div>
|
|
210
214
|
{!finalOptions.fullCustomization && (
|
|
211
|
-
<div
|
|
212
|
-
className="dss-modal-footer"
|
|
213
|
-
hidden={!finalOptions.showCancelButton && !finalOptions.showConfirmButton}
|
|
214
|
-
>
|
|
215
|
+
<div className="dss-modal-footer" hidden={!finalOptions.showCancelButton && !finalOptions.showConfirmButton}>
|
|
215
216
|
{finalOptions.showCancelButton && (
|
|
216
217
|
<dss-button
|
|
217
218
|
label={finalOptions.cancelButtonText}
|
|
@@ -238,17 +239,13 @@ export class ParimariaInteractionServiceImpl extends PrimariaInteractionService
|
|
|
238
239
|
);
|
|
239
240
|
};
|
|
240
241
|
|
|
241
|
-
|
|
242
242
|
const root = createRoot(div);
|
|
243
243
|
root.render(<DialogWrapper />);
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
confirmMessage(
|
|
248
|
-
message:
|
|
249
|
-
options?: ConfirmationOptions | undefined,
|
|
250
|
-
): Promise<ConfirmationResult> {
|
|
251
|
-
return this.confirm(message, {component: ConfirmationMessage}, options);
|
|
247
|
+
confirmMessage(message: string, options?: ConfirmationOptions | undefined): Promise<ConfirmationResult> {
|
|
248
|
+
return this.confirm(message, { component: ConfirmationMessage }, options);
|
|
252
249
|
}
|
|
253
250
|
|
|
254
251
|
dispose(): void {
|
|
@@ -11,44 +11,48 @@ import { getLanguage, getLocales, localizerFactory, setLocales } from "@uxland/l
|
|
|
11
11
|
* getCurrentLanguage: () => string,
|
|
12
12
|
* }>} A promise that resolves to an object with methods for translating strings and getting translations.
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return Promise.resolve({
|
|
19
|
-
/**
|
|
20
|
-
* Translates the given path using the provided variables and the plugin's ID.
|
|
21
|
-
*
|
|
22
|
-
* @param {string} path - The path to be translated.
|
|
23
|
-
* @param {Record<string, string>} [variables] - Optional variables to be used in the translation.
|
|
24
|
-
* @return {string} The translated string, or the original path if an error occurs.
|
|
25
|
-
*/
|
|
26
|
-
translate: (path: string, variables?: Record<string, string>) => {
|
|
27
|
-
try {
|
|
28
|
-
return localizer(`${pluginId}.${path}`, variables);
|
|
29
|
-
} catch (e) {
|
|
30
|
-
console.error(e);
|
|
31
|
-
return path;
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
/**
|
|
35
|
-
* Retrieves the translations for the current language and plugin.
|
|
36
|
-
*
|
|
37
|
-
* @return {Record<string, string>} The translations for the current language and plugin.
|
|
38
|
-
*/
|
|
39
|
-
getTranslations: () => {
|
|
40
|
-
const translations = getLocales();
|
|
41
|
-
const language = getLanguage();
|
|
42
|
-
return translations[language][pluginId] || {};
|
|
43
|
-
},
|
|
14
|
+
/** Arbre de traduccions: claus imbricades fins a arribar al text. */
|
|
15
|
+
export interface LocalizationMessages {
|
|
16
|
+
[key: string]: string | LocalizationMessages;
|
|
17
|
+
}
|
|
44
18
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
19
|
+
export const createLocaleManager = (pluginId: string) => (translations: Record<string, LocalizationMessages>) => {
|
|
20
|
+
const localizer = localizerFactory(getLanguage(), translations, "", true);
|
|
21
|
+
setLocales(translations);
|
|
22
|
+
return Promise.resolve({
|
|
23
|
+
/**
|
|
24
|
+
* Translates the given path using the provided variables and the plugin's ID.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} path - The path to be translated.
|
|
27
|
+
* @param {Record<string, string>} [variables] - Optional variables to be used in the translation.
|
|
28
|
+
* @return {string} The translated string, or the original path if an error occurs.
|
|
29
|
+
*/
|
|
30
|
+
translate: (path: string, variables?: Record<string, string>) => {
|
|
31
|
+
try {
|
|
32
|
+
return localizer(`${pluginId}.${path}`, variables);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.error(e);
|
|
35
|
+
return path;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves the translations for the current language and plugin.
|
|
40
|
+
*
|
|
41
|
+
* @return {Record<string, string>} The translations for the current language and plugin.
|
|
42
|
+
*/
|
|
43
|
+
getTranslations: () => {
|
|
44
|
+
const translations = getLocales();
|
|
45
|
+
const language = getLanguage();
|
|
46
|
+
return translations[language][pluginId] || {};
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Retrieves the current language.
|
|
51
|
+
*
|
|
52
|
+
* @return {string} The current language.
|
|
53
|
+
*/
|
|
54
|
+
getCurrentLanguage: () => {
|
|
55
|
+
return getLanguage();
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
};
|
|
@@ -3,7 +3,7 @@ import { createRegionManagerProxy } from "./region-manager";
|
|
|
3
3
|
import { BROKER_EVENTS } from "../broker/broker-events";
|
|
4
4
|
|
|
5
5
|
const pluginId = "test-plugin";
|
|
6
|
-
const mockView = { id: "view1" };
|
|
6
|
+
const mockView = { id: "view1", factory: () => Promise.resolve(document.createElement("div")) };
|
|
7
7
|
|
|
8
8
|
const createMockRegion = () => ({
|
|
9
9
|
activate: vi.fn(),
|
|
@@ -109,14 +109,24 @@ class RegionManagerProxy implements PrimariaRegionManager {
|
|
|
109
109
|
*/
|
|
110
110
|
isViewActive(regionName: string, viewId: string) {
|
|
111
111
|
const region = this.regionManager.getRegion(regionName);
|
|
112
|
-
|
|
112
|
+
// `ViewDefinition` de @uxland/regions no declara `id`, però el shell només hi registra
|
|
113
|
+
// `HarmonixViewDefinition`, que sí que en porta.
|
|
114
|
+
const isViewActive = region.currentActiveViews.some((view) => (view as HarmonixViewDefinition).id === viewId);
|
|
113
115
|
return Promise.resolve(isViewActive);
|
|
114
116
|
}
|
|
115
117
|
async registerQuickAction(view: HarmonixViewDefinition): Promise<void> {
|
|
116
|
-
await this.regionManager.registerViewWithRegion(
|
|
118
|
+
await this.regionManager.registerViewWithRegion(
|
|
119
|
+
this.regions.shell.quickActions,
|
|
120
|
+
`${this.pluginInfo.pluginId}::${view.id}`,
|
|
121
|
+
view,
|
|
122
|
+
);
|
|
117
123
|
}
|
|
118
124
|
async registerNavigationMenu(view: HarmonixViewDefinition): Promise<void> {
|
|
119
|
-
await this.regionManager.registerViewWithRegion(
|
|
125
|
+
await this.regionManager.registerViewWithRegion(
|
|
126
|
+
this.regions.shell.navigationMenu,
|
|
127
|
+
`${this.pluginInfo.pluginId}::${view.id}`,
|
|
128
|
+
view,
|
|
129
|
+
);
|
|
120
130
|
}
|
|
121
131
|
async registerMainView(view: HarmonixViewDefinition): Promise<void> {
|
|
122
132
|
await this.regionManager.registerViewWithRegion(this.regions.shell.main, `${this.pluginInfo.pluginId}::${view.id}`, view);
|