@3cr/viewer-browser 0.0.58 → 0.0.62

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 (57) hide show
  1. package/components.d.ts +1 -0
  2. package/coverage/.tmp/coverage-100.json +1 -0
  3. package/coverage/.tmp/coverage-101.json +1 -0
  4. package/coverage/.tmp/coverage-102.json +1 -0
  5. package/coverage/.tmp/coverage-103.json +1 -0
  6. package/coverage/.tmp/coverage-104.json +1 -0
  7. package/coverage/.tmp/coverage-105.json +1 -0
  8. package/coverage/.tmp/coverage-106.json +1 -0
  9. package/coverage/.tmp/coverage-107.json +1 -0
  10. package/coverage/.tmp/coverage-108.json +1 -0
  11. package/coverage/.tmp/coverage-109.json +1 -0
  12. package/coverage/.tmp/coverage-110.json +1 -0
  13. package/coverage/.tmp/coverage-98.json +1 -0
  14. package/coverage/.tmp/coverage-99.json +1 -0
  15. package/dist/Viewer3CR.js +11 -11
  16. package/dist/Viewer3CR.mjs +6093 -5964
  17. package/dist/Viewer3CR.umd.js +11 -11
  18. package/package.json +2 -1
  19. package/src/components/modal/DemoPatientModal.vue +59 -0
  20. package/src/components/modal/MftpWebGL3DRModal.vue +56 -9
  21. package/src/components/modal/__tests__/mftp-webgl-3dr-modal.spec.ts +37 -1
  22. package/src/components/selectors/ValueSelector.vue +18 -13
  23. package/src/components/sliders/DoubleSliderSelector.vue +12 -4
  24. package/src/components/sliders/VerticalSliderSelector.vue +5 -2
  25. package/coverage/3cr-viewer-browser/index.html +0 -116
  26. package/coverage/3cr-viewer-browser/index.ts.html +0 -211
  27. package/coverage/3cr-viewer-browser/src/App.vue.html +0 -313
  28. package/coverage/3cr-viewer-browser/src/components/WebGL3DR.vue.html +0 -442
  29. package/coverage/3cr-viewer-browser/src/components/icons/index.html +0 -116
  30. package/coverage/3cr-viewer-browser/src/components/icons/liver.vue.html +0 -148
  31. package/coverage/3cr-viewer-browser/src/components/index.html +0 -116
  32. package/coverage/3cr-viewer-browser/src/components/loading/LoadingSpinner.vue.html +0 -556
  33. package/coverage/3cr-viewer-browser/src/components/loading/index.html +0 -116
  34. package/coverage/3cr-viewer-browser/src/components/modal/MftpWebGL3DRModal.vue.html +0 -4126
  35. package/coverage/3cr-viewer-browser/src/components/modal/index.html +0 -116
  36. package/coverage/3cr-viewer-browser/src/components/selectors/ValueSelector.vue.html +0 -331
  37. package/coverage/3cr-viewer-browser/src/components/selectors/index.html +0 -116
  38. package/coverage/3cr-viewer-browser/src/components/sliders/DoubleSliderSelector.vue.html +0 -445
  39. package/coverage/3cr-viewer-browser/src/components/sliders/VerticalSliderSelector.vue.html +0 -349
  40. package/coverage/3cr-viewer-browser/src/components/sliders/index.html +0 -131
  41. package/coverage/3cr-viewer-browser/src/helpers/index.html +0 -146
  42. package/coverage/3cr-viewer-browser/src/helpers/layoutOverlayStyle.ts.html +0 -406
  43. package/coverage/3cr-viewer-browser/src/helpers/modelHelper.ts.html +0 -412
  44. package/coverage/3cr-viewer-browser/src/helpers/utils.ts.html +0 -133
  45. package/coverage/3cr-viewer-browser/src/index.html +0 -131
  46. package/coverage/3cr-viewer-browser/src/main.ts.html +0 -124
  47. package/coverage/3cr-viewer-browser/src/plugins/index.html +0 -131
  48. package/coverage/3cr-viewer-browser/src/plugins/index.ts.html +0 -130
  49. package/coverage/3cr-viewer-browser/src/plugins/vuetify.ts.html +0 -220
  50. package/coverage/base.css +0 -224
  51. package/coverage/block-navigation.js +0 -87
  52. package/coverage/favicon.png +0 -0
  53. package/coverage/index.html +0 -251
  54. package/coverage/prettify.css +0 -1
  55. package/coverage/prettify.js +0 -2
  56. package/coverage/sort-arrow-sprite.png +0 -0
  57. package/coverage/sorter.js +0 -196
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3cr/viewer-browser",
3
- "version": "0.0.58",
3
+ "version": "0.0.62",
4
4
  "main": "./dist/Viewer3CR.umd.js",
