@uxland/primary-shell 7.50.7 → 7.50.8

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.
@@ -1,5 +1,5 @@
1
- import { ImportParams, PrimariaImportDataManager } from './import-data-manager';
2
1
  import { PrimariaInteractionService } from '../interaction-service/interaction-service';
2
+ import { ImportParams, PrimariaImportDataManager } from './import-data-manager';
3
3
  export declare class ImportDataManagerImpl implements PrimariaImportDataManager {
4
4
  private interactionService;
5
5
  private selectedItems;
@@ -22,8 +22,20 @@ export declare class ImportDataManagerImpl implements PrimariaImportDataManager
22
22
  raw: string;
23
23
  html: string;
24
24
  };
25
+ title?: string;
25
26
  }): void;
26
27
  getCurrentImporterId(): string;
27
28
  getCurrentImportParams(): ImportParams | undefined;
29
+ /**
30
+ * Ajunta el text de cada plugin que ha contribuït a la importació.
31
+ *
32
+ * Els que declaren el mateix títol formen una sola secció, encapçalada un
33
+ * cop (dues iniciatives poden omplir el mateix apartat del modal: el curs
34
+ * clínic i l'històric d'activitat ho fan amb "Seguiment Clínic"). Els que no
35
+ * en declaren cap van tots junts, sense títol.
36
+ *
37
+ * El resultat acaba amb una línia en blanc perquè qui rep el text pugui
38
+ * seguir escrivint a sota.
39
+ */
28
40
  private getConcatenatedText;
29
41
  }
@@ -27,6 +27,11 @@ export interface PrimariaImportDataManager {
27
27
  raw: string;
28
28
  html: string;
29
29
  };
30
+ /** Títol que encapçala aquest text dins del resultat de la importació. Els
31
+ * plugins que en declaren un de mateix queden sota un sol títol, en l'ordre
32
+ * en què han publicat la seva selecció. Sense títol, el text s'afegeix tal
33
+ * qual. */
34
+ title?: string;
30
35
  }): void;
31
36
  getCurrentImporterId(): string;
