@3cr/viewer-browser 0.0.162 → 0.0.194
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/.circleci/config.yml +8 -6
- package/__tests__/index.spec.ts +31 -24
- package/components.d.ts +32 -0
- package/dist/Viewer3CR.js +44 -27
- package/dist/Viewer3CR.mjs +22731 -17742
- package/dist/Viewer3CR.umd.js +44 -27
- package/index.html +5 -8
- package/index.ts +7 -2
- package/package.json +4 -2
- package/playground/index.html +6 -4
- package/src/App.vue +12 -4
- package/src/__tests__/app.spec.ts +2 -13
- package/src/assets/magic_wand.svg +24 -0
- package/src/components/WebGL3DR.vue +53 -92
- package/src/components/__tests__/webgl3dr.spec.ts +29 -48
- package/src/{demo → components/demo}/DemoModal.vue +1 -1
- package/src/{demo → components/demo}/DemoPatientModal.vue +4 -1
- package/src/components/demo/__tests__/DemoModal.spec.ts +25 -0
- package/src/components/demo/__tests__/DemoPatientModal.spec.ts +37 -0
- package/src/components/demo/__tests__/options.spec.ts +25 -0
- package/src/components/demo/licence/DemoLicenceEnableCloudStorageModal.vue +64 -0
- package/src/{demo → components/demo}/licence/DemoLicenceInfoModal.vue +5 -4
- package/src/{demo → components/demo}/licence/DemoLicenceSendToPartyModal.vue +6 -4
- package/src/{demo → components/demo}/licence/DemoLicenceShareToMobileModal.vue +8 -6
- package/src/components/demo/licence/__tests__/DemoLicenceEnableCloudStorageModal.spec.ts +37 -0
- package/src/components/demo/licence/__tests__/DemoLicenceInfoModal.spec.ts +37 -0
- package/src/components/demo/licence/__tests__/DemoLicenceSendToPartyModal.spec.ts +36 -0
- package/src/components/demo/licence/__tests__/DemoLicenceShareToMobileModal.spec.ts +51 -0
- package/src/{demo → components/demo}/options.ts +18 -20
- package/src/components/demo/patient/DemoPatientEnableCloudStorageModal.vue +64 -0
- package/src/{demo → components/demo}/patient/DemoPatientInfoModal.vue +5 -4
- package/src/{demo → components/demo}/patient/DemoPatientSendToPartyModal.vue +4 -3
- package/src/{demo → components/demo}/patient/DemoPatientShareToMobileModal.vue +8 -6
- package/src/components/demo/patient/__tests__/DemoPatientEnableCloudStorageModal.spec.ts +37 -0
- package/src/components/demo/patient/__tests__/DemoPatientInfoModal.spec.ts +37 -0
- package/src/components/demo/patient/__tests__/DemoPatientSendToPartyModal.spec.ts +36 -0
- package/src/components/demo/patient/__tests__/DemoPatientShareToMobileModal.spec.ts +51 -0
- package/src/components/loading/LoadingSpinner.vue +1 -1
- package/src/components/modal/ActionRail.vue +96 -0
- package/src/components/modal/AskAI.vue +250 -0
- package/src/components/modal/CloseViewerModal.vue +104 -0
- package/src/components/modal/MftpWebGL3DRModal.vue +415 -834
- package/src/components/modal/ViewerActionRail.vue +123 -0
- package/src/components/modal/ViewerAnnotationModal.vue +115 -0
- package/src/components/modal/ViewerAnnotations.vue +283 -0
- package/src/components/modal/ViewerDisplaySettings.vue +102 -0
- package/src/components/modal/ViewerNavigationDrawer.vue +90 -0
- package/src/components/modal/ViewerNavigationDrawerContent.vue +126 -0
- package/src/components/modal/ViewerNavigationDrawerFooter.vue +111 -0
- package/src/components/modal/ViewerNavigationDrawerHeader.vue +63 -0
- package/src/components/modal/__tests__/CloseViewerModal.spec.ts +60 -0
- package/src/components/modal/__tests__/{mftp-webgl-3dr-modal.spec.ts → MftpWebGL3DRModal.spec.ts} +47 -298
- package/src/components/modal/__tests__/ViewerAnnotationModal.spec.ts +79 -0
- package/src/components/modal/__tests__/ViewerDisplaySettings.spec.ts +61 -0
- package/src/components/modal/__tests__/ViewerNavigationDrawer.spec.ts +32 -0
- package/src/components/modal/__tests__/ViewerNavigationDrawerContent.spec.ts +29 -0
- package/src/components/modal/__tests__/ViewerNavigationDrawerFooter.spec.ts +43 -0
- package/src/components/modal/__tests__/ViewerNavigationDrawerHeader.spec.ts +37 -0
- package/src/components/modal/actions/Action.vue +40 -0
- package/src/components/modal/actions/Flip3dAction.vue +79 -0
- package/src/components/modal/actions/FlipHorizontalAction.vue +36 -0
- package/src/components/modal/actions/FlipVerticalAction.vue +36 -0
- package/src/components/modal/actions/FullscreenAction.vue +47 -0
- package/src/components/modal/actions/NavigationCubeAction.vue +33 -0
- package/src/components/modal/actions/PanAction.vue +78 -0
- package/src/components/modal/actions/ResetViewAction.vue +29 -0
- package/src/components/modal/actions/Rotate2dAction.vue +78 -0
- package/src/components/modal/actions/Slice3dAction.vue +71 -0
- package/src/components/modal/actions/ZoomAction.vue +70 -0
- package/src/components/modal/actions/__tests__/Action.spec.ts +29 -0
- package/src/components/modal/actions/__tests__/Flip3dAction.spec.ts +48 -0
- package/src/components/modal/actions/__tests__/FlipHorizontalAction.spec.ts +17 -0
- package/src/components/modal/actions/__tests__/FlipVerticalAction.spec.ts +17 -0
- package/src/components/modal/actions/__tests__/FullscreenAction.spec.ts +28 -0
- package/src/components/modal/actions/__tests__/NavigationCubeAction.spec.ts +25 -0
- package/src/components/modal/actions/__tests__/PanAction.spec.ts +46 -0
- package/src/components/modal/actions/__tests__/ResetViewAction.spec.ts +17 -0
- package/src/components/modal/actions/__tests__/Rotate2dAction.spec.ts +23 -0
- package/src/components/modal/actions/__tests__/Slice3dAction.spec.ts +14 -0
- package/src/components/modal/actions/__tests__/ZoomAction.spec.ts +34 -0
- package/src/components/modal/composables/__tests__/useNavigationCubeObserver.spec.ts +56 -0
- package/src/components/modal/composables/useEventListener.ts +22 -0
- package/src/components/modal/composables/useNavigationCubeObserver.ts +104 -0
- package/src/components/selectors/ValueSelector.vue +30 -33
- package/src/components/selectors/__tests__/value-selector.spec.ts +1 -1
- package/src/components/sliders/DoubleSliderSelector.vue +79 -71
- package/src/components/sliders/VerticalSliderSelector.vue +12 -17
- package/src/components/sliders/__tests__/double-slider-selector.spec.ts +1 -1
- package/src/components/sliders/__tests__/vertical-slider-selector.spec.ts +1 -1
- package/src/dataLayer/__tests__/clamp.spec.ts +16 -0
- package/src/dataLayer/__tests__/eventHandlers.spec.ts +38 -0
- package/src/dataLayer/__tests__/getIconForPreset.spec.ts +40 -0
- package/src/dataLayer/__tests__/patchDataOverlay.spec.ts +88 -0
- package/src/dataLayer/__tests__/scanState.spec.ts +93 -0
- package/src/dataLayer/__tests__/useViewer3cr.spec.ts +10 -0
- package/src/dataLayer/__tests__/viewer3cr.spec.ts +331 -0
- package/src/dataLayer/clamp.ts +9 -0
- package/src/dataLayer/eventHandlers.ts +26 -0
- package/src/dataLayer/patchDataOverlay.ts +101 -0
- package/src/dataLayer/scanState.ts +105 -26
- package/src/dataLayer/useViewer3cr.ts +7 -0
- package/src/dataLayer/viewer3cr.ts +410 -0
- package/src/helpers/__tests__/layout-overlay-style.spec.ts +24 -22
- package/src/helpers/__tests__/model-helper.spec.ts +44 -13
- package/src/helpers/layoutOverlayStyle.ts +16 -27
- package/src/helpers/modelHelper.ts +62 -10
- package/src/models/Callbacks.ts +2 -2
- package/src/models/LoadViewerOptions.ts +2 -0
- package/src/models/LoadViewerPayload.ts +1 -0
- package/src/notifications/notification.ts +3 -4
- package/src/plugins/vuetify.ts +5 -0
- package/src/services/gpt/__tests__/gpt.service.spec.ts +27 -0
- package/src/services/gpt/gpt.service.ts +27 -0
- package/static/3cr-types-browser/index.ts +74 -0
- package/static/3cr-types-browser/types/Action.ts +6 -0
- package/static/3cr-types-browser/types/ActionData.ts +4 -0
- package/static/3cr-types-browser/types/AlphaKeys.ts +5 -0
- package/static/3cr-types-browser/types/AnchorPoint.ts +12 -0
- package/static/3cr-types-browser/types/CallToAction.ts +5 -0
- package/static/3cr-types-browser/types/ColourData.ts +7 -0
- package/static/3cr-types-browser/types/ColourPresetData.ts +9 -0
- package/static/3cr-types-browser/types/CurrentDataOverlayState.ts +6 -0
- package/static/3cr-types-browser/types/CurrentScanState.ts +22 -0
- package/static/3cr-types-browser/types/DataOverlay.ts +22 -0
- package/static/3cr-types-browser/types/DataOverlayActions.ts +14 -0
- package/static/3cr-types-browser/types/DataOverlayData.ts +8 -0
- package/static/3cr-types-browser/types/DataOverlayEvent.ts +8 -0
- package/static/3cr-types-browser/types/DecryptionKey.ts +4 -0
- package/static/3cr-types-browser/types/DisplaySettings.ts +10 -0
- package/static/3cr-types-browser/types/EmptyPayload.ts +3 -0
- package/static/3cr-types-browser/types/EnumPayload.ts +4 -0
- package/static/3cr-types-browser/types/FileManagementActions.ts +11 -0
- package/static/3cr-types-browser/types/FlipValue.ts +7 -0
- package/static/3cr-types-browser/types/FrontEndInterfaces.ts +14 -0
- package/static/3cr-types-browser/types/GradientKeys.ts +7 -0
- package/static/3cr-types-browser/types/GreyscalePresetData.ts +6 -0
- package/static/3cr-types-browser/types/InitialDataOverlayState.ts +6 -0
- package/static/3cr-types-browser/types/InitialScanState.ts +19 -0
- package/static/3cr-types-browser/types/InteractionType.ts +8 -0
- package/static/3cr-types-browser/types/InteractivityActions.ts +6 -0
- package/static/3cr-types-browser/types/InteractivityState.ts +4 -0
- package/static/3cr-types-browser/types/InvertTransformData.ts +6 -0
- package/static/3cr-types-browser/types/LayoutActions.ts +6 -0
- package/static/3cr-types-browser/types/LayoutData.ts +7 -0
- package/static/3cr-types-browser/types/LoadDataSet.ts +6 -0
- package/static/3cr-types-browser/types/LoadSessionState.ts +4 -0
- package/static/3cr-types-browser/types/LocalLoadDataset.ts +3 -0
- package/static/3cr-types-browser/types/MovementData.ts +7 -0
- package/static/3cr-types-browser/types/NavigationCubeActions.ts +8 -0
- package/static/3cr-types-browser/types/NavigationCubeData.ts +12 -0
- package/static/3cr-types-browser/types/NavigationCubeTransform.ts +9 -0
- package/static/3cr-types-browser/types/NotificationPayload.ts +7 -0
- package/static/3cr-types-browser/types/NotificationsActions.ts +6 -0
- package/static/3cr-types-browser/types/Object.ts +1 -0
- package/static/3cr-types-browser/types/ObjectColour.ts +7 -0
- package/static/3cr-types-browser/types/ObjectIcon.ts +5 -0
- package/static/3cr-types-browser/types/ObjectInvert.ts +7 -0
- package/static/3cr-types-browser/types/ObjectSize.ts +7 -0
- package/static/3cr-types-browser/types/ObjectSize2D.ts +7 -0
- package/static/3cr-types-browser/types/ObjectVisible.ts +5 -0
- package/static/3cr-types-browser/types/PositionData.ts +14 -0
- package/static/3cr-types-browser/types/PresetsActions.ts +4 -0
- package/static/3cr-types-browser/types/RotationValue.ts +7 -0
- package/static/3cr-types-browser/types/ScanMovementActions.ts +27 -0
- package/static/3cr-types-browser/types/ScanMovementData.ts +3 -0
- package/static/3cr-types-browser/types/ScanOrientationActions.ts +6 -0
- package/static/3cr-types-browser/types/ScanStateActions.ts +4 -0
- package/static/3cr-types-browser/types/ScanView.ts +6 -0
- package/static/3cr-types-browser/types/SettingsData.ts +12 -0
- package/static/3cr-types-browser/types/SlicerData.ts +9 -0
- package/static/3cr-types-browser/types/SliderValue.ts +4 -0
- package/static/3cr-types-browser/types/SlidersActions.ts +18 -0
- package/static/3cr-types-browser/types/Vector2Data.ts +5 -0
- package/static/3cr-types-browser/types/Vector3Data.ts +6 -0
- package/static/3cr-types-browser/types/VectorMovementData.ts +8 -0
- package/static/3cr-types-browser/types/ViewInteractiveMode.ts +5 -0
- package/static/3cr-types-browser/types/ViewOrientation.ts +8 -0
- package/static/3cr-types-browser/types/ViewOrientations.ts +10 -0
- package/static/3cr-types-browser/types/ViewSelectionActions.ts +9 -0
- package/static/3cr-types-browser/types/ViewToggleData.ts +7 -0
- package/static/3cr-types-browser/types/VolumeOrientation.ts +7 -0
- package/test/helper.ts +10 -1
- package/test/setup.ts +13 -0
- package/tsconfig.json +1 -0
- package/vite.config.mts +1 -0
- package/src/dataLayer/__tests__/payload-handler.spec.ts +0 -214
- package/src/dataLayer/payloadHandler.ts +0 -138
- /package/src/dataLayer/{iconData.ts → getIconForPreset.ts} +0 -0
package/index.html
CHANGED
|
@@ -18,24 +18,21 @@
|
|
|
18
18
|
import {registerViewer, loadViewer} from './index.ts';
|
|
19
19
|
|
|
20
20
|
const { StatsigClient, SessionReplay, runStatsigAutoCapture, runStatsigSessionReplay } = window.Statsig;
|
|
21
|
+
|
|
21
22
|
const client = new StatsigClient(
|
|
22
23
|
"client-YaAjxOTTRbuSN3peDAwXEzErieXpI744a3OHDgonzvV",
|
|
23
24
|
{ userID: undefined },
|
|
24
|
-
{environment: {tier: '
|
|
25
|
+
{environment: {tier: 'development'}}
|
|
25
26
|
);
|
|
26
|
-
|
|
27
|
-
// const replayer = new SessionReplay(client);
|
|
28
|
-
// console.log(replayer)
|
|
27
|
+
client.initializeSync()
|
|
29
28
|
|
|
30
29
|
runStatsigAutoCapture(client);
|
|
31
30
|
window.playgroundStatsigClient = client
|
|
32
|
-
// runStatsigSessionReplay(client);
|
|
33
|
-
|
|
34
31
|
|
|
35
32
|
|
|
36
|
-
const dynamicConfig =
|
|
33
|
+
const dynamicConfig = client.getDynamicConfig("3cr_viewer_version");
|
|
37
34
|
const testVersion = (window.location.href.includes('test.') || window.location.href.includes('localhost')) && new URLSearchParams(window.location.search).get("build_version")
|
|
38
|
-
const version = testVersion ?? dynamicConfig.value["sdkVersion"] ?? "1.0
|
|
35
|
+
const version = testVersion ?? dynamicConfig.value["sdkVersion"] ?? "1.1.0";
|
|
39
36
|
|
|
40
37
|
client.initializeAsync().then(() => {
|
|
41
38
|
registerViewer(version).then(() => {
|
package/index.ts
CHANGED
|
@@ -57,11 +57,16 @@ export async function loadViewer(
|
|
|
57
57
|
await (mountedApp as any).loadInstance(payload, options);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export async function loadSession(url: string): Promise<void> {
|
|
61
|
+
if (!mountedApp) {
|
|
62
|
+
throw new Error("Please call `registerViewer(version: string)` first");
|
|
63
|
+
}
|
|
64
|
+
await (mountedApp as any).loadSession(url);
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
export async function ejectViewer() {
|
|
61
|
-
console.log("Ejected Viewer");
|
|
62
68
|
const modal = document.getElementById(modalId);
|
|
63
69
|
const styleSheet = document.getElementById(injectedStyleId);
|
|
64
|
-
|
|
65
70
|
modal?.remove();
|
|
66
71
|
styleSheet?.remove();
|
|
67
72
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3cr/viewer-browser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.194",
|
|
4
4
|
"main": "./dist/Viewer3CR.umd.js",
|
|
5
5
|
"module": "dist/Viewer3CR.umd.js",
|
|
6
6
|
"homepage": "https://docs.3cr.singular.health",
|
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@3cr/sdk-browser": "^1.0.13",
|
|
25
|
-
"@3cr/types-ts": "
|
|
25
|
+
"@3cr/types-ts": "file:static/3cr-types-browser",
|
|
26
26
|
"@kyvg/vue3-notification": "^3.2.1",
|
|
27
27
|
"@mdi/font": "6.2.95",
|
|
28
28
|
"@mdi/js": "^7.4.47",
|
|
29
|
+
"axios": "^1.7.2",
|
|
30
|
+
"intro.js": "^7.2.0",
|
|
29
31
|
"logrocket": "^8.1.0",
|
|
30
32
|
"roboto-fontface": "*",
|
|
31
33
|
"vue": "^3.4.21",
|
package/playground/index.html
CHANGED
|
@@ -80,17 +80,19 @@
|
|
|
80
80
|
<script type="module">
|
|
81
81
|
|
|
82
82
|
const { StatsigClient, runStatsigAutoCapture } = window.Statsig;
|
|
83
|
+
const isTest = (window.location.href.includes('test.') || window.location.href.includes('localhost'))
|
|
83
84
|
const client = new StatsigClient(
|
|
84
85
|
"client-YaAjxOTTRbuSN3peDAwXEzErieXpI744a3OHDgonzvV",
|
|
85
86
|
{ userID: undefined },
|
|
86
|
-
{environment: {tier: 'production'}}
|
|
87
|
+
{environment: {tier: isTest ? 'development' : 'production'}}
|
|
87
88
|
);
|
|
89
|
+
client.initializeSync()
|
|
88
90
|
runStatsigAutoCapture(client);
|
|
89
91
|
window.playgroundStatsigClient = client
|
|
90
92
|
|
|
91
|
-
const dynamicConfig =
|
|
92
|
-
const testVersion = (
|
|
93
|
-
const version = testVersion ?? dynamicConfig.value["sdkVersion"] ?? "1.0
|
|
93
|
+
const dynamicConfig = client.getDynamicConfig("3cr_viewer_version");
|
|
94
|
+
const testVersion = (isTest) && new URLSearchParams(window.location.search).get("build_version")
|
|
95
|
+
const version = testVersion ?? dynamicConfig.value["sdkVersion"] ?? "1.1.0";
|
|
94
96
|
|
|
95
97
|
client.initializeAsync().then(() => {
|
|
96
98
|
window.registerViewer(version).then(() => {
|
package/src/App.vue
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
defaultLoadViewerOptions,
|
|
21
21
|
LoadViewerOptions,
|
|
22
22
|
} from "@/models/LoadViewerOptions";
|
|
23
|
-
import { isDemo } from "@/demo/options";
|
|
23
|
+
import { isDemo } from "@/components/demo/options";
|
|
24
24
|
import LogRocket from "logrocket";
|
|
25
25
|
|
|
26
26
|
if (isDemo.value) {
|
|
@@ -34,12 +34,10 @@ const payload = ref<LoadViewerPayload>({
|
|
|
34
34
|
Key: "KUc722X1y4w42M+jCf9a3+6EGz66z7UMWK3m2aMqGxM=",
|
|
35
35
|
},
|
|
36
36
|
});
|
|
37
|
+
|
|
37
38
|
const options = ref<LoadViewerOptions>(defaultLoadViewerOptions);
|
|
38
39
|
|
|
39
40
|
const mftpWebGL3DRModal = ref<typeof MftpWebGL3DRModal | null>(null);
|
|
40
|
-
defineExpose({
|
|
41
|
-
loadInstance,
|
|
42
|
-
});
|
|
43
41
|
|
|
44
42
|
async function loadInstance(
|
|
45
43
|
payloadIncoming: LoadViewerPayload | undefined,
|
|
@@ -51,7 +49,17 @@ async function loadInstance(
|
|
|
51
49
|
await nextTick();
|
|
52
50
|
unref(mftpWebGL3DRModal)?.alterValue(true);
|
|
53
51
|
}
|
|
52
|
+
|
|
53
|
+
async function loadSession(url: string): Promise<void> {
|
|
54
|
+
await unref(mftpWebGL3DRModal)?.loadSession(url);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
defineExpose({
|
|
58
|
+
loadInstance,
|
|
59
|
+
loadSession,
|
|
60
|
+
});
|
|
54
61
|
</script>
|
|
62
|
+
|
|
55
63
|
<style>
|
|
56
64
|
.material-icons-outlined,
|
|
57
65
|
.material-symbols-outlined {
|
|
@@ -1,25 +1,14 @@
|
|
|
1
|
-
import { expect, describe, it
|
|
1
|
+
import { expect, describe, it } from "vitest";
|
|
2
2
|
import { shallowMountVuetify } from "~/helper";
|
|
3
3
|
import App from "@/App.vue";
|
|
4
4
|
|
|
5
5
|
const wrapper = shallowMountVuetify(App);
|
|
6
6
|
|
|
7
|
-
vi.mock("@3cr/sdk-browser", async (importOriginal) => {
|
|
8
|
-
const mod = (await importOriginal()) as object;
|
|
9
|
-
return {
|
|
10
|
-
...mod,
|
|
11
|
-
// replace some exports
|
|
12
|
-
registerVersion: vi.fn(),
|
|
13
|
-
createInstance: vi.fn(),
|
|
14
|
-
executePayload: vi.fn(),
|
|
15
|
-
registerOnPayloadHandler: vi.fn(),
|
|
16
|
-
};
|
|
17
|
-
});
|
|
18
|
-
|
|
19
7
|
describe("App.vue", () => {
|
|
20
8
|
it("should inflate component", () => {
|
|
21
9
|
expect(wrapper).toBeTruthy();
|
|
22
10
|
});
|
|
11
|
+
|
|
23
12
|
it("should loadScan", async () => {
|
|
24
13
|
await wrapper.vm.loadInstance(undefined, {});
|
|
25
14
|
expect(wrapper).toBeTruthy();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
|
|
3
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
4
|
+
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
5
|
+
<svg width="800px" height="800px" viewBox="-3 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
6
|
+
<g id="icomoon-ignore">
|
|
7
|
+
</g>
|
|
8
|
+
<path d="M-0.007 28.236l13.916-13.916 0.754 0.754-13.916 13.916-0.754-0.754z" fill="#000000">
|
|
9
|
+
|
|
10
|
+
<path d="M9.973 10.453h4.267v1.067h-4.267v-1.067z" fill="#000000">
|
|
11
|
+
|
|
12
|
+
<path d="M21.707 10.453h4.267v1.067h-4.267v-1.067z" fill="#000000">
|
|
13
|
+
|
|
14
|
+
<path d="M17.44 14.72h1.067v4.267h-1.067v-4.267z" fill="#000000">
|
|
15
|
+
|
|
16
|
+
<path d="M17.44 2.987h1.067v4.267h-1.067v-4.267z" fill="#000000">
|
|
17
|
+
|
|
18
|
+
<path d="M23.991 5.717l-3.017 3.017-0.754-0.754 3.017-3.017 0.754 0.754z" fill="#000000">
|
|
19
|
+
|
|
20
|
+
<path d="M23.246 17.042l-3.017-3.017 0.754-0.754 3.017 3.017-0.754 0.754z" fill="#000000">
|
|
21
|
+
|
|
22
|
+
<path d="M14.986 8.741l-3.017-3.017 0.754-0.754 3.017 3.017-0.754 0.754z" fill="#000000">
|
|
23
|
+
|
|
24
|
+
</svg>
|
|
@@ -1,82 +1,46 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
id="screenshotWindow"
|
|
4
|
-
class=""
|
|
5
|
-
@mouseover="emit('hover', true)"
|
|
6
|
-
@mouseout="emit('hover', false)"
|
|
7
|
-
>
|
|
2
|
+
<div id="webgl-container">
|
|
8
3
|
<canvas
|
|
9
|
-
id="
|
|
4
|
+
id="canvas"
|
|
5
|
+
ref="canvas"
|
|
10
6
|
width="100%"
|
|
11
|
-
height="
|
|
7
|
+
height="100%"
|
|
12
8
|
tabindex="-1"
|
|
13
|
-
style="
|
|
14
|
-
width: 100%;
|
|
15
|
-
height: calc(100vh - 50px);
|
|
16
|
-
background-size: cover !important;
|
|
17
|
-
"
|
|
18
9
|
>
|
|
19
10
|
</canvas>
|
|
20
|
-
<div id="
|
|
11
|
+
<div id="overlay" ref="overlay">
|
|
21
12
|
<slot></slot>
|
|
22
13
|
</div>
|
|
23
14
|
</div>
|
|
24
15
|
</template>
|
|
25
|
-
<script setup lang="ts">
|
|
26
|
-
import { defineEmits, nextTick, onMounted, ref } from "vue";
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
registerOnPayloadHandler,
|
|
32
|
-
} from "@3cr/sdk-browser";
|
|
33
|
-
import {
|
|
34
|
-
FrontEndInterfaces,
|
|
35
|
-
FrontEndPayload,
|
|
36
|
-
} from "@3cr/sdk-browser/types/payload";
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { onMounted, ref } from "vue";
|
|
19
|
+
import { useViewer3cr } from '@/dataLayer/useViewer3cr';
|
|
37
20
|
|
|
38
|
-
const
|
|
21
|
+
const viewer3cr = useViewer3cr();
|
|
22
|
+
const canvas = ref<HTMLCanvasElement>();
|
|
23
|
+
const overlay = ref<HTMLDivElement>();
|
|
39
24
|
|
|
40
25
|
const emit = defineEmits<{
|
|
41
26
|
instance_loaded: [void];
|
|
42
|
-
on_payload: [FrontEndInterfaces, string, string];
|
|
43
|
-
hover: [boolean];
|
|
44
27
|
}>();
|
|
45
28
|
|
|
46
|
-
defineExpose({
|
|
47
|
-
sendPayload,
|
|
48
|
-
receiveMessageFromUnity,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
29
|
onMounted(async () => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
await registerOnPayloadHandler(receiveMessageFromUnity);
|
|
30
|
+
if (!canvas.value || !overlay.value) {
|
|
31
|
+
throw new Error('One or more canvases failed to load');
|
|
32
|
+
}
|
|
56
33
|
|
|
57
34
|
/* c8 ignore start */
|
|
58
35
|
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
|
|
59
36
|
// Mobile device style: fill the whole browser client area with the game canvas:
|
|
60
37
|
const meta = document.createElement("meta");
|
|
61
38
|
meta.name = "viewport";
|
|
62
|
-
meta.content =
|
|
63
|
-
"width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes";
|
|
39
|
+
meta.content = "width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes";
|
|
64
40
|
document.getElementsByTagName("head")[0].appendChild(meta);
|
|
65
|
-
|
|
66
|
-
canvas.style.width = "100%";
|
|
67
|
-
canvas.style.height = "80vh";
|
|
68
|
-
canvas.style.position = "fixed";
|
|
69
|
-
|
|
70
|
-
document.body.style.textAlign = "left";
|
|
71
41
|
}
|
|
72
|
-
/* c8 ignore stop */
|
|
73
|
-
await nextTick();
|
|
74
|
-
unityInstance.value = await createInstance(canvas);
|
|
75
|
-
|
|
76
|
-
await nextTick();
|
|
77
42
|
|
|
78
|
-
|
|
79
|
-
if (navigator.storage) {
|
|
43
|
+
if (navigator.storage && navigator.storage.estimate) {
|
|
80
44
|
const quota = await navigator.storage.estimate();
|
|
81
45
|
if (quota) {
|
|
82
46
|
const percentageUsed = (quota.usage! / quota.quota!) * 100;
|
|
@@ -87,55 +51,52 @@ onMounted(async () => {
|
|
|
87
51
|
}
|
|
88
52
|
/* c8 ignore stop */
|
|
89
53
|
|
|
90
|
-
emit("instance_loaded");
|
|
91
54
|
// Overlay scroll events to the container instance
|
|
92
|
-
const fixedDiv = document.getElementById("parent-canvas");
|
|
93
55
|
/* c8 ignore start */
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const evt = new WheelEvent("wheel", {
|
|
97
|
-
...e,
|
|
98
|
-
deltaY: e.deltaY,
|
|
99
|
-
});
|
|
100
|
-
canvas.dispatchEvent(evt);
|
|
101
|
-
});
|
|
102
|
-
function injectEventListener(eventType: keyof HTMLElementEventMap) {
|
|
103
|
-
fixedDiv?.addEventListener(eventType, function (e: Event) {
|
|
56
|
+
function injectEventListener(type: keyof HTMLElementEventMap) {
|
|
57
|
+
overlay.value!.addEventListener(type, (e: Event) => {
|
|
104
58
|
e.preventDefault();
|
|
105
|
-
|
|
106
|
-
...e,
|
|
107
|
-
});
|
|
108
|
-
canvas.dispatchEvent(evt);
|
|
59
|
+
canvas.value!.dispatchEvent(new MouseEvent(type, e));
|
|
109
60
|
});
|
|
110
61
|
}
|
|
111
|
-
injectEventListener("mousedown");
|
|
112
|
-
injectEventListener("mouseup");
|
|
113
|
-
injectEventListener("mouseout");
|
|
114
|
-
injectEventListener("mouseover");
|
|
115
|
-
injectEventListener("mouseenter");
|
|
116
|
-
injectEventListener("mouseleave");
|
|
117
|
-
injectEventListener("mousemove");
|
|
118
|
-
injectEventListener("contextmenu");
|
|
119
|
-
injectEventListener("dblclick");
|
|
120
62
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
63
|
+
overlay.value!.addEventListener("wheel", (e: WheelEvent) => {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
canvas.value!.dispatchEvent(new WheelEvent(e.type, e));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
injectEventListener('click');
|
|
69
|
+
injectEventListener('dblclick');
|
|
70
|
+
injectEventListener('auxclick');
|
|
71
|
+
injectEventListener('mousedown');
|
|
72
|
+
injectEventListener('mousemove');
|
|
73
|
+
injectEventListener('mouseup');
|
|
74
|
+
injectEventListener('mouseout');
|
|
75
|
+
injectEventListener('mouseover');
|
|
76
|
+
injectEventListener('mouseenter');
|
|
77
|
+
injectEventListener('mouseleave');
|
|
78
|
+
injectEventListener('contextmenu');
|
|
79
|
+
|
|
80
|
+
await viewer3cr.register(canvas.value);
|
|
81
|
+
emit("instance_loaded");
|
|
131
82
|
|
|
132
83
|
/* c8 ignore stop */
|
|
133
84
|
});
|
|
134
85
|
|
|
135
|
-
|
|
136
|
-
|
|
86
|
+
defineExpose({ canvas });
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<style scoped lang="scss">
|
|
90
|
+
#webgl-container {
|
|
91
|
+
position: relative;
|
|
92
|
+
width: 100%;
|
|
93
|
+
height: 100%;
|
|
137
94
|
}
|
|
138
|
-
|
|
139
|
-
|
|
95
|
+
|
|
96
|
+
#canvas, #overlay {
|
|
97
|
+
position: absolute;
|
|
98
|
+
inset: 0;
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 100%;
|
|
140
101
|
}
|
|
141
|
-
</
|
|
102
|
+
</style>
|
|
@@ -1,56 +1,37 @@
|
|
|
1
|
-
import { expect,
|
|
2
|
-
import WebGL3DR from "../WebGL3DR.vue";
|
|
1
|
+
import { expect, describe, it } from "vitest";
|
|
3
2
|
import { registerOnPayloadHandler, createInstance } from "@3cr/sdk-browser";
|
|
4
3
|
import { mountVuetify } from "~/helper";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
vi.mock("@3cr/sdk-browser", async (importOriginal) => {
|
|
8
|
-
const mod = (await importOriginal()) as object;
|
|
9
|
-
return {
|
|
10
|
-
...mod,
|
|
11
|
-
registerVersion: vi.fn(),
|
|
12
|
-
createInstance: vi.fn(),
|
|
13
|
-
executePayload: vi.fn(),
|
|
14
|
-
registerOnPayloadHandler: vi.fn(),
|
|
15
|
-
};
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const wrapper = mountVuetify(WebGL3DR);
|
|
4
|
+
import { nextTick } from "vue";
|
|
5
|
+
import WebGL3DR from "../WebGL3DR.vue";
|
|
19
6
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
test("creates instance", () => {
|
|
27
|
-
wrapper.vm.receiveMessageFromUnity({
|
|
28
|
-
Action: FileManagementActions.fm01 as any,
|
|
29
|
-
Message: "testing message",
|
|
30
|
-
Interface: FrontEndInterfaces.file_management as any,
|
|
7
|
+
describe('WebGL3DR spec', () => {
|
|
8
|
+
it("creates instance", async () => {
|
|
9
|
+
mountVuetify(WebGL3DR);
|
|
10
|
+
await nextTick();
|
|
11
|
+
expect(createInstance).toHaveBeenCalled();
|
|
12
|
+
expect(registerOnPayloadHandler).toHaveBeenCalled();
|
|
31
13
|
});
|
|
32
14
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const parentCanvas = wrapper.find("#parent-canvas");
|
|
40
|
-
parentCanvas.trigger("wheel");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("mouseover", () => {
|
|
44
|
-
const parentCanvas = wrapper.find("#screenshotWindow");
|
|
45
|
-
parentCanvas.trigger("mouseover");
|
|
46
|
-
|
|
47
|
-
expect(wrapper.emitted()["hover"]).toStrictEqual([[true]]);
|
|
48
|
-
});
|
|
15
|
+
it("should emit wheel event", () => {
|
|
16
|
+
const wrapper = mountVuetify(WebGL3DR);
|
|
17
|
+
const overlay = wrapper.find("#overlay");
|
|
18
|
+
overlay.trigger("wheel");
|
|
19
|
+
expect(wrapper.emitted()["wheel"]).toBeTruthy();
|
|
20
|
+
});
|
|
49
21
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
22
|
+
it("should emit mouseover event", () => {
|
|
23
|
+
const wrapper = mountVuetify(WebGL3DR);
|
|
24
|
+
const overlay = wrapper.find("#overlay");
|
|
25
|
+
overlay.trigger("mouseover");
|
|
26
|
+
expect(wrapper.emitted()["mouseover"]).toBeTruthy();
|
|
27
|
+
});
|
|
54
28
|
|
|
55
|
-
|
|
29
|
+
it("should emit mouseout event", () => {
|
|
30
|
+
const wrapper = mountVuetify(WebGL3DR);
|
|
31
|
+
const overlay = wrapper.find("#overlay");
|
|
32
|
+
overlay.trigger("mouseover");
|
|
33
|
+
overlay.trigger("mouseout");
|
|
34
|
+
expect(wrapper.emitted()["mouseover"]).toBeTruthy();
|
|
35
|
+
expect(wrapper.emitted()["mouseout"]).toBeTruthy();
|
|
36
|
+
});
|
|
56
37
|
});
|
|
@@ -37,7 +37,7 @@ const modalState = computed({
|
|
|
37
37
|
<v-card-text> support@singular.health </v-card-text>
|
|
38
38
|
<v-card-actions>
|
|
39
39
|
<v-spacer />
|
|
40
|
-
<v-btn color="primary" @click="modalState = false"> Thanks! </v-btn>
|
|
40
|
+
<v-btn data-testid="close" color="primary" @click="modalState = false"> Thanks! </v-btn>
|
|
41
41
|
</v-card-actions>
|
|
42
42
|
</v-card>
|
|
43
43
|
</v-dialog>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
+
import {PRICING_URL} from "@/components/demo/options";
|
|
3
4
|
|
|
4
5
|
export interface Props {
|
|
5
6
|
modal: boolean;
|
|
@@ -39,6 +40,7 @@ function openUrl(url: string) {
|
|
|
39
40
|
</v-card-text>
|
|
40
41
|
<v-card-actions>
|
|
41
42
|
<v-btn
|
|
43
|
+
data-testid="close"
|
|
42
44
|
color="error"
|
|
43
45
|
@click="modalState = false"
|
|
44
46
|
:disabled="!isModalOpen"
|
|
@@ -47,9 +49,10 @@ function openUrl(url: string) {
|
|
|
47
49
|
</v-btn>
|
|
48
50
|
<v-spacer />
|
|
49
51
|
<v-btn
|
|
52
|
+
data-testid="select-plan"
|
|
50
53
|
variant="tonal"
|
|
51
54
|
color="success"
|
|
52
|
-
@click="openUrl(
|
|
55
|
+
@click="openUrl(PRICING_URL)"
|
|
53
56
|
>
|
|
54
57
|
Select a Plan
|
|
55
58
|
</v-btn>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {mountVuetify, openAllModals} from "~/helper";
|
|
3
|
+
import DemoModal from "@/components/demo/DemoModal.vue";
|
|
4
|
+
|
|
5
|
+
describe('DemoModal tests', () => {
|
|
6
|
+
it('should mount', () => {
|
|
7
|
+
const props = { modal: true };
|
|
8
|
+
const wrapper = mountVuetify(DemoModal, props);
|
|
9
|
+
expect(wrapper).toBeTruthy();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should close', async () => {
|
|
13
|
+
const props = { modal: true };
|
|
14
|
+
const wrapper = mountVuetify(DemoModal, props);
|
|
15
|
+
const button = wrapper.findComponent('[data-testid="close"]');
|
|
16
|
+
await button.trigger('click');
|
|
17
|
+
expect(wrapper.emitted()['update:modal']).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should open via input', async () => {
|
|
21
|
+
const props = { modal: false };
|
|
22
|
+
const wrapper = mountVuetify(DemoModal, props);
|
|
23
|
+
await openAllModals(wrapper);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { mountVuetify, openAllModals } from "~/helper";
|
|
3
|
+
import { PRICING_URL } from "@/components/demo/options";
|
|
4
|
+
import DemoPatientModal from "@/components/demo/DemoPatientModal.vue";
|
|
5
|
+
|
|
6
|
+
describe('DemoPatientModal tests', () => {
|
|
7
|
+
it('should mount', () => {
|
|
8
|
+
const props = { modal: true, isModalOpen: true };
|
|
9
|
+
const wrapper = mountVuetify(DemoPatientModal, props);
|
|
10
|
+
expect(wrapper).toBeTruthy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should close', async () => {
|
|
14
|
+
const props = { modal: true, isModalOpen: true };
|
|
15
|
+
const wrapper = mountVuetify(DemoPatientModal, props);
|
|
16
|
+
const button = wrapper.findComponent('[data-testid="close"]');
|
|
17
|
+
await button.trigger('click');
|
|
18
|
+
expect(wrapper.emitted()['update:modal']).toBeTruthy();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should open pricing url', async () => {
|
|
22
|
+
vi.stubGlobal('open', vi.fn());
|
|
23
|
+
const spy = vi.spyOn(window, 'open');
|
|
24
|
+
const props = { modal: true, isModalOpen: true };
|
|
25
|
+
const wrapper = mountVuetify(DemoPatientModal, props);
|
|
26
|
+
const button = wrapper.findComponent('[data-testid="select-plan"]');
|
|
27
|
+
await button.trigger('click');
|
|
28
|
+
expect(spy).toHaveBeenCalledWith(PRICING_URL, '_self');
|
|
29
|
+
vi.restoreAllMocks();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should open via input', async () => {
|
|
33
|
+
const props = { modal: false, isModalOpen: true };
|
|
34
|
+
const wrapper = mountVuetify(DemoPatientModal, props);
|
|
35
|
+
await openAllModals(wrapper);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { demoLicenceOptions, demoPatientOptions } from "@/components/demo/options";
|
|
3
|
+
import { LoadViewerOptions } from "@/models/LoadViewerOptions";
|
|
4
|
+
|
|
5
|
+
describe('options tests', () => {
|
|
6
|
+
it('should call demo license options', () => {
|
|
7
|
+
Object.keys(demoLicenceOptions).forEach(key => {
|
|
8
|
+
const k = key as keyof LoadViewerOptions;
|
|
9
|
+
const fn = demoLicenceOptions[k];
|
|
10
|
+
if (fn) {
|
|
11
|
+
expect(fn).not.toThrow();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should call demo patient options', () => {
|
|
17
|
+
Object.keys(demoPatientOptions).forEach(key => {
|
|
18
|
+
const k = key as keyof LoadViewerOptions;
|
|
19
|
+
const fn = demoPatientOptions[k];
|
|
20
|
+
if (fn) {
|
|
21
|
+
expect(fn).not.toThrow();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog width="600" v-model:model-value="modalState">
|
|
3
|
+
<v-card theme="dark" class="motif-background">
|
|
4
|
+
<v-card-title class="text-center font-weight-bold">
|
|
5
|
+
Enable Cloud Storage
|
|
6
|
+
</v-card-title>
|
|
7
|
+
<v-card-text>
|
|
8
|
+
<p style="text-align: center;">Enable annual storage for just <b>5 credits</b>.</p>
|
|
9
|
+
<br />
|
|
10
|
+
<div>
|
|
11
|
+
<v-row no-gutters v-for="(benefit, idx) in benefits" :key="idx">
|
|
12
|
+
<v-col class="d-flex justify-end" cols="2">
|
|
13
|
+
<v-icon class="mr-2" color="success" icon="check" />
|
|
14
|
+
</v-col>
|
|
15
|
+
<v-col>
|
|
16
|
+
{{ benefit }}
|
|
17
|
+
</v-col>
|
|
18
|
+
</v-row>
|
|
19
|
+
</div>
|
|
20
|
+
</v-card-text>
|
|
21
|
+
<v-card-actions>
|
|
22
|
+
<v-btn data-testid="close" color="red" @click="modalState = false">
|
|
23
|
+
Continue with Demo
|
|
24
|
+
</v-btn>
|
|
25
|
+
<v-spacer />
|
|
26
|
+
<v-btn data-testid="confirm" variant="flat" color="success" @click="openUrl(PRICING_URL)">
|
|
27
|
+
Enable Cloud Storage
|
|
28
|
+
</v-btn>
|
|
29
|
+
</v-card-actions>
|
|
30
|
+
</v-card>
|
|
31
|
+
</v-dialog>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { computed } from 'vue';
|
|
36
|
+
import { PRICING_URL, openUrl } from '@/components/demo/options';
|
|
37
|
+
|
|
38
|
+
interface Props {
|
|
39
|
+
modal?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type Emits = {
|
|
43
|
+
'update:modal': [value: boolean];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const props = defineProps<Props>();
|
|
47
|
+
|
|
48
|
+
const emit = defineEmits<Emits>();
|
|
49
|
+
|
|
50
|
+
const benefits = [
|
|
51
|
+
'Secure storage',
|
|
52
|
+
'Access your scan from any device',
|
|
53
|
+
'Keep your medical imaging records at your fingertips'
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const modalState = computed({
|
|
57
|
+
get(): boolean {
|
|
58
|
+
return props.modal;
|
|
59
|
+
},
|
|
60
|
+
set(value: boolean): void {
|
|
61
|
+
emit('update:modal', value);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
</script>
|