5
5
  "module": "dist/Viewer3CR.umd.js",
6
6
  "homepage": "https://docs.3cr.singular.health",
@@ -14,6 +14,7 @@
14
14
  "deploy": "npm version --no-git-tag-version patch && npm run build && npm publish",
15
15
  "preview": "vite preview",
16
16
  "test": "vitest",
17
+ "test:ui": "vitest --ui",
17
18
  "compile:scripts": "tsc --project tsconfig.build-scripts.json",
18
19
  "deploy:playground": "npm run compile:scripts && node scripts/postPublish.js",
19
20
  "coverage": "vitest run --coverage"
@@ -0,0 +1,59 @@
1
+ <script setup lang="ts">
2
+ import { computed } from "vue";
3
+
4
+ export interface Props {
5
+ modal: boolean;
6
+ isModalOpen: boolean;
7
+ }
8
+
9
+ const emit = defineEmits<{
10
+ "update:modal": [value: boolean];
11
+ }>();
12
+
13
+ const props = withDefaults(defineProps<Props>(), {
14
+ modal: false,
15
+ isModalOpen: true,
16
+ });
17
+
18
+ const modalState = computed({
19
+ get() {
20
+ return props.modal;
21
+ },
22
+ set(value) {
23
+ emit("update:modal", value);
24
+ },
25
+ });
26
+ function openUrl(url: string) {
27
+ window.open(url, "_self");
28
+ }
29
+ </script>
30
+
31
+ <template>
32
+ <v-dialog v-model:model-value="modalState">
33
+ <v-card class="pa-1 ma-auto position-relative" max-width="450">
34
+ <v-card-title>Purchase 3Dicom Viewer</v-card-title>
35
+ <v-card-text> Thank you for trying 3Dicom Online Viewer! </v-card-text>
36
+ <v-card-text>
37
+ This instance of the Online Viewer is a Demo instance. If you would like
38
+ to see your scans in 3D, please choose a plan for 3DICOM
39
+ </v-card-text>
40
+ <v-card-actions>
41
+ <v-btn
42
+ color="error"
43
+ @click="modalState = false"
44
+ :disabled="!isModalOpen"
45
+ >
46
+ Continue with Viewer
47
+ </v-btn>
48
+ <v-spacer />
49
+ <v-btn
50
+ variant="tonal"
51
+ color="success"
52
+ @click="openUrl('https://3dicomviewer.com/pricing')"
53
+ >
54
+ Select a Plan
55
+ </v-btn>
56
+ </v-card-actions>
57
+ </v-card>
58
+ </v-dialog>
59
+ </template>
@@ -1,6 +1,7 @@
1
1
  <!-- /* c8 ignore start */ -->
2
2
  <template>
3
3
  <DemoModal v-model:modal="m_demo" />
4
+ <DemoPatientModal v-model:modal="m_demoPatient" :is-modal-open="value" />
4
5
  <v-dialog
5
6
  id="cr-viewer"
6
7
  class="pa-0 ma-0 overflow-y-auto overflow-x-hidden"