32
37
  /** Returns the params the current importer was opened with (or undefined
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxland/primary-shell",
3
- "version": "7.50.7",
3
+ "version": "7.50.8",
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.30"
50
+ "@primaria/plugins-core": "1.0.31"
51
51
  },
52
52
  "scripts": {
53
53
  "serve": "vite",
@@ -139,8 +139,8 @@ describe("ImportDataManagerImpl implements PrimariaImportDataManager", () => {
139
139
  "plugin-1": [{ id: "1", name: "Item 1" }],
140
140
  "plugin-2": [{ id: "2", name: "Item 2" }],
141
141
  });
142
- expect(result.text.raw).toBe("Item 1\n\nItem 2");
143
- expect(result.text.html).toBe("<p>Item 1</p><br><br><p>Item 2</p>");
142
+ expect(result.text.raw).toBe("Item 1\n\nItem 2\n");
143
+ expect(result.text.html).toBe("<p>Item 1</p><br><br><p>Item 2</p><p><br></p>");
144
144
  });
145
145
 
146
146
  it("should return cancelled result with empty data when not confirmed", async () => {
@@ -252,9 +252,9 @@ describe("ImportDataManagerImpl implements PrimariaImportDataManager", () => {
252
252
 
253
253
  const result = await importDataManager.import("test-importer");
254
254
 
255
- expect(result.text.raw).toBe("E11.9 - Diabetes\n\nPenicillin - High severity");
255
+ expect(result.text.raw).toBe("E11.9 - Diabetes\n\nPenicillin - High severity\n");
256
256
  expect(result.text.html).toBe(
257
- "<p><strong>E11.9</strong> - Diabetes</p><br><br><p><strong>Penicillin</strong> - High severity</p>",
257
+ "<p><strong>E11.9</strong> - Diabetes</p><br><br><p><strong>Penicillin</strong> - High severity</p><p><br></p>",
258
258
  );
259
259
  });
260
260
 
@@ -281,8 +281,84 @@ describe("ImportDataManagerImpl implements PrimariaImportDataManager", () => {
281
281
 
282
282
  const result = await importDataManager.import("test-importer");
283
283
 
284
- expect(result.text.raw).toBe("Item 2");
285
- expect(result.text.html).toBe("<p>Item 2</p>");
284
+ expect(result.text.raw).toBe("Item 2\n");
285
+ expect(result.text.html).toBe("<p>Item 2</p><p><br></p>");
286
+ });
287
+
288
+ it("heads the texts sharing a title with that title, just once", async () => {
289
+ mockInteractionService.setMockConfirmResult({ confirmed: true });
290
+
291
+ const originalConfirm = mockInteractionService.confirm.bind(mockInteractionService);
292
+ vi.spyOn(mockInteractionService, "confirm").mockImplementation(async (...args) => {
293
+ importDataManager.selectItems({
294
+ pluginId: "clinical-course",
295
+ data: [{ id: "draft" }],
296
+ text: { raw: "Esborrany", html: "<p>Esborrany</p>" },
297
+ title: "Seguiment Clínic",
298
+ });
299
+
300
+ importDataManager.selectItems({
301
+ pluginId: "activity-history",
302
+ data: [{ id: "note" }],
303
+ text: { raw: "Nota", html: "<p>Nota</p>" },
304
+ title: "Seguiment Clínic",
305
+ });
306
+
307
+ return originalConfirm(...args);
308
+ });
309
+
310
+ const result = await importDataManager.import("test-importer");
311
+
312
+ expect(result.text.raw).toBe("Seguiment Clínic\n\nEsborrany\n\nNota\n");
313
+ expect(result.text.html).toBe("<p><strong>Seguiment Clínic</strong></p><p>Esborrany</p><br><br><p>Nota</p><p><br></p>");
314
+ });
315
+
316
+ it("keeps untitled texts without any heading", async () => {
317
+ mockInteractionService.setMockConfirmResult({ confirmed: true });
318
+
319
+ const originalConfirm = mockInteractionService.confirm.bind(mockInteractionService);
320
+ vi.spyOn(mockInteractionService, "confirm").mockImplementation(async (...args) => {
321
+ importDataManager.selectItems({
322
+ pluginId: "activity-history",
323
+ data: [{ id: "note" }],
324
+ text: { raw: "Nota", html: "<p>Nota</p>" },
325
+ title: "Seguiment Clínic",
326
+ });
327
+
328
+ importDataManager.selectItems({
329
+ pluginId: "diagnostics",
330
+ data: [{ id: "diag" }],
331
+ text: { raw: "E11.9", html: "<p>E11.9</p>" },
332
+ });
333
+
334
+ return originalConfirm(...args);
335
+ });
336
+
337
+ const result = await importDataManager.import("test-importer");
338
+
339
+ expect(result.text.raw).toBe("Seguiment Clínic\n\nNota\n\nE11.9\n");
340
+ expect(result.text.html).toBe("<p><strong>Seguiment Clínic</strong></p><p>Nota</p><br><br><p>E11.9</p><p><br></p>");
341
+ });
342
+
343
+ it("leaves out the title of a plugin that ends up contributing no text", async () => {
344
+ mockInteractionService.setMockConfirmResult({ confirmed: true });
345
+
346
+ const originalConfirm = mockInteractionService.confirm.bind(mockInteractionService);
347
+ vi.spyOn(mockInteractionService, "confirm").mockImplementation(async (...args) => {
348
+ importDataManager.selectItems({
349
+ pluginId: "clinical-course",
350
+ data: [],
351
+ text: { raw: "", html: "" },
352
+ title: "Seguiment Clínic",
353
+ });
354
+
355
+ return originalConfirm(...args);
356
+ });
357
+
358
+ const result = await importDataManager.import("test-importer");
359
+
360
+ expect(result.text.raw).toBe("");
361
+ expect(result.text.html).toBe("");
286
362
  });
287
363
  });
288
364
  });
@@ -1,11 +1,11 @@
1
- import { ImportParams, PrimariaImportDataManager } from "./import-data-manager";
2
1
  import { PrimariaInteractionService } from "../interaction-service/interaction-service";
2
+ import { ImportParams, PrimariaImportDataManager } from "./import-data-manager";
3
3
 
4
4
  export class ImportDataManagerImpl implements PrimariaImportDataManager {
5
5
  private selectedItems: Record<string, any[]> = {};
6
6
  private currentImporterId = "";
7
7
  private currentImportParams: ImportParams | undefined;
8
- private pluginTexts: Record<string, { raw: string; html: string }> = {};
8
+ private pluginTexts: Record<string, { raw: string; html: string; title?: string }> = {};
9
9
 
10
10
  constructor(private interactionService: PrimariaInteractionService) {}
11
11
 
@@ -61,12 +61,12 @@ export class ImportDataManagerImpl implements PrimariaImportDataManager {
61
61
  }
62
62
  }
63
63
 
64
- selectItems(payload: { pluginId: string; data: any[]; text: { raw: string; html: string } }): void {
64
+ selectItems(payload: { pluginId: string; data: any[]; text: { raw: string; html: string }; title?: string }): void {
65
65
  console.log(
66
66
  `[ImportDataManager] selectItems — pluginId: "${payload.pluginId}" | items: ${payload.data.length} | text.raw: ${payload.text.raw.length} chars | text.html: ${payload.text.html.length} chars`,
67
67
  );
68
68
  this.selectedItems[payload.pluginId] = payload.data;
69
- this.pluginTexts[payload.pluginId] = payload.text;
69
+ this.pluginTexts[payload.pluginId] = { ...payload.text, title: payload.title };
70
70
  }
71
71
 
72
72
  getCurrentImporterId(): string {
@@ -77,18 +77,45 @@ export class ImportDataManagerImpl implements PrimariaImportDataManager {
77
77
  return this.currentImportParams;
78
78
  }
79
79
 
80
+ /**
81
+ * Ajunta el text de cada plugin que ha contribuït a la importació.
82
+ *
83
+ * Els que declaren el mateix títol formen una sola secció, encapçalada un
84
+ * cop (dues iniciatives poden omplir el mateix apartat del modal: el curs
85
+ * clínic i l'històric d'activitat ho fan amb "Seguiment Clínic"). Els que no
86
+ * en declaren cap van tots junts, sense títol.
87
+ *
88
+ * El resultat acaba amb una línia en blanc perquè qui rep el text pugui
89
+ * seguir escrivint a sota.
90
+ */
80
91
  private getConcatenatedText(): { raw: string; html: string } {
81
- const rawTexts: string[] = [];
82
- const htmlTexts: string[] = [];
83
-
84
- for (const text of Object.values(this.pluginTexts)) {
85
- if (text.raw) rawTexts.push(text.raw);
86
- if (text.html) htmlTexts.push(text.html);
92
+ const sections: { title: string; raw: string[]; html: string[] }[] = [];
93
+
94
+ for (const { raw, html, title } of Object.values(this.pluginTexts)) {
95
+ if (!raw && !html) continue;
96
+ const sectionTitle = title ?? "";
97
+ let section = sections.find((s) => s.title === sectionTitle);
98
+ if (!section) {
99
+ section = { title: sectionTitle, raw: [], html: [] };
100
+ sections.push(section);
101
+ }
102
+ if (raw) section.raw.push(raw);
103
+ if (html) section.html.push(html);
87
104
  }
88
105
 
106
+ const raw = sections
107
+ .filter((section) => section.raw.length > 0)
108
+ .map((section) => (section.title ? `${section.title}\n\n` : "") + section.raw.join("\n\n"))
109
+ .join("\n\n");
110
+
111
+ const html = sections
112
+ .filter((section) => section.html.length > 0)
113
+ .map((section) => (section.title ? `<p><strong>${section.title}</strong></p>` : "") + section.html.join("<br><br>"))
114
+ .join("<br><br>");
115
+
89
116
  return {
90
- raw: rawTexts.join("\n\n"),
91
- html: htmlTexts.join("<br><br>"),
117
+ raw: raw ? `${raw}\n` : "",
118
+ html: html ? `${html}<p><br></p>` : "",
92
119
  };
93
120
  }
94
121
  }
@@ -27,6 +27,11 @@ export interface PrimariaImportDataManager {
27
27
  pluginId: string;
28
28
  data: any[];
29
29
  text: { raw: string; html: string };
30
+ /** Títol que encapçala aquest text dins del resultat de la importació. Els
31
+ * plugins que en declaren un de mateix queden sota un sol títol, en l'ordre
32
+ * en què han publicat la seva selecció. Sense títol, el text s'afegeix tal
33
+ * qual. */
34
+ title?: string;
30
35
  }): void;
31
36
 
32
37
  getCurrentImporterId(): string;