@@ -161,7 +162,9 @@
161
162
 
162
163
  <v-spacer />
163
164
  <div class="font-weight-bold">
164
- <span v-if="isDemo">[DEMO]&nbsp;</span>Not for Diagnostic Use
165
+ <span v-if="isDemo" class="text-capitalize"
166
+ >[3DICOM {{ demoType }} Demo]&nbsp;</span
167
+ >Not for Diagnostic Use
165
168
  </div>
166
169
  <v-spacer />
167
170
  <v-btn
@@ -693,6 +696,10 @@ import {
693
696
  LoadViewerPayload,
694
697
  } from "../../../index";
695
698
 
699
+ import { useNotification } from "@kyvg/vue3-notification";
700
+
701
+ const { notify } = useNotification();
702
+
696
703
  const emit = defineEmits<{
697
704
  instanceLoaded: [void];
698
705
  snap: [void];
@@ -715,8 +722,9 @@ const props = withDefaults(defineProps<Props>(), {
715
722
  });
716
723
  const isDemo = ref<boolean>(false);
717
724
  let m_demo = ref<boolean>(false);
725
+ let m_demoPatient = ref<boolean>(false);
718
726
 
719
- const demoOptions: LoadViewerOptions = {
727
+ const demoLicenceOptions: LoadViewerOptions = {
720
728
  OnClosePopup: () => Promise.resolve(),
721
729
  OnExitViewer: () => {
722
730
  m_demo.value = true;
@@ -747,11 +755,54 @@ const demoOptions: LoadViewerOptions = {
747
755
  },
748
756
  };
749
757
 
758
+ const demoPatientOptions: LoadViewerOptions = {
759
+ OnClosePopup: () => Promise.resolve(),
760
+ OnExitViewer: () => {
761
+ m_demoPatient.value = true;
762
+ },
763
+ OnLoadNewDicomSeries: () => {
764
+ m_demoPatient.value = true;
765
+ },
766
+ OnDownloadDicomSeries: () => {
767
+ m_demoPatient.value = true;
768
+ },
769
+ OnLoadSavedSession: () => {
770
+ m_demoPatient.value = true;
771
+ },
772
+ OnSaveSession: () => {
773
+ m_demoPatient.value = true;
774
+ },
775
+ OnSendTo3rdParty: () => {
776
+ m_demoPatient.value = true;
777
+ },
778
+ OnShareToMobile: () => {
779
+ m_demoPatient.value = true;
780
+ },
781
+ OnShare: () => {
782
+ m_demoPatient.value = true;
783
+ },
784
+ OnScreenshot: () => {
785
+ m_demoPatient.value = true;
786
+ },
787
+ };
788
+
789
+ const demoType = computed(() => {
790
+ const urlParams = new URLSearchParams(window.location.search);
791
+ return urlParams.get("demoType") || "licence";
792
+ });
793
+
750
794
  function executeOption(key: keyof LoadViewerOptions) {
751
795
  if (unref(isDemo)) {
752
- const functionToExecute = demoOptions[key];
753
- if (functionToExecute !== undefined) {
754
- functionToExecute();
796
+ if (unref(demoType) === "licence") {
797
+ const functionToExecute = demoLicenceOptions[key];
798
+ if (functionToExecute !== undefined) {
799
+ functionToExecute();
800
+ }
801
+ } else if (unref(demoType) === "patient") {
802
+ const functionToExecute = demoPatientOptions[key];
803
+ if (functionToExecute !== undefined) {
804
+ functionToExecute();
805
+ }
755
806
  }
756
807
  } else {
757
808
  const functionToExecute = unref(props.options)[key];
@@ -1175,10 +1226,6 @@ async function i_fileManagement(action: string, message: string) {
1175
1226
  await hoverOverCanvas(false);
1176
1227
  }
1177
1228
 
1178
- import { useNotification } from "@kyvg/vue3-notification";
1179
-
1180
- const { notify } = useNotification();
1181
-
1182
1229
  async function i_notifications(action: string, message: string) {
1183
1230
  const notification = JSON.parse(message) as NotificationPayload;
1184
1231
 
@@ -9,6 +9,8 @@ import {
9
9
  AnchorPoint,
10
10
  FileManagementActions,
11
11
  FrontEndInterfaces,
12
+ InteractivityActions,
13
+ NotificationPayload,
12
14
  PositionData,
13
15
  PresetsActions,
14
16
  ScanMovementActions,
@@ -29,6 +31,15 @@ vi.mock("@3cr/sdk-browser", async (importOriginal) => {
29
31
  registerOnPayloadHandler: vi.fn(),
30
32
  };
31
33
  });
34
+ vi.mock("@kyvg/vue3-notification", async (importOriginal) => {
35
+ const mod = (await importOriginal()) as object;
36
+ return {
37
+ ...mod,
38
+ useNotification: {
39
+ notify: vi.fn(),
40
+ },
41
+ };
42
+ });
32
43
 
33
44
  describe("MftpWebGL3DRModal.vue", () => {
34
45
  let wrapper = shallowMountVuetify(
@@ -292,6 +303,14 @@ describe("MftpWebGL3DRModal.vue", () => {
292
303
  wrapper.findComponent("#close-dialog-prompt");
293
304
  });
294
305
 
306
+ it("should closeModal", async () => {
307
+ wrapper.vm.closeModal();
308
+ wrapper.vm.alterValue(false);
309
+
310
+ await flushPromises();
311
+ wrapper.findComponent("#close-dialog-prompt");
312
+ });
313
+
295
314
  it("should handleOnPayload file_management", async () => {
296
315
  wrapper.vm.handleOnPayload(
297
316
  FrontEndInterfaces.file_management,
@@ -308,7 +327,24 @@ describe("MftpWebGL3DRModal.vue", () => {
308
327
  );
309
328
  });
310
329
  it("should handleOnPayload notifications", async () => {
311
- wrapper.vm.handleOnPayload(FrontEndInterfaces.notifications, "123", "123");
330
+ wrapper.vm.handleOnPayload(
331
+ FrontEndInterfaces.notifications,
332
+ "123",
333
+ JSON.stringify({
334
+ Action: InteractivityActions.in01,
335
+ Code: "S00000",
336
+ } as NotificationPayload)
337
+ );
338
+ });
339
+ it("should handleOnPayload notifications", async () => {
340
+ wrapper.vm.handleOnPayload(
341
+ FrontEndInterfaces.notifications,
342
+ "123",
343
+ JSON.stringify({
344
+ Action: InteractivityActions.in02,
345
+ Code: "S00000",
346
+ } as NotificationPayload)
347
+ );
312
348
  });
313
349
 
314
350
  it("should handleOnPayload scan_state", async () => {
@@ -1,7 +1,6 @@
1
1
  <script setup lang="ts">
2
- import {computed, defineEmits} from 'vue';
3
-
4
-
2
+ import { computed, defineEmits } from "vue";
3
+ import { toNumber } from "@/helpers/utils";
5
4
 
6
5
  export interface Props {
7
6
  value: number;
@@ -9,8 +8,8 @@ export interface Props {
9
8
  label?: string;
10
9
  min?: number;
11
10
  max?: number;
12
- step?: number,
13
- prepend?: string,
11
+ step?: number;
12
+ prepend?: string;
14
13
  }
15
14
 
16
15
  const props = withDefaults(defineProps<Props>(), {
@@ -20,19 +19,22 @@ const props = withDefaults(defineProps<Props>(), {
20
19
  min: -99999,
21
20
  max: 99999,
22
21
  step: 1,
23
- prepend: '',
22
+ prepend: "",
24
23
  });
25
24
  const emit = defineEmits<{
26
- 'update:value': [number];
25
+ "update:value": [number];
27
26
  }>();
28
27
  const sliderValue = computed({
29
28
  get() {
30
- return props.value
29
+ return Math.floor(props.value);
31
30
  },
32
31
  set(value: number) {
33
- emit('update:value', value);
34
- }
35
- })
32
+ let val = value;
33
+ if (value > props.max) val = props.max;
34
+ if (value < props.min) val = props.min;
35
+ emit("update:value", Math.floor(val));
36
+ },
37
+ });
36
38
  </script>
37
39
 
38
40
  <template>
@@ -45,7 +47,8 @@ const sliderValue = computed({
45
47
  </v-col>
46
48
  <v-col cols="6">
47
49
  <v-text-field
48
- v-model="sliderValue"
50
+ :model-value="sliderValue"
51
+ @update:modelValue="sliderValue = toNumber($event)"
49
52
  outlined
50
53
  dense
51
54
  class="mt-0 pt-0"
@@ -65,7 +68,9 @@ const sliderValue = computed({
65
68
  .v-text-field.v-text-field--enclosed:not(.v-text-field--rounded)
66
69
  > .v-input__control
67
70
  > .v-input__slot,
68
- .single-slider-selector .v-text-field.v-text-field--enclosed .v-text-field__details {
71
+ .single-slider-selector
72
+ .v-text-field.v-text-field--enclosed
73
+ .v-text-field__details {
69
74
  padding: 0px 8px !important;
70
75
  }
71
76
 
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, defineEmits, ref, unref, watch } from "vue";
3
+ import { toNumber } from "@vue/shared";
3
4
 
4
5
  export interface Props {
5
6
  value: Array<number>;
@@ -33,10 +34,15 @@ const sliderValue = computed({
33
34
  return props.value;
34
35
  },
35
36
  set(value: Array<number>) {
36
- emit("update:value", value);
37
+ let val = value;
38
+ if (value[0] > props.max) val[0] = props.max;
39
+ if (value[1] > props.max) val[1] = props.max;
40
+ if (value[0] < props.min) val[0] = props.min;
41
+ if (value[1] < props.min) val[1] = props.min;
42
+ const normalised = [Math.floor(val[0]), Math.floor(val[1])];
43
+ emit("update:value", normalised);
37
44
  },
38
45
  });
39
-
40
46
  watch(
41
47
  sliderValue,
42
48
  async (currentValue: Array<number>) => {
@@ -60,7 +66,8 @@ watch(
60
66
  }}</v-card-subtitle>
61
67
  <v-card-actions class="px-2 pb-0">
62
68
  <v-text-field
63
- v-model="sliderValue[0]"
69
+ :model-value="sliderValue[0]"
70
+ @update:modelValue="sliderValue = [toNumber($event), sliderValue[1]]"
64
71
  density="compact"
65
72
  class="mt-0 pt-0"
66
73
  hide-details
@@ -70,7 +77,8 @@ watch(
70
77
  ></v-text-field>
71
78
  <v-spacer />
72
79
  <v-text-field
73
- v-model="sliderValue[1]"
80
+ :model-value="sliderValue[1]"
81
+ @update:modelValue="sliderValue = [sliderValue[0], toNumber($event)]"
74
82
  density="compact"
75
83
  class="mt-0 pt-0"
76
84
  hide-details
@@ -30,10 +30,10 @@ const showThumb = ref<"always" | boolean>(true);
30
30
  const showThumbTimeout = ref<NodeJS.Timeout | undefined>(undefined);
31
31
  const sliderValue = computed({
32
32
  get() {
33
- return props.value;
33
+ return Math.floor(props.value);
34
34
  },
35
35
  set(value: number) {
36
- emit("update:value", value);
36
+ emit("update:value", Math.floor(value));
37
37
  },
38
38
  });
39
39
 
@@ -73,6 +73,9 @@ watch(
73
73
  <template #prepend>
74
74
  <div class="text-white py-1 my-0 text-center">{{ min }}</div>
75
75
  </template>
76
+ <template v-slot:thumb-label="{ modelValue }">
77
+ {{ Math.floor(modelValue) }}
78
+ </template>
76
79
  </v-slider>
77
80
  </template>
78
81
 
@@ -1,116 +0,0 @@
1
-
2
- <!doctype html>
3
- <html lang="en">
4
-
5
- <head>
6
- <title>Code coverage report for 3cr-viewer-browser</title>
7
- <meta charset="utf-8" />
8
- <link rel="stylesheet" href="../prettify.css" />
9
- <link rel="stylesheet" href="../base.css" />
10
- <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
- <meta name="viewport" content="width=device-width, initial-scale=1" />
12
- <style type='text/css'>
13
- .coverage-summary .sorter {
14
- background-image: url(../sort-arrow-sprite.png);
15
- }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <div class='wrapper'>
21
- <div class='pad1'>
22
- <h1><a href="../index.html">All files</a> 3cr-viewer-browser</h1>
23
- <div class='clearfix'>
24
-
25
- <div class='fl pad1y space-right2'>
26
- <span class="strong">100% </span>
27
- <span class="quiet">Statements</span>
28
- <span class='fraction'>42/42</span>
29
- </div>
30
-
31
-
32
- <div class='fl pad1y space-right2'>
33
- <span class="strong">100% </span>
34
- <span class="quiet">Branches</span>
35
- <span class='fraction'>3/3</span>
36
- </div>
37
-
38
-
39
- <div class='fl pad1y space-right2'>
40
- <span class="strong">100% </span>
41
- <span class="quiet">Functions</span>
42
- <span class='fraction'>2/2</span>
43
- </div>
44
-
45
-
46
- <div class='fl pad1y space-right2'>
47
- <span class="strong">100% </span>
48
- <span class="quiet">Lines</span>
49
- <span class='fraction'>42/42</span>
50
- </div>
51
-
52
-
53
- </div>
54
- <p class="quiet">
55
- Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
- </p>
57
- <template id="filterTemplate">
58
- <div class="quiet">
59
- Filter:
60
- <input type="search" id="fileSearch">
61
- </div>
62
- </template>
63
- </div>
64
- <div class='status-line high'></div>
65
- <div class="pad1">
66
- <table class="coverage-summary">
67
- <thead>
68
- <tr>
69
- <th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
70
- <th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
71
- <th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
72
- <th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
73
- <th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
74
- <th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
75
- <th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
76
- <th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
77
- <th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
78
- <th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
79
- </tr>
80
- </thead>
81
- <tbody><tr>
82
- <td class="file high" data-value="index.ts"><a href="index.ts.html">index.ts</a></td>
83
- <td data-value="100" class="pic high">
84
- <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
85
- </td>
86
- <td data-value="100" class="pct high">100%</td>
87
- <td data-value="42" class="abs high">42/42</td>
88
- <td data-value="100" class="pct high">100%</td>
89
- <td data-value="3" class="abs high">3/3</td>
90
- <td data-value="100" class="pct high">100%</td>
91
- <td data-value="2" class="abs high">2/2</td>
92
- <td data-value="100" class="pct high">100%</td>
93
- <td data-value="42" class="abs high">42/42</td>
94
- </tr>
95
-
96
- </tbody>
97
- </table>
98
- </div>
99
- <div class='push'></div><!-- for sticky footer -->
100
- </div><!-- /wrapper -->
101
- <div class='footer quiet pad2 space-top1 center small'>
102
- Code coverage generated by
103
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2024-04-09T22:46:57.006Z
105
- </div>
106
- <script src="../prettify.js"></script>
107
- <script>
108
- window.onload = function () {
109
- prettyPrint();
110
- };
111
- </script>
112
- <script src="../sorter.js"></script>
113
- <script src="../block-navigation.js"></script>
114
- </body>
115
- </html>
116
-