(self["webpackChunkviewer"] = self["webpackChunkviewer"] || []).push([["main"],{ /***/ 93955 /*!****************************************************!*\ !*** ./apps/viewer/src/app/app-loading.service.ts ***! \****************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AppLoadingService: () => (/* binding */ AppLoadingService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); class AppLoadingService { loadingText = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('Loading…', ...(ngDevMode ? [{ debugName: "loadingText" }] : [])); static ɵfac = function AppLoadingService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AppLoadingService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: AppLoadingService, factory: AppLoadingService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 18815 /*!************************************!*\ !*** ./apps/viewer/src/app/app.ts ***! \************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ App: () => (/* binding */ App) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/router */ 38709); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_confirmdialog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/confirmdialog */ 77531); /* harmony import */ var primeng_toast__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/toast */ 73794); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_electron_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/electron-utils */ 63940); /* harmony import */ var _tomoverse_feature__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/feature */ 8938); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _app_loading_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./app-loading.service */ 93955); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @angular/core */ 14975); function App_Conditional_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](1, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](2, "p", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate"](ctx_r0.appLoading.loadingText()); } } function App_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "section", 8); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](1, "router-outlet"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵclassProp"]("electron-macos", ctx_r0.isElectronMacOS); } } function App_ng_template_5_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](0, "lib-icon", 10); } if (rf & 2) { const conf_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("icon", conf_r2.icon); } } function App_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](1, App_ng_template_5_Conditional_1_Template, 1, 1, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const conf_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](conf_r2.icon ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate"](conf_r2.message); } } function App_ng_template_7_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p-button", 11); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("onClick", function App_ng_template_7_Conditional_1_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const confirm_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](4); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](confirm_r4.onAccept()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](1, "p-button", 12); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("onClick", function App_ng_template_7_Conditional_1_Template_p_button_onClick_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const confirm_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](4); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](confirm_r4.onReject()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); const confirmation_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("buttonProps", confirmation_r5 == null ? null : confirmation_r5.acceptButtonProps)("label", confirmation_r5 == null ? null : confirmation_r5.acceptLabel); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("buttonProps", confirmation_r5 == null ? null : confirmation_r5.rejectButtonProps)("label", confirmation_r5 == null ? null : confirmation_r5.rejectLabel); } } function App_ng_template_7_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p-button", 13); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("onClick", function App_ng_template_7_Conditional_2_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const confirm_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](4); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](confirm_r4.onReject()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](1, "p-button", 14); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("onClick", function App_ng_template_7_Conditional_2_Template_p_button_onClick_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const confirm_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](4); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](confirm_r4.onAccept()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); const confirmation_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("buttonProps", confirmation_r5 == null ? null : confirmation_r5.rejectButtonProps)("label", confirmation_r5 == null ? null : confirmation_r5.rejectLabel); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("buttonProps", confirmation_r5 == null ? null : confirmation_r5.acceptButtonProps)("label", confirmation_r5 == null ? null : confirmation_r5.acceptLabel); } } function App_ng_template_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](1, App_ng_template_7_Conditional_1_Template, 2, 4)(2, App_ng_template_7_Conditional_2_Template, 2, 4); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); const confirm_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](4); const confirmation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵstoreLet"](confirm_r4.confirmation); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"]((confirmation_r7 == null ? null : confirmation_r7.defaultFocus) === "accept" ? 1 : 2); } } class App { log = (0,_tomoverse_feature__WEBPACK_IMPORTED_MODULE_9__.getLogger)(App.name); authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__.AuthService); rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__.RxdbManager); dicomDatabase = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__.DicomDatabaseService); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_2__.Router); appLoading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_app_loading_service__WEBPACK_IMPORTED_MODULE_11__.AppLoadingService); devOptions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__.DevelopmentOptionsService); isElectronMacOS = (0,_tomoverse_electron_utils__WEBPACK_IMPORTED_MODULE_8__.isElectron)() && typeof navigator !== 'undefined' && navigator.userAgent.includes('Mac OS X'); toastPt = { closeButton: { style: { margin: '0' } }, messageContent: { style: { alignItems: 'center' } }, messageText: { style: { gap: '0' } } }; constructor() { var _this = this; (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const isAuthenticated = _this.authService.isAuthenticated(); yield (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (isAuthenticated) { yield _this.rxdbManager.init(); return; } // Session-scoped peek cache (see DicomDatabaseService.clearPeekCache) must not carry // over into the next login, same reasoning as AuthService.logout clearing preferences. _this.dicomDatabase.clearPeekCache(); yield _this.rxdbManager.remove(); })); })); this.log.debug('Application started'); } ngOnInit() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { if (_this2.authService.isAuthenticated() && _this2.devOptions.clearDicomCacheOnStartup() && (yield _this2.dicomDatabase.hasLocalDicomImports())) { _this2.appLoading.loadingText.set('Clearing local DICOM storage…'); yield _this2.dicomDatabase.clearLocalImports(_this2.getActiveSeriesUid()); } } finally { _this2.appLoading.loadingText.set(undefined); } })(); } getActiveSeriesUid() { // Route: /volume-viewer/:storeUid/:studyUid/:seriesUid/:workSessionUid let route = this.router.routerState.snapshot.root; while (route.firstChild) route = route.firstChild; return route.paramMap.get('seriesUid') ?? undefined; } static ɵfac = function App_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || App)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵdefineComponent"]({ type: App, selectors: [["app-root"]], decls: 9, vars: 2, consts: [["confirm", ""], ["message", ""], ["footer", ""], ["id", "app-loading"], [1, "h-screen", "w-full", "overflow-auto", 3, "electron-macos"], ["position", "top-center", 3, "pt"], ["id", "app-loading-spinner"], ["id", "app-loading-text"], [1, "h-screen", "w-full", "overflow-auto"], [1, "align-items-center", "flex", "flex-row", "gap-3"], [1, "text-3xl", 3, "icon"], ["data-test-id", "app-p-button-confirm-accept", "styleClass", "p-confirm-default-action", 1, "order-2", 3, "onClick", "buttonProps", "label"], ["data-test-id", "app-p-button-confirm-reject", 1, "order-1", 3, "onClick", "buttonProps", "label"], ["data-test-id", "app-p-button-confirm-reject", 3, "onClick", "buttonProps", "label"], ["data-test-id", "app-p-button-confirm-accept", 3, "onClick", "buttonProps", "label"]], template: function App_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](0, App_Conditional_0_Template, 4, 1, "div", 3)(1, App_Conditional_1_Template, 2, 2, "section", 4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](2, "p-toast", 5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](3, "p-confirm-dialog", null, 0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](5, App_ng_template_5_Template, 4, 2, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"])(7, App_ng_template_7_Template, 3, 2, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.appLoading.loadingText() ? 0 : 1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("pt", ctx.toastPt); } }, dependencies: [_angular_router__WEBPACK_IMPORTED_MODULE_3__.RouterModule, _angular_router__WEBPACK_IMPORTED_MODULE_2__.RouterOutlet, primeng_button__WEBPACK_IMPORTED_MODULE_4__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_4__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__.IconComponent, primeng_confirmdialog__WEBPACK_IMPORTED_MODULE_5__.ConfirmDialog, primeng_toast__WEBPACK_IMPORTED_MODULE_6__.ToastModule, primeng_toast__WEBPACK_IMPORTED_MODULE_6__.Toast], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 37407 /*!***********************************************!*\ !*** ./apps/viewer/src/app/runtime-config.ts ***! \***********************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getRuntimeConfig: () => (/* binding */ getRuntimeConfig), /* harmony export */ loadRuntimeConfig: () => (/* binding */ loadRuntimeConfig) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); let runtimeConfig = {}; const parseRuntimeConfig = value => { if (typeof value !== 'object' || value === null) return {}; const config = value; return { ...(typeof config['apiUrl'] === 'string' && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.isValidBackendApiUrl)(config['apiUrl']) ? { apiUrl: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.normalizeBackendApiUrl)(config['apiUrl']) } : {}), ...(typeof config['loginRouteRedirect'] === 'string' ? { loginRouteRedirect: config['loginRouteRedirect'] } : {}), ...(typeof config['signUpRouteRedirect'] === 'string' ? { signUpRouteRedirect: config['signUpRouteRedirect'] } : {}), ...(Array.isArray(config['staticHosts']) && config['staticHosts'].every(host => typeof host === 'string') ? { staticHosts: config['staticHosts'] } : {}), ...(typeof config['transferSyntaxUid'] === 'string' ? { transferSyntaxUid: config['transferSyntaxUid'] } : {}) }; }; const loadBundledRuntimeConfig = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const response = yield fetch(`assets/tvct-config.json?version=${Date.now()}`, { cache: 'no-store' }); if (!response.ok) return {}; return parseRuntimeConfig(yield response.json()); } catch { return {}; } }); return function loadBundledRuntimeConfig() { return _ref.apply(this, arguments); }; }(); function loadRuntimeConfig() { return _loadRuntimeConfig.apply(this, arguments); } function _loadRuntimeConfig() { _loadRuntimeConfig = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const bundledConfig = yield loadBundledRuntimeConfig(); if (!globalThis.electronAPI?.getRuntimeConfig) { runtimeConfig = bundledConfig; return runtimeConfig; } try { runtimeConfig = { ...bundledConfig, ...parseRuntimeConfig(yield globalThis.electronAPI.getRuntimeConfig()) }; } catch { runtimeConfig = bundledConfig; } return runtimeConfig; }); return _loadRuntimeConfig.apply(this, arguments); } function getRuntimeConfig() { if (!runtimeConfig.loginRouteRedirect || !runtimeConfig.signUpRouteRedirect || !runtimeConfig.staticHosts || !runtimeConfig.transferSyntaxUid) { throw new Error('Runtime configuration is missing required viewer settings.'); } return runtimeConfig; } /***/ }, /***/ 97283 /*!*********************************!*\ !*** ./apps/viewer/src/main.ts ***! \*********************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_platform_browser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/platform-browser */ 91486); /* harmony import */ var _app_app__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./app/app */ 18815); /* harmony import */ var _app_runtime_config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app/runtime-config */ 37407); // Prevent trackpad pinch zoom from magnifying the entire page. globalThis.addEventListener('wheel', event => { if (event.ctrlKey) event.preventDefault(); }, { passive: false }); function bootstrap() { return _bootstrap.apply(this, arguments); } // eslint-disable-next-line function _bootstrap() { _bootstrap = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield (0,_app_runtime_config__WEBPACK_IMPORTED_MODULE_3__.loadRuntimeConfig)(); const { appConfig } = yield __webpack_require__.e(/*! import() */ "apps_viewer_src_app_app_config_ts").then(__webpack_require__.bind(__webpack_require__, /*! ./app/app.config */ 36271)); yield (0,_angular_platform_browser__WEBPACK_IMPORTED_MODULE_1__.bootstrapApplication)(_app_app__WEBPACK_IMPORTED_MODULE_2__.App, appConfig); }); return _bootstrap.apply(this, arguments); } void bootstrap().catch(error => console.error(error)); /***/ }, /***/ 19875 /*!*************************************!*\ !*** ./libs/contracts/src/index.ts ***! \*************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CLOUD_RUN_MAX_REQUEST_BYTES: () => (/* reexport safe */ _lib_dicom_upload_limits__WEBPACK_IMPORTED_MODULE_2__.CLOUD_RUN_MAX_REQUEST_BYTES), /* harmony export */ DEFAULT_API_BODY_LIMIT_BYTES: () => (/* reexport safe */ _lib_dicom_upload_limits__WEBPACK_IMPORTED_MODULE_2__.DEFAULT_API_BODY_LIMIT_BYTES), /* harmony export */ MAX_UPLOAD_BATCH_BYTES: () => (/* reexport safe */ _lib_dicom_upload_limits__WEBPACK_IMPORTED_MODULE_2__.MAX_UPLOAD_BATCH_BYTES), /* harmony export */ OT_PAYLOAD_LATEST_VERSION: () => (/* reexport safe */ _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__.OT_PAYLOAD_LATEST_VERSION), /* harmony export */ OT_PAYLOAD_SCHEMA_VERSION: () => (/* reexport safe */ _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__.OT_PAYLOAD_SCHEMA_VERSION), /* harmony export */ WORK_SESSION_LATEST_SCHEMA: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.WORK_SESSION_LATEST_SCHEMA), /* harmony export */ annotationPayloadSchema: () => (/* reexport safe */ _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__.annotationPayloadSchema), /* harmony export */ annotationPayloadV1Schema: () => (/* reexport safe */ _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__.annotationPayloadV1Schema), /* harmony export */ annotationProtocolBindingV1Schema: () => (/* reexport safe */ _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__.annotationProtocolBindingV1Schema), /* harmony export */ annotationSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.annotationSchema), /* harmony export */ dicomInstanceId: () => (/* reexport safe */ _lib_dicom_schema__WEBPACK_IMPORTED_MODULE_0__.dicomInstanceId), /* harmony export */ dicomSchema: () => (/* reexport safe */ _lib_dicom_schema__WEBPACK_IMPORTED_MODULE_0__.dicomSchema), /* harmony export */ dicomSchemaLiteral: () => (/* reexport safe */ _lib_dicom_schema__WEBPACK_IMPORTED_MODULE_0__.dicomSchemaLiteral), /* harmony export */ dicomSeriesId: () => (/* reexport safe */ _lib_dicom_series_schema__WEBPACK_IMPORTED_MODULE_1__.dicomSeriesId), /* harmony export */ dicomSeriesSchema: () => (/* reexport safe */ _lib_dicom_series_schema__WEBPACK_IMPORTED_MODULE_1__.dicomSeriesSchema), /* harmony export */ dicomSeriesSchemaLiteral: () => (/* reexport safe */ _lib_dicom_series_schema__WEBPACK_IMPORTED_MODULE_1__.dicomSeriesSchemaLiteral), /* harmony export */ matrixSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.matrixSchema), /* harmony export */ placeholderSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.placeholderSchema), /* harmony export */ point2Schema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.point2Schema), /* harmony export */ point3Schema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.point3Schema), /* harmony export */ protocolDefinitionSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.protocolDefinitionSchema), /* harmony export */ protocolInstanceSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.protocolInstanceSchema), /* harmony export */ protocolVolumeDataSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.protocolVolumeDataSchema), /* harmony export */ quatSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.quatSchema), /* harmony export */ rxDbAttachmentSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.rxDbAttachmentSchema), /* harmony export */ workSessionJsonSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.workSessionJsonSchema), /* harmony export */ workSessionRxdbJsonSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.workSessionRxdbJsonSchema), /* harmony export */ workSessionSchema: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.workSessionSchema), /* harmony export */ workSessionSchemaWithAttachments: () => (/* reexport safe */ _lib_work_session__WEBPACK_IMPORTED_MODULE_4__.workSessionSchemaWithAttachments) /* harmony export */ }); /* harmony import */ var _lib_dicom_schema__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/dicom.schema */ 77746); /* harmony import */ var _lib_dicom_series_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/dicom-series.schema */ 82096); /* harmony import */ var _lib_dicom_upload_limits__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/dicom-upload-limits */ 99482); /* harmony import */ var _lib_ot_payload__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/ot-payload */ 16520); /* harmony import */ var _lib_work_session__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/work-session */ 32656); /***/ }, /***/ 82096 /*!*******************************************************!*\ !*** ./libs/contracts/src/lib/dicom-series.schema.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ dicomSeriesId: () => (/* binding */ dicomSeriesId), /* harmony export */ dicomSeriesSchema: () => (/* binding */ dicomSeriesSchema), /* harmony export */ dicomSeriesSchemaLiteral: () => (/* binding */ dicomSeriesSchemaLiteral) /* harmony export */ }); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! rxdb */ 69402); const dicomSeriesId = (storeUid, seriesInstanceUID) => `${storeUid}|${seriesInstanceUID}`; const dicomSeriesSchemaLiteral = { description: 'Stores DICOM series metadata', indexes: ['studyInstanceUID', 'storeUid', 'seriesInstanceUID'], primaryKey: 'id', properties: { createdAt: { type: 'integer' }, id: { maxLength: 300, type: 'string' }, institutionName: { maxLength: 128, type: ['string', 'null'] }, modality: { maxLength: 32, type: ['string', 'null'] }, patientID: { maxLength: 128, type: ['string', 'null'] }, patientName: { maxLength: 128, type: ['string', 'null'] }, seriesDate: { maxLength: 128, type: ['string', 'null'] }, seriesDescription: { maxLength: 256, type: ['string', 'null'] }, seriesInstanceUID: { maxLength: 128, type: 'string' }, seriesNumber: { type: ['integer', 'null'] }, seriesTime: { maxLength: 128, type: ['string', 'null'] }, storeUid: { maxLength: 128, type: 'string' }, studyDate: { maxLength: 128, type: ['string', 'null'] }, studyDescription: { maxLength: 256, type: ['string', 'null'] }, studyInstanceUID: { maxLength: 128, type: 'string' } }, required: ['id', 'seriesInstanceUID', 'studyInstanceUID', 'storeUid'], title: 'Dicom series schema', type: 'object', version: 2 }; const _schemaTyped = (0,rxdb__WEBPACK_IMPORTED_MODULE_0__.toTypedRxJsonSchema)(dicomSeriesSchemaLiteral); const dicomSeriesSchema = dicomSeriesSchemaLiteral; /***/ }, /***/ 99482 /*!*******************************************************!*\ !*** ./libs/contracts/src/lib/dicom-upload-limits.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CLOUD_RUN_MAX_REQUEST_BYTES: () => (/* binding */ CLOUD_RUN_MAX_REQUEST_BYTES), /* harmony export */ DEFAULT_API_BODY_LIMIT_BYTES: () => (/* binding */ DEFAULT_API_BODY_LIMIT_BYTES), /* harmony export */ MAX_UPLOAD_BATCH_BYTES: () => (/* binding */ MAX_UPLOAD_BATCH_BYTES) /* harmony export */ }); /** * Shared between the frontend upload batcher (dicom-api.service.ts) and the API's * body size limit (apps/api/src/main.ts). These three values must stay in this * relationship - MAX_UPLOAD_BATCH_BYTES < DEFAULT_API_BODY_LIMIT_BYTES < * CLOUD_RUN_MAX_REQUEST_BYTES - or a batch the frontend considers safely under * Cloud Run's limit gets silently rejected by the API before it ever reaches * Cloud Run (see TVC-897, TVC-895, TVC-1110 - this has regressed three times). */ // Cloud Run's front end enforces a fixed, unconfigurable ~32MB limit on unary HTTP // request bodies. const CLOUD_RUN_MAX_REQUEST_BYTES = 32 * 1024 * 1024; // Frontend upload batches are capped well under that, leaving headroom for // multipart boundary overhead. const MAX_UPLOAD_BATCH_BYTES = 20 * 1024 * 1024; // The API's own body size limit must sit between the two above, so a batch never // gets rejected by the API before Cloud Run even sees it. const DEFAULT_API_BODY_LIMIT_BYTES = 25 * 1024 * 1024; /***/ }, /***/ 77746 /*!************************************************!*\ !*** ./libs/contracts/src/lib/dicom.schema.ts ***! \************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ dicomInstanceId: () => (/* binding */ dicomInstanceId), /* harmony export */ dicomSchema: () => (/* binding */ dicomSchema), /* harmony export */ dicomSchemaLiteral: () => (/* binding */ dicomSchemaLiteral) /* harmony export */ }); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! rxdb */ 69402); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const dicomInstanceId = (storeUid, sopInstanceUID) => `${storeUid}|${sopInstanceUID}`; const dicomSchemaLiteral = { attachments: { encrypted: false }, description: 'Stores DICOM metadata and sync status', indexes: ['seriesUid', 'studyUid', 'storeUid', 'sopInstanceUID', 'syncStatus'], primaryKey: 'id', properties: { createdAt: { type: 'integer' }, id: { maxLength: 300, type: 'string' }, instanceNumber: { default: 0, type: 'integer' }, metadata: { additionalProperties: true, type: 'object' }, seriesUid: { maxLength: 128, type: 'string' }, sopInstanceUID: { maxLength: 128, type: 'string' }, storeUid: { maxLength: 128, type: 'string' }, studyUid: { maxLength: 128, type: 'string' }, syncStatus: { enum: [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.RxDBSyncStatus.LOCAL, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.RxDBSyncStatus.UPLOADING, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.RxDBSyncStatus.SYNCED], maxLength: 16, type: 'string' } }, required: ['id', 'sopInstanceUID', 'seriesUid', 'studyUid', 'storeUid', 'syncStatus', 'instanceNumber'], title: 'Dicom instance schema', type: 'object', version: 2 }; const _schemaTyped = (0,rxdb__WEBPACK_IMPORTED_MODULE_0__.toTypedRxJsonSchema)(dicomSchemaLiteral); const dicomSchema = dicomSchemaLiteral; /***/ }, /***/ 31095 /*!***************************************************************************!*\ !*** ./libs/contracts/src/lib/ot-payload/annotation-payload-v1.schema.ts ***! \***************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ annotationPayloadV1Schema: () => (/* binding */ annotationPayloadV1Schema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _work_session_annotation_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../work-session/annotation.schema */ 45254); /* harmony import */ var _work_session_common_schema__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../work-session/common.schema */ 17990); /* harmony import */ var _work_session_render_settings_schema__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../work-session/render-settings.schema */ 94881); /* harmony import */ var _annotation_protocol_binding_schema__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./annotation-protocol-binding.schema */ 25727); /** * Window/level rendering parameters shared by all 2D volume modes (axial, sagittal, coronal - * there's no per-mode setting, one preset applies across all of them). Optional and additive: * files exported before this section existed simply lack it, and readers must treat that as * "nothing to apply" rather than an error - see annotation-payload.schema.ts for why this * doesn't warrant a version bump. */ const renderSettings2DSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ selectedWindowPresetName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), windowPresets: zod__WEBPACK_IMPORTED_MODULE_0__.array(_work_session_render_settings_schema__WEBPACK_IMPORTED_MODULE_4__.windowPresetSchema) }); /** * 3D volume ray-cast rendering parameters (ENDO/FLUOROSCOPIC/MIP/VASCULAR/XRAY presets). * Optional and additive, same rationale as renderSettings2D above. */ const renderSettings3DSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ selectedVolumePresetName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), volumeRenderPresets: zod__WEBPACK_IMPORTED_MODULE_0__.array(_work_session_render_settings_schema__WEBPACK_IMPORTED_MODULE_4__.volumeRenderPresetSchema) }); const taviProtocolFormValuesSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ artifacts: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['none', 'calcium-blooming', 'contrast-related-streaks', 'metal-related-streaks', 'high-noise-level', 'poor-contrast-opacification', 'banding-stitching'])).optional(), comments: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(4000).optional(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['good', 'fair', 'poor']).optional(), phaseUnit: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['percent', 'milliseconds', 'unlabelled']).optional(), phaseValue: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(64).optional(), proceed: zod__WEBPACK_IMPORTED_MODULE_0__.boolean().optional(), proceedReason: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['n1', 'n2', 'n3', 'n4', 'n5']).optional(), variant: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['tricuspid', 'tricommissural-functional-bicuspid', 'bav-type-0', 'bav-type-1-rl', 'bav-type-1-ln', 'bav-type-1-rn', 'bav-type-2', 'unicuspid', 'tav-balloon-expandable', 'tav-self-expanding', 'sav-tissue', 'sav-metallic', 'undetermined']).optional(), volumeIdentifier: zod__WEBPACK_IMPORTED_MODULE_0__.string().min(1).max(256).optional() }); const protocolFormValuesSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ // Accepts any id this protocol has shipped under so previously exported OTs stay readable; // normalized to the canonical id below. protocolId: zod__WEBPACK_IMPORTED_MODULE_0__.string().refine(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.isTaviProtocolId), values: taviProtocolFormValuesSchema }).strict(); const annotationPayloadV1Schema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ annotationProtocolBindings: zod__WEBPACK_IMPORTED_MODULE_0__.array(_annotation_protocol_binding_schema__WEBPACK_IMPORTED_MODULE_5__.annotationProtocolBindingV1Schema), // Cast to Annotation[]: the Zod-inferred object types are structurally mutable whereas // the dtos union members are all Readonly<{...}>. Mutable is assignable to readonly at // runtime — the cast bridges the TypeScript-level gap only. annotations: zod__WEBPACK_IMPORTED_MODULE_0__.array(_work_session_annotation_schema__WEBPACK_IMPORTED_MODULE_2__.annotationSchema).transform(array => array), /** Maps annotationId → rendered spline path points (kept separate from control points). */ calculatedPaths: zod__WEBPACK_IMPORTED_MODULE_0__.record(zod__WEBPACK_IMPORTED_MODULE_0__.string(), zod__WEBPACK_IMPORTED_MODULE_0__.array(_work_session_common_schema__WEBPACK_IMPORTED_MODULE_3__.point3Schema)), // OT payloads only persist the TAVI form. Accept the previously exported // unscoped shape so persisted OTs remain importable, then normalize it. protocolFormValues: zod__WEBPACK_IMPORTED_MODULE_0__.union([protocolFormValuesSchema, taviProtocolFormValuesSchema]).transform(formValues => 'protocolId' in formValues ? { ...formValues, protocolId: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.canonicalProtocolId)(formValues.protocolId) } : { protocolId: _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.TAVI_PROTOCOL_ID, values: formValues }).optional(), renderSettings2D: renderSettings2DSchema.optional(), renderSettings3D: renderSettings3DSchema.optional(), sourceInstanceUIDs: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).optional(), sourceSeriesUID: zod__WEBPACK_IMPORTED_MODULE_0__.string().optional(), version: zod__WEBPACK_IMPORTED_MODULE_0__.literal(1) }); /***/ }, /***/ 36379 /*!************************************************************************!*\ !*** ./libs/contracts/src/lib/ot-payload/annotation-payload.schema.ts ***! \************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ OT_PAYLOAD_LATEST_VERSION: () => (/* binding */ OT_PAYLOAD_LATEST_VERSION), /* harmony export */ OT_PAYLOAD_SCHEMA_VERSION: () => (/* binding */ OT_PAYLOAD_SCHEMA_VERSION), /* harmony export */ annotationPayloadSchema: () => (/* binding */ annotationPayloadSchema), /* harmony export */ annotationPayloadV1Schema: () => (/* reexport safe */ _annotation_payload_v1_schema__WEBPACK_IMPORTED_MODULE_0__.annotationPayloadV1Schema) /* harmony export */ }); /* harmony import */ var _annotation_payload_v1_schema__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./annotation-payload-v1.schema */ 31095); /** * Discriminated union over all payload versions, keyed on `version`. * Add new versions here as they are introduced: * * export const annotationPayloadSchema = z.discriminatedUnion('version', [ * annotationPayloadV1Schema, * annotationPayloadV2Schema, * ]); */ const annotationPayloadSchema = _annotation_payload_v1_schema__WEBPACK_IMPORTED_MODULE_0__.annotationPayloadV1Schema; const OT_PAYLOAD_LATEST_VERSION = 1; const OT_PAYLOAD_SCHEMA_VERSION = '1.0.0'; /***/ }, /***/ 25727 /*!*********************************************************************************!*\ !*** ./libs/contracts/src/lib/ot-payload/annotation-protocol-binding.schema.ts ***! \*********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ annotationProtocolBindingV1Schema: () => (/* binding */ annotationProtocolBindingV1Schema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); const annotationProtocolBindingV1Schema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ annotationId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.string(), color: zod__WEBPACK_IMPORTED_MODULE_0__.string(), placeholderIndex: zod__WEBPACK_IMPORTED_MODULE_0__.number(), placeholderName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), protocolId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), protocolName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), protocolPlaceholderId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), /** JSON-serialized relationship object, or empty string when no relationship. */ role: zod__WEBPACK_IMPORTED_MODULE_0__.string() }); /***/ }, /***/ 16520 /*!****************************************************!*\ !*** ./libs/contracts/src/lib/ot-payload/index.ts ***! \****************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ OT_PAYLOAD_LATEST_VERSION: () => (/* reexport safe */ _annotation_payload_schema__WEBPACK_IMPORTED_MODULE_0__.OT_PAYLOAD_LATEST_VERSION), /* harmony export */ OT_PAYLOAD_SCHEMA_VERSION: () => (/* reexport safe */ _annotation_payload_schema__WEBPACK_IMPORTED_MODULE_0__.OT_PAYLOAD_SCHEMA_VERSION), /* harmony export */ annotationPayloadSchema: () => (/* reexport safe */ _annotation_payload_schema__WEBPACK_IMPORTED_MODULE_0__.annotationPayloadSchema), /* harmony export */ annotationPayloadV1Schema: () => (/* reexport safe */ _annotation_payload_schema__WEBPACK_IMPORTED_MODULE_0__.annotationPayloadV1Schema), /* harmony export */ annotationProtocolBindingV1Schema: () => (/* reexport safe */ _annotation_protocol_binding_schema__WEBPACK_IMPORTED_MODULE_2__.annotationProtocolBindingV1Schema) /* harmony export */ }); /* harmony import */ var _annotation_payload_schema__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./annotation-payload.schema */ 36379); /* harmony import */ var _annotation_payload_v1_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./annotation-payload-v1.schema */ 31095); /* harmony import */ var _annotation_protocol_binding_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./annotation-protocol-binding.schema */ 25727); /***/ }, /***/ 10706 /*!******************************************************!*\ !*** ./libs/contracts/src/lib/utils/schema-utils.ts ***! \******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ fixTuplesForDraft7: () => (/* binding */ fixTuplesForDraft7) /* harmony export */ }); /* eslint-disable sonarjs/cyclomatic-complexity */ /* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable @typescript-eslint/no-explicit-any */ /** * Iterate through a JSON Schema instance and convert any Tuple types to a format * that RxDB can parse. We originally tried calling `z.toJSONSchema()` as `draft-7` but * this also caused problems. */ function fixTuplesForDraft7(schema) { if (typeof schema !== 'object' || schema === null) return schema; const result = { ...schema }; // Convert prefixItems -> Draft 7 tuple form if (result['prefixItems']) { const tupleLength = result['prefixItems'].length; result['items'] = result['prefixItems'].map(s => fixTuplesForDraft7(s)); delete result['prefixItems']; result['minItems'] = result['minItems'] ?? tupleLength; result['maxItems'] = result['maxItems'] ?? tupleLength; result['additionalItems'] = false; } // Recurse into items — must handle both array and object forms if (Array.isArray(result['items'])) { result['items'] = result['items'].map(item => fixTuplesForDraft7(item)); } else if (result['items'] !== null && typeof result['items'] === 'object') { result['items'] = fixTuplesForDraft7(result['items']); } else { // Nothing needed } // Recurse into all composition keywords for (const key of ['oneOf', 'anyOf', 'allOf']) { if (Array.isArray(result[key])) { result[key] = result[key].map(item => fixTuplesForDraft7(item)); } } // Recurse into single-schema keywords for (const key of ['additionalProperties', 'additionalItems', 'contains', 'not', 'if', 'then', 'else']) { if (result[key] !== null && typeof result[key] === 'object') { result[key] = fixTuplesForDraft7(result[key]); } } // Recurse into map-of-schemas keywords for (const key of ['properties', 'patternProperties', '$defs', 'definitions']) { if (result[key] !== null && typeof result[key] === 'object') { result[key] = Object.fromEntries(Object.entries(result[key]).map(([k, v]) => [k, fixTuplesForDraft7(v)])); } } return result; } /***/ }, /***/ 45254 /*!******************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/annotation.schema.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ annotationSchema: () => (/* binding */ annotationSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _common_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./common.schema */ 17990); const base = zod__WEBPACK_IMPORTED_MODULE_0__.object({ color: zod__WEBPACK_IMPORTED_MODULE_0__.string(), displayOrder: zod__WEBPACK_IMPORTED_MODULE_0__.number().nonnegative().default(0), hidden: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), id: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string(), placeholderId: zod__WEBPACK_IMPORTED_MODULE_0__.string().optional() }); const point = base.extend({ position: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.string()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['attached-point', 'curvature-point']) }).optional(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT) }); const angle = base.extend({ points: zod__WEBPACK_IMPORTED_MODULE_0__.array(_common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema).length(3), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.string(), zod__WEBPACK_IMPORTED_MODULE_0__.string()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['angle-between-spline-axes', 'angle-between-splines']) }).optional(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE) }); const cylinder = base.extend({ diameter: zod__WEBPACK_IMPORTED_MODULE_0__.number(), height: zod__WEBPACK_IMPORTED_MODULE_0__.number(), locked: zod__WEBPACK_IMPORTED_MODULE_0__.boolean().default(false), orientation: _common_schema__WEBPACK_IMPORTED_MODULE_2__.quatSchema, position: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, sides: zod__WEBPACK_IMPORTED_MODULE_0__.number(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CYLINDER) }); const distance = base.extend({ points: zod__WEBPACK_IMPORTED_MODULE_0__.array(_common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema).length(2), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.union([zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.string()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['attached-distance', 'center-distance', 'chord', 'closest-distance-to-one-annotation', 'projected-distance']) }), zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.string(), zod__WEBPACK_IMPORTED_MODULE_0__.string()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['angle-between-spline-axes', 'angle-between-splines', 'closest-distance-between-annotations', 'distance-between', 'projected-distance-from-point']) })]).optional(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE) }); const hollowCylinder = base.extend({ height: zod__WEBPACK_IMPORTED_MODULE_0__.number(), innerDiameter: zod__WEBPACK_IMPORTED_MODULE_0__.number(), locked: zod__WEBPACK_IMPORTED_MODULE_0__.boolean().default(false), orientation: _common_schema__WEBPACK_IMPORTED_MODULE_2__.quatSchema, outerDiameter: zod__WEBPACK_IMPORTED_MODULE_0__.number(), position: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, sides: zod__WEBPACK_IMPORTED_MODULE_0__.number(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.HOLLOW_CYLINDER) }); const openSpline = base.extend({ points: zod__WEBPACK_IMPORTED_MODULE_0__.array(_common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema).min(2), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.string()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal('attached-spline') }).optional(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.OPEN_SPLINE) }); const closedSpline = base.extend({ points: zod__WEBPACK_IMPORTED_MODULE_0__.array(_common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema).min(2), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE) }); const stl = base.extend({ autoAlignAxis: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), axisOfSymmetryRotation: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.number()), centerOfRotation: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema.optional(), fileName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), geometryId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), locked: zod__WEBPACK_IMPORTED_MODULE_0__.boolean().default(false), orientation: _common_schema__WEBPACK_IMPORTED_MODULE_2__.quatSchema, position: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, type: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.STL) }); const annotationSchema = zod__WEBPACK_IMPORTED_MODULE_0__.discriminatedUnion('type', [angle, closedSpline, cylinder, distance, hollowCylinder, openSpline, point, stl]); /***/ }, /***/ 44876 /*!**************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/chamber.chema.ts ***! \**************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ chamberSchema: () => (/* binding */ chamberSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 99756); /* harmony import */ var _common_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./common.schema */ 17990); const chamberSchema = zod__WEBPACK_IMPORTED_MODULE_0__["default"].object({ ax: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number(), cameraOrientation: zod__WEBPACK_IMPORTED_MODULE_0__["default"].object({ ax: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number(), cc: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number(), rl: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number() }), color: zod__WEBPACK_IMPORTED_MODULE_0__["default"].string(), crosshairRotation: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number().optional(), hidden: zod__WEBPACK_IMPORTED_MODULE_0__["default"].boolean(), id: zod__WEBPACK_IMPORTED_MODULE_0__["default"].uuid(), intersection: _common_schema__WEBPACK_IMPORTED_MODULE_1__.point3Schema.optional(), isocenter: _common_schema__WEBPACK_IMPORTED_MODULE_1__.point3Schema.optional(), isPosterior: zod__WEBPACK_IMPORTED_MODULE_0__["default"].boolean(), name: zod__WEBPACK_IMPORTED_MODULE_0__["default"].string() }); /***/ }, /***/ 17990 /*!**************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/common.schema.ts ***! \**************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ matrixSchema: () => (/* binding */ matrixSchema), /* harmony export */ point2Schema: () => (/* binding */ point2Schema), /* harmony export */ point3Schema: () => (/* binding */ point3Schema), /* harmony export */ quatSchema: () => (/* binding */ quatSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); const point2Schema = zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number()]).readonly(); const point3Schema = zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number()]).readonly(); const matrixSchema = zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.number()).length(9); const quatSchema = zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number(), zod__WEBPACK_IMPORTED_MODULE_0__.number()]).readonly(); /***/ }, /***/ 32656 /*!******************************************************!*\ !*** ./libs/contracts/src/lib/work-session/index.ts ***! \******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WORK_SESSION_LATEST_SCHEMA: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.WORK_SESSION_LATEST_SCHEMA), /* harmony export */ annotationSchema: () => (/* reexport safe */ _annotation_schema__WEBPACK_IMPORTED_MODULE_0__.annotationSchema), /* harmony export */ matrixSchema: () => (/* reexport safe */ _common_schema__WEBPACK_IMPORTED_MODULE_1__.matrixSchema), /* harmony export */ placeholderSchema: () => (/* reexport safe */ _placeholder_schema__WEBPACK_IMPORTED_MODULE_2__.placeholderSchema), /* harmony export */ point2Schema: () => (/* reexport safe */ _common_schema__WEBPACK_IMPORTED_MODULE_1__.point2Schema), /* harmony export */ point3Schema: () => (/* reexport safe */ _common_schema__WEBPACK_IMPORTED_MODULE_1__.point3Schema), /* harmony export */ protocolDefinitionSchema: () => (/* reexport safe */ _protocol_schema__WEBPACK_IMPORTED_MODULE_3__.protocolDefinitionSchema), /* harmony export */ protocolInstanceSchema: () => (/* reexport safe */ _protocol_schema__WEBPACK_IMPORTED_MODULE_3__.protocolInstanceSchema), /* harmony export */ protocolVolumeDataSchema: () => (/* reexport safe */ _protocol_schema__WEBPACK_IMPORTED_MODULE_3__.protocolVolumeDataSchema), /* harmony export */ quatSchema: () => (/* reexport safe */ _common_schema__WEBPACK_IMPORTED_MODULE_1__.quatSchema), /* harmony export */ rxDbAttachmentSchema: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.rxDbAttachmentSchema), /* harmony export */ workSessionJsonSchema: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.workSessionJsonSchema), /* harmony export */ workSessionRxdbJsonSchema: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.workSessionRxdbJsonSchema), /* harmony export */ workSessionSchema: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.workSessionSchema), /* harmony export */ workSessionSchemaWithAttachments: () => (/* reexport safe */ _work_session_schema__WEBPACK_IMPORTED_MODULE_4__.workSessionSchemaWithAttachments) /* harmony export */ }); /* harmony import */ var _annotation_schema__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./annotation.schema */ 45254); /* harmony import */ var _common_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./common.schema */ 17990); /* harmony import */ var _placeholder_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./placeholder.schema */ 1516); /* harmony import */ var _protocol_schema__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./protocol.schema */ 16653); /* harmony import */ var _work_session_schema__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./work-session.schema */ 87969); /***/ }, /***/ 1516 /*!*******************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/placeholder.schema.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ placeholderSchema: () => (/* binding */ placeholderSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const placeholderBase = zod__WEBPACK_IMPORTED_MODULE_0__.object({ color: zod__WEBPACK_IMPORTED_MODULE_0__.string(), id: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string() }); const point = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).length(1), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['attached-point', 'curvature-point']) }).optional() }); const angle = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).length(2), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['angle-between-spline-axes', 'angle-between-splines']) }).optional() }); const cylinder = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CYLINDER) }); const distance = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.union([zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).length(1), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['attached-distance', 'center-distance', 'chord', 'closest-distance-to-one-annotation', 'projected-distance']) }), zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).length(2), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['angle-between-spline-axes', 'angle-between-splines', 'closest-distance-between-annotations', 'distance-between', 'projected-distance-from-point']) })]).optional() }); const hollowCylinder = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.HOLLOW_CYLINDER) }); const openSpline = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.OPEN_SPLINE), relationship: zod__WEBPACK_IMPORTED_MODULE_0__.object({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()).length(1), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal('attached-spline') }).optional() }); const closedSpline = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE) }); const stl = placeholderBase.extend({ annotationType: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.STL) }); const placeholderSchema = zod__WEBPACK_IMPORTED_MODULE_0__.discriminatedUnion('annotationType', [angle, closedSpline, cylinder, distance, hollowCylinder, openSpline, point, stl]); /***/ }, /***/ 16653 /*!****************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/protocol.schema.ts ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ protocolDefinitionSchema: () => (/* binding */ protocolDefinitionSchema), /* harmony export */ protocolInstanceSchema: () => (/* binding */ protocolInstanceSchema), /* harmony export */ protocolVolumeDataSchema: () => (/* binding */ protocolVolumeDataSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _placeholder_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./placeholder.schema */ 1516); const formFieldValueSchema = zod__WEBPACK_IMPORTED_MODULE_0__.union([zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), zod__WEBPACK_IMPORTED_MODULE_0__.string(), zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.boolean()), zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string())]).readonly(); const validationRuleSchema = zod__WEBPACK_IMPORTED_MODULE_0__.looseObject({ type: zod__WEBPACK_IMPORTED_MODULE_0__.string() }).readonly(); const protocolFormFieldSchema = zod__WEBPACK_IMPORTED_MODULE_0__.looseObject({ representation: zod__WEBPACK_IMPORTED_MODULE_0__.string(), valueType: zod__WEBPACK_IMPORTED_MODULE_0__.string() }).readonly(); const protocolFormDefinitionSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ canProceedRule: validationRuleSchema.optional(), fields: zod__WEBPACK_IMPORTED_MODULE_0__.array(protocolFormFieldSchema), name: zod__WEBPACK_IMPORTED_MODULE_0__.string(), required: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), validation: zod__WEBPACK_IMPORTED_MODULE_0__.record(zod__WEBPACK_IMPORTED_MODULE_0__.string(), validationRuleSchema) }).readonly(); const protocolDefinitionSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ form: protocolFormDefinitionSchema.optional(), id: zod__WEBPACK_IMPORTED_MODULE_0__.string(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string(), placeholders: zod__WEBPACK_IMPORTED_MODULE_0__.array(_placeholder_schema__WEBPACK_IMPORTED_MODULE_1__.placeholderSchema).readonly() }).readonly(); const protocolInstanceSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ formValues: zod__WEBPACK_IMPORTED_MODULE_0__.record(zod__WEBPACK_IMPORTED_MODULE_0__.string(), formFieldValueSchema).readonly().optional(), placeholderMappings: zod__WEBPACK_IMPORTED_MODULE_0__.record(zod__WEBPACK_IMPORTED_MODULE_0__.string(), zod__WEBPACK_IMPORTED_MODULE_0__.string()).readonly(), protocolId: zod__WEBPACK_IMPORTED_MODULE_0__.string() }).readonly(); // Used at volume-level const protocolVolumeDataSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ activeProtocolId: zod__WEBPACK_IMPORTED_MODULE_0__.string().optional(), instances: zod__WEBPACK_IMPORTED_MODULE_0__.array(protocolInstanceSchema) }); /***/ }, /***/ 94881 /*!***********************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/render-settings.schema.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ renderSettingsStoreStateSchema: () => (/* binding */ renderSettingsStoreStateSchema), /* harmony export */ volumeRenderPresetSchema: () => (/* binding */ volumeRenderPresetSchema), /* harmony export */ windowPresetSchema: () => (/* binding */ windowPresetSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const endoPreset = zod__WEBPACK_IMPORTED_MODULE_0__.object({ airTissueThreshold: zod__WEBPACK_IMPORTED_MODULE_0__.number(), ambient: zod__WEBPACK_IMPORTED_MODULE_0__.number(), bloodCalciumThreshold: zod__WEBPACK_IMPORTED_MODULE_0__.number(), diffuse: zod__WEBPACK_IMPORTED_MODULE_0__.number(), distalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__.number(), label: zod__WEBPACK_IMPORTED_MODULE_0__.string(), opacityTransitionWidth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), proximalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), rgbTransitionWidth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedPreset: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.ENDO), specular: zod__WEBPACK_IMPORTED_MODULE_0__.number(), specularPower: zod__WEBPACK_IMPORTED_MODULE_0__.number(), tissueBloodThreshold: zod__WEBPACK_IMPORTED_MODULE_0__.number() }); const fluoroscopicPreset = zod__WEBPACK_IMPORTED_MODULE_0__.object({ brightness: zod__WEBPACK_IMPORTED_MODULE_0__.number(), distalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__.number(), label: zod__WEBPACK_IMPORTED_MODULE_0__.string(), proximalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedPreset: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.FLUOROSCOPIC), threshold: zod__WEBPACK_IMPORTED_MODULE_0__.number() }); // NOTE: no `.default()` on any field here — RxDB's SchemaCheck (SC7) rejects default // values on anything nested under an array item / discriminated-union branch; they're // only legal at the schema's top level. Defaults for these fields are supplied // explicitly instead, by VOLUME_RENDERING_PRESETS (new sessions) and the work-session // migrations (backfilling old ones) — see v13, v20, and v26. const mipPreset = zod__WEBPACK_IMPORTED_MODULE_0__.object({ // brightness = window level, threshold = window width - see MipSettings. brightness: zod__WEBPACK_IMPORTED_MODULE_0__.number(), distalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__.number(), label: zod__WEBPACK_IMPORTED_MODULE_0__.string(), proximalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedPreset: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.MIP), threshold: zod__WEBPACK_IMPORTED_MODULE_0__.number() }); const vascularPreset = zod__WEBPACK_IMPORTED_MODULE_0__.object({ ambient: zod__WEBPACK_IMPORTED_MODULE_0__.number(), bloodCalciumThreshold: zod__WEBPACK_IMPORTED_MODULE_0__.number(), clusterSize: zod__WEBPACK_IMPORTED_MODULE_0__.number(), diffuse: zod__WEBPACK_IMPORTED_MODULE_0__.number(), distalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), erosionRadius: zod__WEBPACK_IMPORTED_MODULE_0__.number(), gridStep: zod__WEBPACK_IMPORTED_MODULE_0__.number(), hasAcceptedSegmentation: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__.number(), label: zod__WEBPACK_IMPORTED_MODULE_0__.string(), maxHU: zod__WEBPACK_IMPORTED_MODULE_0__.number(), minHU: zod__WEBPACK_IMPORTED_MODULE_0__.number(), opacityTransitionWidth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), outlierOpacity: zod__WEBPACK_IMPORTED_MODULE_0__.number(), proximalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedPreset: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.VASCULAR), specular: zod__WEBPACK_IMPORTED_MODULE_0__.number(), specularPower: zod__WEBPACK_IMPORTED_MODULE_0__.number(), tissueBloodThreshold: zod__WEBPACK_IMPORTED_MODULE_0__.number(), vascularSegmentationState: zod__WEBPACK_IMPORTED_MODULE_0__.nativeEnum(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VascularSegmentationState), vascularThresholdsAutoTuned: zod__WEBPACK_IMPORTED_MODULE_0__.boolean() }); const xrayPreset = zod__WEBPACK_IMPORTED_MODULE_0__.object({ brightness: zod__WEBPACK_IMPORTED_MODULE_0__.number(), distalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), imageQuality: zod__WEBPACK_IMPORTED_MODULE_0__.number(), label: zod__WEBPACK_IMPORTED_MODULE_0__.string(), proximalDepth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedPreset: zod__WEBPACK_IMPORTED_MODULE_0__.literal(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.XRAY), threshold: zod__WEBPACK_IMPORTED_MODULE_0__.number() }); const legacyVolumeRenderingPresetNameMap = { ENDO: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.ENDO, Endovascular: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.ENDO, FLUOROSCOPIC: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.FLUOROSCOPIC, Fluoroscopic: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.FLUOROSCOPIC, 'X-Ray': _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.XRAY, XRAY: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption.XRAY }; const normalizeVolumeRenderingPresetName = value => { if (typeof value !== 'string') return; return Object.values(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.VolumeRenderingOption).find(option => option === value) ?? legacyVolumeRenderingPresetNameMap[value]; }; const normalizeVolumeRenderPreset = value => { if (!value || typeof value !== 'object' || Array.isArray(value)) return value; const preset = value; const normalizedPreset = normalizeVolumeRenderingPresetName(preset['selectedPreset']) ?? normalizeVolumeRenderingPresetName(preset['value']); if (!normalizedPreset) return value; return { ...preset, selectedPreset: normalizedPreset }; }; const volumeRenderPresetSchema = zod__WEBPACK_IMPORTED_MODULE_0__.preprocess(normalizeVolumeRenderPreset, zod__WEBPACK_IMPORTED_MODULE_0__.discriminatedUnion('selectedPreset', [endoPreset, fluoroscopicPreset, mipPreset, vascularPreset, xrayPreset])); const windowPresetSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ level: zod__WEBPACK_IMPORTED_MODULE_0__.number(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string(), width: zod__WEBPACK_IMPORTED_MODULE_0__.number() }); const renderSettingsStoreStateSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ sCurveGraphFontSize: zod__WEBPACK_IMPORTED_MODULE_0__.number(), sCurveLineWidth: zod__WEBPACK_IMPORTED_MODULE_0__.number(), selectedVolumePresetName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), selectedWindowPresetName: zod__WEBPACK_IMPORTED_MODULE_0__.string(), volumeRenderPresets: zod__WEBPACK_IMPORTED_MODULE_0__.array(volumeRenderPresetSchema), windowPresets: zod__WEBPACK_IMPORTED_MODULE_0__.array(windowPresetSchema) }); /***/ }, /***/ 35354 /*!***************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/s-curve.schema.ts ***! \***************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ sCurveRelativeMeasurementSchema: () => (/* binding */ sCurveRelativeMeasurementSchema), /* harmony export */ sCurveSchema: () => (/* binding */ sCurveSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _common_schema__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./common.schema */ 17990); const sCurveBase = zod__WEBPACK_IMPORTED_MODULE_0__.object({ color: zod__WEBPACK_IMPORTED_MODULE_0__.string(), hidden: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), id: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string() }); const controlPointSCurve = sCurveBase.extend({ controlPoints: zod__WEBPACK_IMPORTED_MODULE_0__.array(_common_schema__WEBPACK_IMPORTED_MODULE_1__.point2Schema), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal('control-point') }); // Spline-derived s-curves are re-synced live from the annotation store on load, so // only a lightweight stub (preserving id/hidden/ordering) is persisted in // their place - never the full embedded spline. const sCurveStub = zod__WEBPACK_IMPORTED_MODULE_0__.object({ hidden: zod__WEBPACK_IMPORTED_MODULE_0__.boolean(), id: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), type: zod__WEBPACK_IMPORTED_MODULE_0__.literal('stub') }); const sCurveSchema = zod__WEBPACK_IMPORTED_MODULE_0__.discriminatedUnion('type', [controlPointSCurve, sCurveStub]); // The angle/intersection VALUE is never persisted - always derived live from the // current shape of the source curves. Only the measurement's own identity/display // fields (which curves it relates, name/color/visibility) are persisted here. const sCurveRelativeMeasurementSchema = sCurveBase.extend({ sourceIds: zod__WEBPACK_IMPORTED_MODULE_0__.tuple([zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), zod__WEBPACK_IMPORTED_MODULE_0__.uuid()]).readonly(), type: zod__WEBPACK_IMPORTED_MODULE_0__["enum"](['angle', 'intersection']) }); /***/ }, /***/ 92603 /*!**********************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/viewport-store.schema.ts ***! \**********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ viewportStoreStateSchema: () => (/* binding */ viewportStoreStateSchema) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 99756); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _common_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./common.schema */ 17990); const viewportStoreStateSchema = zod__WEBPACK_IMPORTED_MODULE_0__["default"].object({ ax: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number(), cameraDistance: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number(), intersection: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, isocenter: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema, isPosterior: zod__WEBPACK_IMPORTED_MODULE_0__["default"].boolean(), matrix: _common_schema__WEBPACK_IMPORTED_MODULE_2__.matrixSchema, showCrosshairs: zod__WEBPACK_IMPORTED_MODULE_0__["default"].boolean(), // NOTE: Using `z.enum(ViewportAxisState)` as the key breaks the RxDB schema viewportAxisMapping: zod__WEBPACK_IMPORTED_MODULE_0__["default"].record(zod__WEBPACK_IMPORTED_MODULE_0__["default"].string(), zod__WEBPACK_IMPORTED_MODULE_0__["default"]["enum"](_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.ViewportAxis)), volumeCenter: _common_schema__WEBPACK_IMPORTED_MODULE_2__.point3Schema.optional(), zoom: zod__WEBPACK_IMPORTED_MODULE_0__["default"].number() }); /***/ }, /***/ 87969 /*!********************************************************************!*\ !*** ./libs/contracts/src/lib/work-session/work-session.schema.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WORK_SESSION_LATEST_SCHEMA: () => (/* binding */ WORK_SESSION_LATEST_SCHEMA), /* harmony export */ rxDbAttachmentSchema: () => (/* binding */ rxDbAttachmentSchema), /* harmony export */ workSessionJsonSchema: () => (/* binding */ workSessionJsonSchema), /* harmony export */ workSessionRxdbJsonSchema: () => (/* binding */ workSessionRxdbJsonSchema), /* harmony export */ workSessionSchema: () => (/* binding */ workSessionSchema), /* harmony export */ workSessionSchemaWithAttachments: () => (/* binding */ workSessionSchemaWithAttachments) /* harmony export */ }); /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! zod */ 14713); /* harmony import */ var _utils_schema_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/schema-utils */ 10706); /* harmony import */ var _annotation_schema__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./annotation.schema */ 45254); /* harmony import */ var _chamber_chema__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./chamber.chema */ 44876); /* harmony import */ var _protocol_schema__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./protocol.schema */ 16653); /* harmony import */ var _render_settings_schema__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./render-settings.schema */ 94881); /* harmony import */ var _s_curve_schema__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./s-curve.schema */ 35354); /* harmony import */ var _viewport_store_schema__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./viewport-store.schema */ 92603); const phaseSelectionSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ activePhaseId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), availablePhaseIds: zod__WEBPACK_IMPORTED_MODULE_0__.array(zod__WEBPACK_IMPORTED_MODULE_0__.string()) }); const volumeBundleSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ annotations: zod__WEBPACK_IMPORTED_MODULE_0__.array(_annotation_schema__WEBPACK_IMPORTED_MODULE_2__.annotationSchema), chambers: zod__WEBPACK_IMPORTED_MODULE_0__.array(_chamber_chema__WEBPACK_IMPORTED_MODULE_3__.chamberSchema), phaseId: zod__WEBPACK_IMPORTED_MODULE_0__.string(), protocolData: _protocol_schema__WEBPACK_IMPORTED_MODULE_4__.protocolVolumeDataSchema, renderSettings: _render_settings_schema__WEBPACK_IMPORTED_MODULE_5__.renderSettingsStoreStateSchema, sCurveRelativeMeasurements: zod__WEBPACK_IMPORTED_MODULE_0__.array(_s_curve_schema__WEBPACK_IMPORTED_MODULE_6__.sCurveRelativeMeasurementSchema), sCurves: zod__WEBPACK_IMPORTED_MODULE_0__.array(_s_curve_schema__WEBPACK_IMPORTED_MODULE_6__.sCurveSchema), viewportCamera: _viewport_store_schema__WEBPACK_IMPORTED_MODULE_7__.viewportStoreStateSchema }); const workSessionSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ annotationSize: zod__WEBPACK_IMPORTED_MODULE_0__.number().default(2), createdAt: zod__WEBPACK_IMPORTED_MODULE_0__.iso.datetime(), createdByUid: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), name: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(64), phaseSelection: phaseSelectionSchema.optional(), protocolDefinitions: zod__WEBPACK_IMPORTED_MODULE_0__.array(_protocol_schema__WEBPACK_IMPORTED_MODULE_4__.protocolDefinitionSchema), renderSettings: _render_settings_schema__WEBPACK_IMPORTED_MODULE_5__.renderSettingsStoreStateSchema, schemaVersion: zod__WEBPACK_IMPORTED_MODULE_0__.number(), seriesUid: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(128), storeUid: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(128), studyUid: zod__WEBPACK_IMPORTED_MODULE_0__.string().max(128), uid: zod__WEBPACK_IMPORTED_MODULE_0__.uuid().length(36), updatedAt: zod__WEBPACK_IMPORTED_MODULE_0__.iso.datetime().min(0).max(2000), updatedByUid: zod__WEBPACK_IMPORTED_MODULE_0__.uuid(), version: zod__WEBPACK_IMPORTED_MODULE_0__.number().min(0).max(Number.MAX_VALUE).default(0), viewportCamera: _viewport_store_schema__WEBPACK_IMPORTED_MODULE_7__.viewportStoreStateSchema, volumes: zod__WEBPACK_IMPORTED_MODULE_0__.array(volumeBundleSchema).default([]) }).refine(data => data.volumes.every(({ annotations }) => new Set(annotations.map(({ displayOrder }) => displayOrder)).size === annotations.length), { message: 'Unique displayOrder required', path: ['volumes'] }); // eslint-disable-next-line unicorn/prevent-abbreviations const rxDbAttachmentSchema = zod__WEBPACK_IMPORTED_MODULE_0__.object({ data: zod__WEBPACK_IMPORTED_MODULE_0__.string().optional(), digest: zod__WEBPACK_IMPORTED_MODULE_0__.string(), length: zod__WEBPACK_IMPORTED_MODULE_0__.number().int(), type: zod__WEBPACK_IMPORTED_MODULE_0__.string() }); const workSessionSchemaWithAttachments = workSessionSchema.extend({ _attachments: zod__WEBPACK_IMPORTED_MODULE_0__.record(zod__WEBPACK_IMPORTED_MODULE_0__.string(), rxDbAttachmentSchema).default({}) }); // NOTE: We use `draft-7` otherwise `z.tuple()` is unsupported by RxDB const workSessionJsonSchema = (0,_utils_schema_utils__WEBPACK_IMPORTED_MODULE_1__.fixTuplesForDraft7)(zod__WEBPACK_IMPORTED_MODULE_0__.toJSONSchema(workSessionSchema)); const properties = workSessionJsonSchema['properties']; const WORK_SESSION_LATEST_SCHEMA = 27; const workSessionRxdbJsonSchema = { attachments: { encrypted: false }, indexes: ['studyUid', 'seriesUid', 'version', 'updatedAt'], primaryKey: 'uid', properties: { ...properties, version: { ...properties.version, multipleOf: 1 } }, required: workSessionJsonSchema['required'], title: 'Work Session Schema', type: 'object', version: WORK_SESSION_LATEST_SCHEMA }; /***/ }, /***/ 42541 /*!***************************************!*\ !*** ./libs/data-access/src/index.ts ***! \***************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AppInitService: () => (/* reexport safe */ _lib_services_app_init_service__WEBPACK_IMPORTED_MODULE_2__.AppInitService), /* harmony export */ AuthInterceptor: () => (/* reexport safe */ _lib_services_auth_interceptor_service__WEBPACK_IMPORTED_MODULE_1__.AuthInterceptor), /* harmony export */ AuthService: () => (/* reexport safe */ _lib_services_auth_service__WEBPACK_IMPORTED_MODULE_0__.AuthService), /* harmony export */ ClientStudySearchProvider: () => (/* reexport safe */ _lib_services_dicom_study_search_provider__WEBPACK_IMPORTED_MODULE_4__.ClientStudySearchProvider), /* harmony export */ DevelopmentOptionsService: () => (/* reexport safe */ _lib_services_dev_options_service__WEBPACK_IMPORTED_MODULE_18__.DevelopmentOptionsService), /* harmony export */ DicomApiService: () => (/* reexport safe */ _lib_services_dicom_dicom_api_service__WEBPACK_IMPORTED_MODULE_3__.DicomApiService), /* harmony export */ DicomDatabaseService: () => (/* reexport safe */ _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__.DicomDatabaseService), /* harmony export */ DicomImportService: () => (/* reexport safe */ _lib_services_dicom_dicom_import_service__WEBPACK_IMPORTED_MODULE_15__.DicomImportService), /* harmony export */ DicomStoreListService: () => (/* reexport safe */ _lib_services_dicom_dicom_store_list_service__WEBPACK_IMPORTED_MODULE_5__.DicomStoreListService), /* harmony export */ PreferencesService: () => (/* reexport safe */ _lib_services_preferences_preferences_service__WEBPACK_IMPORTED_MODULE_16__.PreferencesService), /* harmony export */ RXDB_CONFIG: () => (/* reexport safe */ _lib_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_12__.RXDB_CONFIG), /* harmony export */ RXDB_DEFAULT_STORAGE: () => (/* reexport safe */ _lib_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_12__.RXDB_DEFAULT_STORAGE), /* harmony export */ RecentWorkSessionsService: () => (/* reexport safe */ _lib_services_recent_work_sessions_service__WEBPACK_IMPORTED_MODULE_17__.RecentWorkSessionsService), /* harmony export */ RenderingEngineService: () => (/* reexport safe */ _lib_services_dicom_rendering_engine_service__WEBPACK_IMPORTED_MODULE_6__.RenderingEngineService), /* harmony export */ RxdbManager: () => (/* reexport safe */ _lib_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_12__.RxdbManager), /* harmony export */ StudySearchProvider: () => (/* reexport safe */ _lib_services_dicom_study_search_provider__WEBPACK_IMPORTED_MODULE_4__.StudySearchProvider), /* harmony export */ VolumeLoaderService: () => (/* reexport safe */ _lib_services_dicom_volume_loader_service__WEBPACK_IMPORTED_MODULE_7__.VolumeLoaderService), /* harmony export */ WorkSessionApiService: () => (/* reexport safe */ _lib_services_work_session_work_session_api_service__WEBPACK_IMPORTED_MODULE_8__.WorkSessionApiService), /* harmony export */ WorkSessionDatabaseService: () => (/* reexport safe */ _lib_db_work_session_work_session_database_service__WEBPACK_IMPORTED_MODULE_14__.WorkSessionDatabaseService), /* harmony export */ WorkSessionNavigationService: () => (/* reexport safe */ _lib_services_work_session_work_session_navigation_service__WEBPACK_IMPORTED_MODULE_9__.WorkSessionNavigationService), /* harmony export */ approvalToReviewStatus: () => (/* reexport safe */ _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__.approvalToReviewStatus), /* harmony export */ authGuard: () => (/* reexport safe */ _lib_guards_auth_guard__WEBPACK_IMPORTED_MODULE_10__.authGuard), /* harmony export */ batchFilesForUpload: () => (/* reexport safe */ _lib_services_dicom_dicom_api_service__WEBPACK_IMPORTED_MODULE_3__.batchFilesForUpload), /* harmony export */ isSeriesFullyCached: () => (/* reexport safe */ _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__.isSeriesFullyCached), /* harmony export */ parseImageId: () => (/* reexport safe */ _lib_services_dicom_volume_loader_service__WEBPACK_IMPORTED_MODULE_7__.parseImageId), /* harmony export */ resolveSeriesReviewStatus: () => (/* reexport safe */ _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__.resolveSeriesReviewStatus), /* harmony export */ reviewStatusRank: () => (/* reexport safe */ _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__.reviewStatusRank), /* harmony export */ separateSeriesPhases: () => (/* reexport safe */ _lib_services_dicom_volume_loader_service__WEBPACK_IMPORTED_MODULE_7__.separateSeriesPhases), /* harmony export */ sessionCleanupGuard: () => (/* reexport safe */ _lib_guards_session_cleanup_guard__WEBPACK_IMPORTED_MODULE_11__.sessionCleanupGuard) /* harmony export */ }); /* harmony import */ var _lib_services_auth_service__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/services/auth.service */ 52807); /* harmony import */ var _lib_services_auth_interceptor_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/services/auth-interceptor.service */ 98765); /* harmony import */ var _lib_services_app_init_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/services/app-init.service */ 44769); /* harmony import */ var _lib_services_dicom_dicom_api_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/services/dicom/dicom-api.service */ 96269); /* harmony import */ var _lib_services_dicom_study_search_provider__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/services/dicom/study-search.provider */ 75826); /* harmony import */ var _lib_services_dicom_dicom_store_list_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/services/dicom/dicom-store-list.service */ 55643); /* harmony import */ var _lib_services_dicom_rendering_engine_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/services/dicom/rendering-engine.service */ 68453); /* harmony import */ var _lib_services_dicom_volume_loader_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./lib/services/dicom/volume-loader.service */ 79950); /* harmony import */ var _lib_services_work_session_work_session_api_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/services/work-session/work-session-api.service */ 29039); /* harmony import */ var _lib_services_work_session_work_session_navigation_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./lib/services/work-session/work-session-navigation.service */ 60923); /* harmony import */ var _lib_guards_auth_guard__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./lib/guards/auth.guard */ 89967); /* harmony import */ var _lib_guards_session_cleanup_guard__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./lib/guards/session-cleanup.guard */ 5138); /* harmony import */ var _lib_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./lib/db/rxdb-manager.service */ 67189); /* harmony import */ var _lib_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./lib/db/dicom/dicom-database.service */ 30860); /* harmony import */ var _lib_db_work_session_work_session_database_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./lib/db/work-session/work-session-database.service */ 17818); /* harmony import */ var _lib_services_dicom_dicom_import_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./lib/services/dicom/dicom-import.service */ 67430); /* harmony import */ var _lib_services_preferences_preferences_service__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./lib/services/preferences/preferences.service */ 4508); /* harmony import */ var _lib_services_recent_work_sessions_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./lib/services/recent-work-sessions.service */ 23974); /* harmony import */ var _lib_services_dev_options_service__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./lib/services/dev-options.service */ 40911); /***/ }, /***/ 30860 /*!*********************************************************************!*\ !*** ./libs/data-access/src/lib/db/dicom/dicom-database.service.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DicomDatabaseService: () => (/* binding */ DicomDatabaseService), /* harmony export */ approvalToReviewStatus: () => (/* binding */ approvalToReviewStatus), /* harmony export */ isSeriesFullyCached: () => (/* binding */ isSeriesFullyCached), /* harmony export */ resolveSeriesReviewStatus: () => (/* binding */ resolveSeriesReviewStatus), /* harmony export */ reviewStatusRank: () => (/* reexport safe */ _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_16__.reviewStatusRank) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_awaitAsyncGenerator_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/awaitAsyncGenerator.js */ 60256); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_wrapAsyncGenerator_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/wrapAsyncGenerator.js */ 8014); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_platform_browser__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/platform-browser */ 20189); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 87675); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 90015); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @cornerstonejs/core */ 38277); /* harmony import */ var p_limit__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! p-limit */ 13551); /* harmony import */ var p_retry__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! p-retry */ 24214); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_types__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @tomoverse/types */ 25575); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _tomoverse_utils_promises__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/utils/promises */ 75379); /* harmony import */ var _rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../../rxdb-attachment-binary */ 94669); /* harmony import */ var _services_dicom_dicom_api_service__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../../services/dicom/dicom-api.service */ 96269); /* harmony import */ var _rxdb_manager_service__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../rxdb-manager.service */ 67189); function isSeriesFullyCached(progress) { return progress.totalCount > 0 && progress.cachedCount >= progress.totalCount; } const PIXEL_DATA_ATTACHMENT_NAME = 'pixelData'; function mergeReviewStatus(a, b) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_16__.reviewStatusRank)(b) > (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_16__.reviewStatusRank)(a) ? b : a; } function approvalToReviewStatus(approval) { switch (approval.trim()) { case 'APPROVED': { return 'approved'; } case 'REJECTED': { return 'rejected'; } case 'UNAPPROVED': { return 'unapproved'; } default: { return 'none'; } } } function readMetaTag(meta, tag) { return String(meta?.[tag]?.Value?.[0] ?? '').trim(); } /** Highest-precedence status across the instances: approved > rejected > unapproved. */ function resolveReviewStatusFromMetas(metas) { let status = 'none'; for (const meta of metas) { // Private mirror fallback in case the store dropped the non-indexed standard tag. const instanceStatus = approvalToReviewStatus(readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.ApprovalStatus) || readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.TvctReviewStatus)); if (instanceStatus === 'approved') return 'approved'; status = mergeReviewStatus(status, instanceStatus); } return status; } function resolveSeriesReviewStatus(instances) { return resolveReviewStatusFromMetas(instances.map(inst => inst.toJSON().metadata)); } const FETCH_CONCURRENCY = 15; // Deliberately much lower than FETCH_CONCURRENCY: peekStudyInstanceCount is a background // enrichment for a heading display, not a critical load path - firing one request per series // unbounded can flood the connection pool and delay unrelated concurrent requests (e.g. the // study-summary peek for just the first series) behind this purely informational sum. const PEEK_CONCURRENCY = 4; const FETCH_RETRIES = 1; const FETCH_MIN_RETRY_TIMEOUT = 500; // A local RxDB write should never legitimately take this long - see fetchOverNetworkAndCache. const SAVE_BINARY_TIMEOUT_MS = 15_000; const SAVE_BINARY_TIMEOUT_PREFIX = 'Timed out saving binary for instance'; /** * Angular's HttpErrorResponse extends HttpResponseBase, not the built-in Error, * so `instanceof Error` returns false. pRetry v7 normalises non-Error throws to a * generic TypeError, losing the .status property that shouldRetry needs to bail * on 404/400. Wrap the function so pRetry always receives a real Error. */ function asRetriable(function_) { return /*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { return yield function_(); } catch (error) { if (error instanceof Error) throw error; const normalizedError = new Error(error && typeof error === 'object' && 'message' in error ? String(error.message) : String(error)); if (error && typeof error === 'object' && 'status' in error) { normalizedError.status = error.status; } throw normalizedError; } }); } class DicomDatabaseService { rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_23__.RxdbManager); api = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_services_dicom_dicom_api_service__WEBPACK_IMPORTED_MODULE_22__.DicomApiService); sanitizer = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_platform_browser__WEBPACK_IMPORTED_MODULE_4__.DomSanitizer); prefetchProgressBySeriesUid = new Map(); // Cornerstone's own rendering/prefetch machinery can keep re-requesting an image it never // successfully loaded, indefinitely - without this, a single permanently-bad (400/404) // instance turns into an unbounded stream of repeat network requests (observed freezing the // tab from memory pressure on a large series). Scoped per store+instance, in-memory only, so a // page reload gives every instance a clean slate. permanentlyFailedInstances = new Set(); // A series' true instance total never changes once known (deleting the local cache doesn't // change what's on the server) - without this, re-opening the same study re-runs the same // network peek every time, purely to redisplay a number the app already learned. Keyed by // storeUid+seriesUid, in-memory only, so it naturally clears on refresh; clearPeekCache() // clears it on logout too, so the next account doesn't see a previous session's data. peekedSeriesInstanceCountCache = new Map(); // Bumped by clearPeekCache(). A peek already in flight when sign-out fires must not repopulate // the cache it just cleared once its RxDB read or network call resolves - peekSeriesInstanceCount // captures this before awaiting anything and only writes back if it's still current. peekedSeriesInstanceCountCacheGeneration = 0; // The background series-cache prefetch and Cornerstone's own on-demand per-image loading both // route through getBinary and, on a cold cache, race to fetch the SAME instance concurrently - // this dedupes those into a single in-flight request instead of hitting the network twice. inFlightFetches = new Map(); // VolumeLoaderService is provided per-route/per-component (the volume viewer and the imaging // library's series preview each get their own instance), so its own in-flight caching can't see // across instances. In practice that means previewing a series then opening it in the full // viewer starts two independent prefetchInstanceBinaries loops for the same series, each with // its own progress counter and its own pLimit(FETCH_CONCURRENCY) queue - doubling background // fetch load for no benefit. This service is the one thing both instances actually share // (providedIn: 'root'), so dedupe here instead. Scoped by series+store only, not by the // sopInstanceUIDs subset a scoped (phase-limited) caller might pass - a scoped caller piggy- // backing on an in-flight unscoped (whole-series) prefetch is correct; a caller whose specific // subset a differently-scoped in-flight prefetch doesn't fully cover is still safe, since // getBinary's own fetch-on-demand fallback covers whatever this skips. inFlightPrefetches = new Map(); // The single point every network fetch actually goes through, regardless of caller - the // background prefetch and Cornerstone's on-demand per-image loading (via getBinary) used to // each apply their own separate pLimit, which allowed up to ~20 real network requests in flight // at once; now all flows share a single FETCH_CONCURRENCY (15) limiter to cap the true total // and avoid congesting the connection pool (individual fetches were observed taking 6-7s // instead of well under 1s when the connection was saturated). networkFetchLimit = (0,p_limit__WEBPACK_IMPORTED_MODULE_13__["default"])(FETCH_CONCURRENCY); // Nothing else evicts a series' cached instances/attachments once the volume viewer moves on, // so a session that opens many series (e.g. a large scan) grows this store unboundedly, which // measurably slows down every later query against it. Evict by total cached attachment size // rather than by count - one large scan can dwarf several small ones - and base "least // recently used" on RxDB's own persisted last-write-time rather than in-memory session state, // so scans cached in a previous session (before the last page reload) get cleaned up too. static MAX_CACHED_INSTANCE_BYTES = 1024 * 1024 * 1024; // 1 GiB instanceKey(sopInstanceUID, storeUid) { return `${storeUid}:${sopInstanceUID}`; } /** * A concurrent write (e.g. an in-flight background prefetch still saving binaries into this * collection, or a second overlapping caller removing from it - a user's manual clear-cache * landing on top of markSeriesViewed's background eviction) can bump a document's revision * between reading it and removing it here. Plain `.remove()` has no retry of its own and * throws CONFLICT outright on any revision mismatch; a single manual retry against * `getLatest()` isn't enough either, since whatever raced us can keep winning more than once * (confirmed in practice: the retry's own remove() hit a second CONFLICT). * * `incrementalRemove()` routes through RxDB's own incremental write queue instead, which on a * CONFLICT re-fetches the document's actual current state and re-applies the deletion against * it, looping until it wins rather than giving up after a fixed number of attempts - so it * converges no matter how many times a concurrent writer beats us to it. */ removeDocumentWithRetry(document) { return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!document || document.deleted) return; yield document.incrementalRemove(); })(); } getSeriesForStudy(studyUid, storeUid) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this2.rxdbManager.getSeriesCollection(); const localSeries = yield collection.find({ selector: { storeUid, studyInstanceUID: studyUid }, sort: [{ seriesNumber: 'asc' }] }).exec(); if (localSeries.length > 0) { return localSeries.map(series => series.toJSON()); } const remoteSeries = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this2.api.getSeriesForStudy(studyUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); yield _this2.persistSeries(remoteSeries, studyUid, storeUid); return remoteSeries; })(); } streamSeriesForStudy(studyUid, storeUid) { return this.rxdbManager.dicomSeries$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(collection => collection.find({ selector: { storeUid, studyInstanceUID: studyUid }, sort: [{ seriesNumber: 'asc' }] }).$), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(documents => documents.map(({ toJSON }) => toJSON()))); } refreshSeriesForStudy(_x, _x2) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (studyUid, storeUid, shouldPersist = () => true) { const remoteSeries = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this3.api.getSeriesForStudy(studyUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); yield _this3.persistSeries(remoteSeries, studyUid, storeUid, shouldPersist); return remoteSeries; }).apply(this, arguments); } /** * Hard resync used by an explicit "reload" - clears the local series cache so server-side * deletions are picked up, then repopulates it from the store. Fetches BEFORE clearing: if * the network call fails (e.g. while a large scan elsewhere is saturating the connection), * the local cache is left untouched instead of wiped with nothing to replace it - clearing * first turned a transient network failure into a permanently empty study that no amount of * re-triggering "reload" could recover from, since every retry re-cleared before re-fetching. */ resyncSeriesForStudy(studyUid, storeUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const remoteSeries = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this4.api.getSeriesForStudy(studyUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); yield _this4.clearSeriesForStudy(studyUid, storeUid); yield _this4.persistSeries(remoteSeries, studyUid, storeUid); return remoteSeries; })(); } streamSeriesInstances(seriesUid, storeUid) { return this.rxdbManager.dicomInstances$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(col => col.find({ selector: { seriesUid, storeUid } }).$)); } streamSeriesCacheProgress(seriesUid, storeUid) { // Scoped prefetches can complete before the rest of a multiphase series. // Derive progress from persisted attachments so the denominator is stable. return this.streamSeriesInstances(seriesUid, storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(documents => this.getSeriesProgressFromDocuments(documents))); } streamSeriesCacheProgressBySeries(seriesUids, storeUid) { return this.rxdbManager.dicomInstances$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(col => col.find({ selector: { seriesUid: { $in: seriesUids }, storeUid } }).$), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(documents => this.groupProgressBySeries(documents, seriesUids))); } groupProgressBySeries(documents, seriesUids) { const bySeries = new Map(); for (const document_ of documents) { const bucket = bySeries.get(document_.seriesUid); if (bucket) bucket.push(document_);else bySeries.set(document_.seriesUid, [document_]); } return Object.fromEntries(seriesUids.map(seriesUid => [seriesUid, this.getSeriesProgressFromDocuments(bySeries.get(seriesUid) ?? [])])); } clearSeriesForStudy(studyUid, storeUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const seriesCollection = yield _this5.rxdbManager.getSeriesCollection(); const instancesCollection = yield _this5.rxdbManager.getInstancesCollection(); const documents = yield seriesCollection.find({ selector: { storeUid, studyInstanceUID: studyUid } }).exec(); const otSeriesUids = documents.filter(s => String(s.modality ?? '').trim().toUpperCase() === 'OT').map(s => s.seriesInstanceUID).filter(Boolean); if (otSeriesUids.length > 0) { const otInstances = yield instancesCollection.find({ selector: { seriesUid: { $in: otSeriesUids }, storeUid } }).exec(); for (const document_ of otInstances) { yield _this5.removeDocumentWithRetry(document_); } } for (const document_ of documents) { yield _this5.removeDocumentWithRetry(document_); } })(); } deleteLocalSeries(seriesUid, storeUid) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instancesCollection = yield _this6.rxdbManager.getInstancesCollection(); const seriesCollection = yield _this6.rxdbManager.getSeriesCollection(); const localInstances = yield instancesCollection.find({ selector: { seriesUid, storeUid, syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.LOCAL } }).exec(); if (localInstances.length > 0) { for (const document_ of localInstances) { yield _this6.removeDocumentWithRetry(document_); } } const remaining = yield instancesCollection.find({ selector: { seriesUid, storeUid } }).exec(); if (remaining.length === 0) { const seriesDocuments = yield seriesCollection.find({ selector: { seriesInstanceUID: seriesUid, storeUid } }).exec(); for (const document_ of seriesDocuments) { yield _this6.removeDocumentWithRetry(document_); } } })(); } hasLocalDicomImports() { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instancesCollection = yield _this7.rxdbManager.getInstancesCollection(); const found = yield instancesCollection.findOne({ selector: { syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.LOCAL } }).exec(); return found !== null; })(); } clearLocalImports(excludeSeriesUid) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instancesCollection = yield _this8.rxdbManager.getInstancesCollection(); const seriesCollection = yield _this8.rxdbManager.getSeriesCollection(); const instanceSelector = excludeSeriesUid ? { seriesUid: { $ne: excludeSeriesUid }, syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.LOCAL } : { syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.LOCAL }; const localInstances = yield instancesCollection.find({ selector: instanceSelector }).exec(); if (localInstances.length === 0) return; const affectedSeries = new Map(localInstances.map(document_ => [`${document_.storeUid}|${document_.seriesUid}`, { seriesUid: document_.seriesUid, storeUid: document_.storeUid }])); for (const document_ of localInstances) { yield _this8.removeDocumentWithRetry(document_); } for (const { seriesUid, storeUid } of affectedSeries.values()) { if (excludeSeriesUid && seriesUid === excludeSeriesUid) continue; const remaining = yield instancesCollection.find({ selector: { seriesUid, storeUid } }).exec(); if (remaining.length > 0) continue; const seriesDocuments = yield seriesCollection.find({ selector: { seriesInstanceUID: seriesUid, storeUid } }).exec(); for (const document_ of seriesDocuments) { yield _this8.removeDocumentWithRetry(document_); } } })(); } getStudyUidsWithOtSeries() { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this9.rxdbManager.getSeriesCollection(); const otSeries = yield collection.find({ selector: { modality: 'OT' } }).exec(); return new Set(otSeries.map(s => s.studyInstanceUID).filter(Boolean)); })(); } /** * Returns the review status for each given study, merged from its OT series * with approved > rejected > unapproved precedence. */ getStudyOtReviewStatuses(studyUids, storeUid) { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // One request budget across every study and series in the batch - see PEEK_CONCURRENCY. const limit = (0,p_limit__WEBPACK_IMPORTED_MODULE_13__["default"])(PEEK_CONCURRENCY); const result = new Map(); yield Promise.all(studyUids.map(/*#__PURE__*/function () { var _ref2 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (studyUid) { result.set(studyUid, yield _this0.resolveStudyReviewStatus(studyUid, storeUid, limit)); }); return function (_x3) { return _ref2.apply(this, arguments); }; }())); return result; })(); } /** * The store's series list is the authority on which OT series a study holds; * the local series cache only covers studies whose details were opened before, * so it only answers when the store is unreachable. */ listOtSeriesUids(studyUid, storeUid, limit) { var _this1 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const remoteSeries = yield limit(() => _this1.api.getSeriesForStudy(studyUid, storeUid)); return remoteSeries.filter(series => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.normalizeModality)(series.modality) === 'OT').map(series => series.seriesInstanceUID).filter(Boolean); } catch { const collection = yield _this1.rxdbManager.getSeriesCollection(); const localSeries = yield collection.find({ selector: { modality: 'OT', storeUid, studyInstanceUID: studyUid } }).exec(); return localSeries.map(series => series.seriesInstanceUID).filter(Boolean); } })(); } resolveStudyReviewStatus(studyUid, storeUid, limit) { var _this10 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const seriesUids = yield _this10.listOtSeriesUids(studyUid, storeUid, limit); if (seriesUids.length === 0) return 'none'; const instancesCollection = yield _this10.rxdbManager.getInstancesCollection(); const seriesStatuses = yield Promise.all(seriesUids.map(/*#__PURE__*/function () { var _ref3 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (seriesUid) { const localInstances = yield instancesCollection.find({ selector: { seriesUid, storeUid } }).exec(); return _this10.resolveSeriesReviewStatusFromStore(studyUid, seriesUid, storeUid, localInstances, limit); }); return function (_x4) { return _ref3.apply(this, arguments); }; }())); let status = 'none'; for (const seriesStatus of seriesStatuses) { status = mergeReviewStatus(status, seriesStatus); } return status; })(); } /** * The store is the source of truth: the local cache can hold a partial or * since-deleted subset of a series, so it only answers when the store is * unreachable. */ resolveSeriesReviewStatusFromStore(studyUid, seriesUid, storeUid, localInstances, limit) { var _this11 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const instances = yield limit(() => _this11.api.getInstancesForSeries(studyUid, seriesUid, storeUid)); return resolveReviewStatusFromMetas(instances.map(inst => inst.rawMetadata)); } catch { return resolveSeriesReviewStatus(localInstances); } })(); } getStudyUidForSeries(seriesUid) { var _this12 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this12.rxdbManager.getInstancesCollection(); const [first] = yield collection.find({ limit: 1, selector: { seriesUid } }).exec(); return first?.studyUid; })(); } getSeriesCacheProgress(seriesUid, storeUid) { var _this13 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this13.rxdbManager.getInstancesCollection(); const documents = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); return _this13.getSeriesProgressFromDocuments(documents); })(); } ensureSeriesCached(studyUid, seriesUid, storeUid) { var _this14 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this14.rxdbManager.getInstancesCollection(); const localInstances = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); if (localInstances.length === 0) { const remoteInstances = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this14.api.getInstancesForSeries(studyUid, seriesUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); yield _this14.saveInstances(remoteInstances, studyUid, seriesUid, storeUid); } yield _this14.prefetchSeriesBinaries(studyUid, seriesUid, storeUid); })(); } /** * Force a fresh binary download for every instance in the series, discarding * whatever is currently cached. Use before export so the pipeline always reads * the authoritative file from the DICOM store rather than a potentially stale * attachment left over from a previous session. */ refreshSeriesBinaries(studyUid, seriesUid, storeUid) { var _this15 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const prefetchKey = `${storeUid}:${seriesUid}`; // If a prefetch for this series is already running, let it settle first so we don't // remove attachments while that run is still deciding what to fetch. const inFlightPrefetch = _this15.inFlightPrefetches.get(prefetchKey); if (inFlightPrefetch) { yield inFlightPrefetch.catch(() => { // best effort; refresh continues with a fresh generation below }); } const collection = yield _this15.rxdbManager.getInstancesCollection(); const documents = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); // Remove stale attachments so prefetchSeriesBinaries re-downloads all of them. yield Promise.all(documents.map(/*#__PURE__*/function () { var _ref4 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (document_) { _this15.permanentlyFailedInstances.delete(_this15.instanceKey(document_.sopInstanceUID, storeUid)); const attachment = document_.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (attachment) yield attachment.remove(); }); return function (_x5) { return _ref4.apply(this, arguments); }; }())); yield _this15.prefetchSeriesBinaries(studyUid, seriesUid, storeUid); })(); } deleteSeriesCache(seriesUid, storeUid, candidateDocuments) { var _this16 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const normalizedSeriesUid = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.normalizeSeriesUid)(seriesUid); if (!normalizedSeriesUid) return; const collection = yield _this16.rxdbManager.getInstancesCollection(); // Reuse documents the caller already loaded (markSeriesViewed's full-store scan) when // available, so an eviction pass over several series doesn't re-run that scan per series. let documents; if (candidateDocuments) { documents = candidateDocuments.filter(document => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.normalizeSeriesUid)(document.seriesUid) === normalizedSeriesUid); } else { // Can't match "equal after trimming" via an index lookup - a stored seriesUid can carry an // arbitrary amount of whitespace (DICOM's UI value representation is historically // space-padded), so there's no fixed set of candidate strings to search for ahead of time. // Reading every cached instance for the store and filtering in memory is the only way to // catch every padded variant, same as the resync/eviction paths already do. const documentsForStore = yield collection.find({ selector: { storeUid } }).exec(); documents = documentsForStore.filter(document => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.normalizeSeriesUid)(document.seriesUid) === normalizedSeriesUid); } _this16.clearClientSideCaches(documents, seriesUid, storeUid); for (const document of documents) { if (!document) continue; yield _this16.removeDocumentWithRetry(document); } const remaining = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); console.log(`✅ Deletion complete. Remaining documents: ${remaining.length}`); if (remaining.length > 0) { console.warn('⚠️ Some documents were not deleted:', remaining.map(d => d.sopInstanceUID)); } })(); } clearClientSideCaches(documents, seriesUid, storeUid) { // Clear DICOM Image Loader cache for each instance for (const document_ of documents) { const { sopInstanceUID } = document_; try { // Must match registration format from volume-loader.service.ts const imageId = `tomoverse-dcm:${storeUid}|${seriesUid}|${sopInstanceUID}`; try { _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_12__["default"].removeImageLoadObject(imageId); console.log(`✅ Removed from cache: ${imageId}`); } catch { console.debug(`Image not in cache: ${imageId}`); } const instanceKey = this.instanceKey(sopInstanceUID, storeUid); this.inFlightFetches.delete(instanceKey); this.permanentlyFailedInstances.delete(instanceKey); } catch (error) { console.warn('Failed to clear instance cache:', error); } } this.prefetchProgressBySeriesUid.delete(seriesUid); this.inFlightPrefetches.delete(`${storeUid}:${seriesUid}`); const volumes = _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_12__["default"].getVolumes(); for (const volume of volumes) { if (volume.volumeId.includes(seriesUid)) { try { _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_12__["default"].removeVolumeLoadObject(volume.volumeId); } catch (error) { console.warn('Failed to remove volume from cache:', error); } } } for (const document_ of documents) { const cacheKey = `${document_.storeUid}:${document_.seriesUid}`; this.peekedSeriesInstanceCountCache.delete(cacheKey); } } /** * Call once a series' volume has actually loaded - not speculatively before a load succeeds. * Keeps total cached instance-attachment size under MAX_CACHED_INSTANCE_BYTES, evicting the * least-recently-touched other series first. The series just viewed is never evicted here, * even if it alone exceeds the budget. */ markSeriesViewed(seriesUid, storeUid) { var _this17 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this17.rxdbManager.getInstancesCollection(); const documents = yield collection.find().exec(); const bySeries = new Map(); for (const document_ of documents) { const attachment = document_.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (!attachment) continue; const json = document_.toJSON(true); const key = `${json.storeUid}|${json.seriesUid}`; const entry = bySeries.get(key) ?? { bytes: 0, lastTouched: 0, seriesUid: json.seriesUid, storeUid: json.storeUid }; entry.bytes += attachment.length; entry.lastTouched = Math.max(entry.lastTouched, json._meta.lwt); bySeries.set(key, entry); } let totalBytes = 0; for (const entry of bySeries.values()) totalBytes += entry.bytes; const evictionCandidates = [...bySeries.values()].filter(entry => !(entry.seriesUid === seriesUid && entry.storeUid === storeUid)).toSorted((a, b) => a.lastTouched - b.lastTouched); for (const candidate of evictionCandidates) { if (totalBytes <= DicomDatabaseService.MAX_CACHED_INSTANCE_BYTES) break; yield _this17.deleteSeriesCache(candidate.seriesUid, candidate.storeUid, documents); totalBytes -= candidate.bytes; } })(); } getSeriesInstancesMetadata(studyUid, seriesUid, storeUid) { var _this18 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this18.rxdbManager.getInstancesCollection(); const localDocuments = yield collection.find({ selector: { seriesUid, storeUid }, sort: [{ instanceNumber: 'asc' }] }).exec(); if (localDocuments.length > 0) return localDocuments; return _this18.refreshSeriesInstancesMetadata(studyUid, seriesUid, storeUid); })(); } /** * Re-fetches a series' instance metadata from the store and upserts it locally, * picking up instances added since the docs were first cached (e.g. a review * recorded by another account). Cached attachments survive the upsert. */ refreshSeriesInstancesMetadata(studyUid, seriesUid, storeUid) { var _this19 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const remoteInstances = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(asRetriable(() => _this19.api.getInstancesForSeries(studyUid, seriesUid, storeUid)), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES, shouldRetry: ({ error }) => !('status' in error && (error.status === 404 || error.status === 400)) }); return _this19.saveInstances(remoteInstances, studyUid, seriesUid, storeUid); })(); } streamSeriesMetadata(studyUid, seriesUid, storeUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_wrapAsyncGenerator_js__WEBPACK_IMPORTED_MODULE_2__["default"])(function* () { const localDicomDocuments = yield (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_awaitAsyncGenerator_js__WEBPACK_IMPORTED_MODULE_1__["default"])(_this.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid)); for (const document of localDicomDocuments) { yield document; } })(); } getSeriesCommonMetadata(studyUid, seriesUid, storeUid) { var _this20 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const [firstInstanceMetadata] = yield _this20.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid); if (!firstInstanceMetadata) return; return _this20.mapDocumentToInstance(firstInstanceMetadata); })(); } /** * Local-only variant of getSeriesCommonMetadata: never fetches remotely at all. That fetch * exists on the caching variant so an intentional open/download re-populates metadata on a * cold cache, but for incidental display purposes (e.g. a study-summary header reacting to * whichever series is currently first in the list) it's an extra request landing on the exact * series - and exact moment - a real open is most likely to also be writing to, adding * concurrent pressure on RxDB's local storage right when it's most contended. See * peekSeriesCommonMetadata for a variant that can still reach the network on a cold cache * without those side effects, when the caller actually needs the richer fields. */ getLocalSeriesCommonMetadata(seriesUid, storeUid) { var _this21 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this21.rxdbManager.getInstancesCollection(); const [localFirstInstance] = yield collection.find({ selector: { seriesUid, storeUid }, sort: [{ instanceNumber: 'asc' }] }).exec(); if (!localFirstInstance) return; return _this21.mapDocumentToInstance(localFirstInstance); })(); } /** * Same summary fields as getSeriesCommonMetadata (patient/study info for a heading, etc.), but * never persists anything locally: on a cold cache it reads the network response straight off * the wire (DicomApiService already returns each instance's raw DICOM-JSON as `rawMetadata`) * instead of routing it through saveInstances. Unlike the caching variant, this can't grow * local storage or resurrect a previously-evicted series' metadata rows just to populate a * display label. */ peekSeriesCommonMetadata(studyUid, seriesUid, storeUid) { var _this22 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const local = yield _this22.getLocalSeriesCommonMetadata(seriesUid, storeUid); if (local) return local; const remoteInstances = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(asRetriable(() => _this22.api.getInstancesForSeries(studyUid, seriesUid, storeUid)), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES, shouldRetry: ({ error }) => !('status' in error && (error.status === 404 || error.status === 400)) }); const [first] = remoteInstances; if (!first?.sopInstanceUID) return; return _this22.mapDocumentToInstance({ metadata: first.rawMetadata, seriesUid, sopInstanceUID: first.sopInstanceUID, studyUid }); })(); } /** * True instance total across every series in the study, without persisting anything locally. * Some stores' study-search response already carries a study-level count (see * StudySearchRow.numberOfInstances), which is far cheaper and should be preferred when * present - this exists for when it isn't (that field is vendor-dependent and can be absent). */ peekStudyInstanceCount(studyUid, storeUid) { var _this23 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const counts = yield _this23.peekSeriesInstanceCounts(studyUid, storeUid); return [...counts.values()].reduce((sum, count) => sum + count, 0); })(); } /** * Per-series instance totals for a study, keyed by seriesInstanceUID - the true count on the * store regardless of what's cached locally, for display purposes (e.g. a series table's * "Images" column) that shouldn't be limited to whatever happens to already be downloaded. * Same peek semantics as peekSeriesCommonMetadata (local-first, network fallback, never * persists), capped at PEEK_CONCURRENCY concurrent network requests. * * Series resolve in parallel (up to PEEK_CONCURRENCY at a time) and not necessarily in list * order - onSeriesCount, when given, fires as each one lands so a caller can render counts * incrementally instead of waiting for the slowest series to show any of them. */ peekSeriesInstanceCounts(studyUid, storeUid, onSeriesCount) { var _this24 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const series = yield _this24.peekSeriesForStudy(studyUid, storeUid); const limit = (0,p_limit__WEBPACK_IMPORTED_MODULE_13__["default"])(PEEK_CONCURRENCY); const entries = yield Promise.all(series.map(/*#__PURE__*/function () { var _ref5 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* ({ seriesInstanceUID }) { if (!seriesInstanceUID) return; const count = yield limit(() => _this24.peekSeriesInstanceCount(studyUid, seriesInstanceUID, storeUid)); onSeriesCount?.(seriesInstanceUID, count); return [seriesInstanceUID, count]; }); return function (_x6) { return _ref5.apply(this, arguments); }; }())); return new Map(entries.filter(entry => entry !== undefined)); })(); } /** * Same series list as getSeriesForStudy, but on a cache miss calls the API client directly * instead of getSeriesForStudy itself - that method persists a cold-cache fetch via * persistSeries, which would defeat peekStudyInstanceCount's whole point of never writing to * local storage just to compute a display count. */ peekSeriesForStudy(studyUid, storeUid) { var _this25 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this25.rxdbManager.getSeriesCollection(); const localSeries = yield collection.find({ selector: { storeUid, studyInstanceUID: studyUid }, sort: [{ seriesNumber: 'asc' }] }).exec(); if (localSeries.length > 0) return localSeries.map(series => series.toJSON()); return (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this25.api.getSeriesForStudy(studyUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); })(); } peekSeriesInstanceCount(studyUid, seriesUid, storeUid) { var _this26 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const cacheKey = `${storeUid}:${seriesUid}`; const cached = _this26.peekedSeriesInstanceCountCache.get(cacheKey); if (cached !== undefined) return cached; const generation = _this26.peekedSeriesInstanceCountCacheGeneration; const collection = yield _this26.rxdbManager.getInstancesCollection(); const localDocuments = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); if (localDocuments.length > 0) { if (generation === _this26.peekedSeriesInstanceCountCacheGeneration) { _this26.peekedSeriesInstanceCountCache.set(cacheKey, localDocuments.length); } return localDocuments.length; } const remoteInstances = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(asRetriable(() => _this26.api.getInstancesForSeries(studyUid, seriesUid, storeUid)), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES, shouldRetry: ({ error }) => !('status' in error && (error.status === 404 || error.status === 400)) }); // Sign-out (clearPeekCache) may have happened while the read/network call above was in // flight - don't let a stale peek from the previous session repopulate the cache it just // cleared. The caller still gets the correct, freshly-fetched count either way. if (generation === _this26.peekedSeriesInstanceCountCacheGeneration) { _this26.peekedSeriesInstanceCountCache.set(cacheKey, remoteInstances.length); } return remoteInstances.length; })(); } /** Clears the session-scoped peek cache above - called on logout so the next account signing * in on the same tab doesn't see a previous account's peeked counts. */ clearPeekCache() { this.peekedSeriesInstanceCountCache.clear(); this.peekedSeriesInstanceCountCacheGeneration++; } getInstance(sopUID, storeUid) { var _this27 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this27.rxdbManager.getInstancesCollection(); return yield collection.findOne((0,_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_15__.dicomInstanceId)(storeUid, sopUID)).exec(); })(); } saveInstances(instances, studyUid, seriesUid, storeUid) { var _this28 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this28.rxdbManager.getInstancesCollection(); const { success: savedInstances } = yield collection.bulkUpsert(instances.filter(instance => Boolean(instance.sopInstanceUID)).map(({ instanceNumber, rawMetadata: metadata, sopInstanceUID }) => ({ createdAt: Date.now(), id: (0,_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_15__.dicomInstanceId)(storeUid, sopInstanceUID), instanceNumber, metadata, seriesUid, sopInstanceUID, storeUid, studyUid, syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.SYNCED }))); return savedInstances.toSorted((a, b) => a.instanceNumber - b.instanceNumber); })(); } getSeriesInstanceFiles(seriesUid, storeUid) { var _this29 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this29.rxdbManager.getInstancesCollection(); const documents = yield collection.find({ selector: { seriesUid, storeUid } }).exec(); const files = []; for (const document_ of documents) { const attachment = document_.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (attachment) { files.push(yield attachment.getData().then(data => _this29.attachmentDataToArrayBuffer(data))); } } return files; })(); } /** Returns an instance's pixel data only if already cached locally - never fetches over the network. */ getCachedBinary(sopInstanceUID, storeUid) { var _this30 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const dicomDocument = yield _this30.getInstance(sopInstanceUID, storeUid); const attachment = dicomDocument?.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (!attachment) return undefined; try { return yield attachment.getData().then(data => _this30.attachmentDataToArrayBuffer(data)); } catch (error) { // See loadBinaryUncached - a concurrent deleteSeriesCache can remove this attachment's // underlying data between the stale reference above and this read. Not cached is // exactly the right answer at that point, not a thrown error. if (_this30.isConcurrentDeletionError(error)) return undefined; throw error; } })(); } getBinary(sopInstanceUID, storeUid) { var _this31 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const key = _this31.instanceKey(sopInstanceUID, storeUid); // Registered synchronously, before any await, so two calls made back-to-back can never // both slip past this check - whichever call happens first always wins the race, even if // the two calls' subsequent async work (e.g. an RxDB lookup) later resolves in either order. const existingFetch = _this31.inFlightFetches.get(key); if (existingFetch) return existingFetch; const fetchPromise = _this31.loadBinaryUncached(sopInstanceUID, storeUid, key); _this31.inFlightFetches.set(key, fetchPromise); return fetchPromise.finally(() => _this31.inFlightFetches.delete(key)); })(); } /** * `getAttachment` reads the attachment's metadata off the (possibly already stale) in-memory * document reference synchronously - it can report an attachment present a moment after a * concurrent deleteSeriesCache has removed that attachment's underlying data. The actual * read only happens on `getData()`, which is where that race surfaces as a raw * NotFoundError instead of the "not cached" case this is functionally equivalent to. */ isConcurrentDeletionError(error) { return error instanceof Error && error.name === 'NotFoundError'; } isQuotaExceededError(error) { return error instanceof DOMException && error.name === 'QuotaExceededError' || error instanceof Error && error.name === 'QuotaExceededError'; } loadBinaryUncached(sopInstanceUID, storeUid, key) { var _this32 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const dicomDocument = yield _this32.getInstance(sopInstanceUID, storeUid); if (!dicomDocument) throw new Error(`Dicom document ${sopInstanceUID} not found.`); const attachment = dicomDocument.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (attachment) { try { return yield attachment.getData().then(data => _this32.attachmentDataToArrayBuffer(data)); } catch (error) { // Fall through to the network path exactly as if there'd been no attachment at all. If // the document is genuinely gone, saveBinary's own already-deleted check (TVC-1182) // makes the resulting cache-write a safe no-op instead of resurrecting it. if (!_this32.isConcurrentDeletionError(error)) throw error; } } return _this32.fetchOverNetworkAndCache(sopInstanceUID, storeUid, dicomDocument.studyUid, dicomDocument.seriesUid, key); })(); } // Split out of getBinary so callers that already have studyUid/seriesUid in hand (like // prefetchInstanceBinaries, iterating documents it already fetched) skip a redundant per- // instance RxDB lookup - that lookup, multiplied over a large series, was adding real latency // to store/series navigation once prefetch started routing through this for deduping. fetchAndCacheBinary(sopInstanceUID, storeUid, studyUid, seriesUid) { const key = this.instanceKey(sopInstanceUID, storeUid); const existingFetch = this.inFlightFetches.get(key); if (existingFetch) return existingFetch; const fetchPromise = this.fetchOverNetworkAndCache(sopInstanceUID, storeUid, studyUid, seriesUid, key); this.inFlightFetches.set(key, fetchPromise); return fetchPromise.finally(() => this.inFlightFetches.delete(key)); } isSaveBinaryTimeoutError(error) { return error instanceof Error && error.message.includes(SAVE_BINARY_TIMEOUT_PREFIX); } // Never calls back into getBinary/fetchAndCacheBinary's own in-flight registration - both of // those already register themselves under `key` before calling this, so doing it again here // would just await their own already-registered promise (a deadlock). fetchOverNetworkAndCache(sopInstanceUID, storeUid, studyUid, seriesUid, key) { var _this33 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this33.permanentlyFailedInstances.has(key)) { throw new Error(`Dicom instance ${sopInstanceUID} previously failed permanently, not retrying`); } try { const buffer = yield _this33.networkFetchLimit(() => (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(asRetriable(() => _this33.api.getInstanceDicomFile(studyUid, seriesUid, sopInstanceUID, storeUid)), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES, shouldRetry: ({ error }) => !('status' in error && (error.status === 404 || error.status === 400)) })); yield _this33.cacheBinary(sopInstanceUID, buffer, storeUid, seriesUid); return buffer; } catch (error) { if (error && typeof error === 'object' && 'status' in error) { const status = error.status; if (status === 400 || status === 404) { _this33.permanentlyFailedInstances.add(key); } } throw error; } })(); } /** * Persists a freshly fetched binary, retrying transient write failures via pRetry. On an * IndexedDB QuotaExceededError (the retry can't help without freeing space) it instead evicts * the least-recently-touched other series once and retries the write; if there is nothing to * evict, eviction fails, or the retry still fails, it gives up on caching rather than failing * the whole fetch - the buffer was already downloaded, so image loading still succeeds. */ cacheBinary(sopInstanceUID, buffer, storeUid, seriesUid) { var _this34 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const writePromise = _this34.saveBinary(sopInstanceUID, buffer, storeUid); try { yield (0,_tomoverse_utils_promises__WEBPACK_IMPORTED_MODULE_20__.withTimeout)(writePromise, SAVE_BINARY_TIMEOUT_MS, `${SAVE_BINARY_TIMEOUT_PREFIX} ${sopInstanceUID} - the local write got stuck.`); } catch (error) { if (_this34.isSaveBinaryTimeoutError(error)) { // Prevent overlapping retries while the original write may still be in flight. yield writePromise.catch(() => { // swallow: original error is rethrown below }); } throw error; } }), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES, shouldRetry: ({ error }) => !_this34.isSaveBinaryTimeoutError(error) && !_this34.isQuotaExceededError(error) }); } catch (error) { if (!_this34.isQuotaExceededError(error)) throw error; try { const evicted = yield _this34.evictLeastRecentlyTouchedSeries(seriesUid, storeUid); if (!evicted) return; yield _this34.saveBinary(sopInstanceUID, buffer, storeUid); } catch { // Best-effort: reclamation or the retry failed, so leave the buffer uncached. } } })(); } /** * Evicts the least-recently-touched cached series other than the one identified by * (excludeSeriesUid, excludeStoreUid) - that series is never evicted by its own write path. * Returns false when there is no other cached series to reclaim. Reuses the same persisted * last-write-time ordering as markSeriesViewed so cross-session "least recently used" holds. */ evictLeastRecentlyTouchedSeries(excludeSeriesUid, excludeStoreUid) { var _this35 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this35.rxdbManager.getInstancesCollection(); const documents = yield collection.find().exec(); const bySeries = new Map(); for (const document_ of documents) { const attachment = document_.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (!attachment) continue; const json = document_.toJSON(true); const key = `${json.storeUid}|${json.seriesUid}`; const entry = bySeries.get(key); if (!entry || json._meta.lwt > entry.lastTouched) { bySeries.set(key, { lastTouched: json._meta.lwt, seriesUid: json.seriesUid, storeUid: json.storeUid }); } } const candidate = [...bySeries.values()].filter(entry => !(entry.seriesUid === excludeSeriesUid && entry.storeUid === excludeStoreUid)).toSorted((a, b) => a.lastTouched - b.lastTouched)[0]; if (!candidate) return false; yield _this35.deleteSeriesCache(candidate.seriesUid, candidate.storeUid); return true; })(); } prefetchSeriesBinaries(studyUid, seriesUid, storeUid) { var _this36 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this36.prefetchInstanceBinaries(studyUid, seriesUid, storeUid); })(); } // Omit sopInstanceUIDs for the whole series. prefetchInstanceBinaries(studyUid, seriesUid, storeUid, sopInstanceUIDs) { var _this37 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const key = `${storeUid}:${seriesUid}`; const existing = _this37.inFlightPrefetches.get(key); if (existing) return existing; const prefetchPromise = _this37.prefetchInstanceBinariesUncached(studyUid, seriesUid, storeUid, sopInstanceUIDs); _this37.inFlightPrefetches.set(key, prefetchPromise); return prefetchPromise.finally(() => _this37.inFlightPrefetches.delete(key)); })(); } prefetchInstanceBinariesUncached(studyUid, seriesUid, storeUid, sopInstanceUIDs) { var _this38 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const progressSubject = _this38.getPrefetchProgressSubject(seriesUid); try { const documents = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this38.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); const wanted = sopInstanceUIDs ? new Set(sopInstanceUIDs) : undefined; const scopedDocuments = documents.filter(document => !wanted || wanted.has(document.sopInstanceUID)); const totalCount = scopedDocuments.length; let cachedCount = scopedDocuments.filter(document => document.getAttachment(PIXEL_DATA_ATTACHMENT_NAME)).length; _this38.emitPrefetchProgress(progressSubject, { cachedCount, percent: _this38.progressPercent(cachedCount, totalCount), totalCount }); // No pLimit wrapper here - fetchAndCacheBinary's actual network call already queues on the // shared networkFetchLimit, which is what needs to stay a single global bound (see its // comment). A second, separately-sized limiter here would just be redundant bookkeeping. yield Promise.all(scopedDocuments.filter(document => !document.getAttachment(PIXEL_DATA_ATTACHMENT_NAME)).map(/*#__PURE__*/function () { var _ref7 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* ({ sopInstanceUID }) { const key = _this38.instanceKey(sopInstanceUID, storeUid); if (_this38.permanentlyFailedInstances.has(key)) return; try { // Shares fetchAndCacheBinary with getBinary rather than fetching independently - // Cornerstone's own on-demand per-image loading calls getBinary too, and on a // cold cache both this background prefetch and that on-demand load race to fetch // the same instance; the shared in-flight dedup collapses that into one request // instead of two concurrent ones hitting the store. studyUid/seriesUid are // already known here, so this skips getBinary's per-instance document lookup. yield _this38.fetchAndCacheBinary(sopInstanceUID, storeUid, studyUid, seriesUid); cachedCount += 1; _this38.emitPrefetchProgress(progressSubject, { cachedCount, percent: _this38.progressPercent(cachedCount, totalCount), totalCount }); } catch (error) { if (_this38.permanentlyFailedInstances.has(key)) return; throw error; } }); return function (_x7) { return _ref7.apply(this, arguments); }; }())); } finally { _this38.removePrefetchProgressSubject(seriesUid, progressSubject); } })(); } getSeriesImageUrls(studyUid, seriesUid, storeUid) { var _this39 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instances = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this39.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); const limit = (0,p_limit__WEBPACK_IMPORTED_MODULE_13__["default"])(FETCH_CONCURRENCY); return yield Promise.all(instances.map(instance => limit(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const blob = yield (0,p_retry__WEBPACK_IMPORTED_MODULE_14__["default"])(() => _this39.api.getInstanceImage(studyUid, seriesUid, instance.sopInstanceUID, storeUid), { minTimeout: FETCH_MIN_RETRY_TIMEOUT, retries: FETCH_RETRIES }); const objectUrl = URL.createObjectURL(blob); // eslint-disable-next-line sonarjs/no-angular-bypass-sanitization return _this39.sanitizer.bypassSecurityTrustUrl(objectUrl); })))); })(); } /** * A concurrent removeDocumentWithRetry (e.g. the user deleting this series' local cache while * this binary is still being fetched in the background) can delete the document between * getInstance's lookup and putAttachment's write, or between that write being queued and RxDB's * incrementalWriteQueue actually running it against the latest (now-deleted) revision - either * way putAttachment throws (surfaced to the user as "Document update conflict" - TVC-1182). * Deliberately not a retry-and-write-anyway like removeDocumentWithRetry's: the user's delete * is the one action here with explicit intent, so a cache write losing that race should be * abandoned instead of resurrecting data onto a document the user just removed. */ saveBinary(sopUID, buffer, storeUid) { var _this40 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const dicomDocument = yield _this40.getInstance(sopUID, storeUid); if (!dicomDocument || dicomDocument.deleted) return; try { yield dicomDocument.putAttachment({ data: (0,_rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_21__.toRxdbAttachmentBinary)(buffer), id: PIXEL_DATA_ATTACHMENT_NAME, type: 'application/dicom' }); } catch (error) { // getLatest() is a synchronous read from RxDB's in-memory doc cache, not a query - it // reflects the delete even if it landed after our stale dicomDocument reference was read. if (dicomDocument.getLatest().deleted) return; throw error; } })(); } attachmentDataToArrayBuffer(data) { return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (typeof data === 'object' && data !== null && 'arrayBuffer' in data && typeof data.arrayBuffer === 'function') { return yield data.arrayBuffer(); } if (data instanceof ArrayBuffer) { return data; } if (ArrayBuffer.isView(data)) { const copy = new Uint8Array(data.byteLength); copy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength)); return copy.buffer; } throw new TypeError('Unsupported attachment data type'); })(); } deleteBinary(sopUID, storeUid) { var _this41 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const dicomDocument = yield _this41.getInstance(sopUID, storeUid); const attachment = dicomDocument?.getAttachment(PIXEL_DATA_ATTACHMENT_NAME); if (attachment) yield attachment.remove(); })(); } getAllNotUploadedSeries(storeUid) { const seriesResults$ = this.rxdbManager.dicomSeries$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.filter)(collection => !collection.closed), (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(collection => collection.find({ selector: { storeUid } }).$), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.catchError)(() => rxjs__WEBPACK_IMPORTED_MODULE_7__.EMPTY)); const instanceResults$ = this.rxdbManager.dicomInstances$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.filter)(collection => !collection.closed), (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(collection => collection.find({ selector: { storeUid } }).$), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.catchError)(() => rxjs__WEBPACK_IMPORTED_MODULE_7__.EMPTY)); return (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.combineLatest)([seriesResults$, instanceResults$]).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(([seriesDocuments, instanceDocuments]) => { const statusesBySeriesUid = new Map(); for (const instanceDocument of instanceDocuments) { const statuses = statusesBySeriesUid.get(instanceDocument.seriesUid); if (statuses) { statuses.push({ syncStatus: instanceDocument.syncStatus }); } else { statusesBySeriesUid.set(instanceDocument.seriesUid, [{ syncStatus: instanceDocument.syncStatus }]); } } return seriesDocuments.map(seriesDocument => ({ ...seriesDocument.toJSON(), instances: statusesBySeriesUid.get(seriesDocument.seriesInstanceUID ?? '') ?? [] })).filter(series => series.instances.some(instance => instance.syncStatus !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.RxDBSyncStatus.SYNCED)); })); } getSeriesProgressFromDocuments(documents) { if (documents.length === 0) return { cachedCount: 0, percent: 0, totalCount: 0 }; const cachedCount = documents.filter(({ getAttachment }) => !!getAttachment(PIXEL_DATA_ATTACHMENT_NAME)).length; const totalCount = documents.length; return { cachedCount, percent: this.progressPercent(cachedCount, totalCount), totalCount }; } progressPercent(cachedCount, totalCount) { if (totalCount === 0) return 0; return Math.round(cachedCount / totalCount * 100); } prefetchProgressStream(seriesUid) { return this.getPrefetchProgressSubject(seriesUid).asObservable(); } emitPrefetchProgress(subject, progress) { console.debug(`[viewer-debug] prefetch progress: ${progress.cachedCount}/${progress.totalCount} (${progress.percent}%)`); subject.next(progress); } getPrefetchProgressSubject(seriesUid) { const existing = this.prefetchProgressBySeriesUid.get(seriesUid); if (existing) return existing; const subject = new rxjs__WEBPACK_IMPORTED_MODULE_5__.ReplaySubject(1); this.prefetchProgressBySeriesUid.set(seriesUid, subject); return subject; } removePrefetchProgressSubject(seriesUid, subject) { if (this.prefetchProgressBySeriesUid.get(seriesUid) === subject) { this.prefetchProgressBySeriesUid.delete(seriesUid); } } persistSeries(_x8, _x9, _x0) { var _this42 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (seriesList, studyUid, storeUid, shouldPersist = () => true) { const collection = yield _this42.rxdbManager.getSeriesCollection(); // Re-checked here, right before the write: the caller's condition (e.g. "is this // still the active request") may have flipped during the getSeriesCollection() await, // and a stale write here could re-add series a concurrent resync just deleted. if (!shouldPersist()) return; const payload = seriesList.filter(series => Boolean(series.seriesInstanceUID)).map(series => ({ ...series, createdAt: Date.now(), id: (0,_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_15__.dicomSeriesId)(storeUid, series.seriesInstanceUID), storeUid, studyInstanceUID: studyUid })); if (payload.length === 0) return; const { error } = yield collection.bulkUpsert(payload); if (error.length === 0) return; // bulkUpsert's error array isn't conflicts-only (status can be 409 conflict, 422 validation, // or 510 attachment) - only 409s are safe to self-heal here, so anything else is surfaced // instead of being retried against the same payload that just failed. const nonConflictErrors = error.filter(({ status }) => status !== 409); if (nonConflictErrors.length > 0) { throw new Error(`Failed to persist ${nonConflictErrors.length} of ${payload.length} series documents ` + `(status ${nonConflictErrors.map(({ status }) => status).join(', ')}).`); } // A concurrent write can bump a document's revision between building this payload and // committing it, silently dropping the conflicting rows. Resolve each one through // incrementalUpsert instead of a second bulk write: it re-reads the document's current state // and applies the change via RxDB's normal single-document write path, queued per document id // so it can't re-race. const conflictedIds = new Set(error.map(({ documentId }) => documentId)); const conflicted = payload.filter(document_ => conflictedIds.has(document_.id)); yield Promise.all(conflicted.map(document_ => collection.incrementalUpsert(document_))); }).apply(this, arguments); } getSeriesComputedMetadata(studyUid, seriesUid, storeUid) { var _this43 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const computedMetadata = yield _this43.computeInstanceMetadata(studyUid, seriesUid, storeUid); if (!computedMetadata) return; const { instanceCount, isCardiacGated, mappedInstanceDocuments, missingInstancesDetected, modalities: [...modalities], totalFileSizeMb } = computedMetadata; const firstPopulatedInstanceDocument = mappedInstanceDocuments[0]; if (!firstPopulatedInstanceDocument) return; const { columns, numberOfTemporalPositions, rows, sliceOrientation, sliceThickness, transferSyntaxUID } = firstPopulatedInstanceDocument; const matrixSize = rows && columns ? `${columns}×${rows}` : undefined; return { compression: transferSyntaxUID, fileSizeMb: totalFileSizeMb > 0 ? Number.parseFloat(totalFileSizeMb.toFixed(2)) : undefined, instanceCount, isCardiacGated, isVolumetric: (numberOfTemporalPositions ?? 1) > 1, mappedInstanceDocuments, matrixSize, missingInstancesDetected, modalities, numberOfTemporalPositions: numberOfTemporalPositions ?? 1, sliceOrientation, sliceThickness }; })(); } computeInstanceMetadata(studyUid, seriesUid, storeUid) { var _this44 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instances = yield _this44.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid); if (instances.length === 0) return; const mappedInstanceDocuments = []; const modalities = new Set(); const seenInstanceIds = new Set(); let totalFileSizeMb = 0; let isCardiacGated = false; for (const instance of instances) { const attachment = instance.getAttachment('pixelData'); if (attachment) totalFileSizeMb += attachment.length / (1024 * 1024); const mappedDocument = _this44.mapDocumentToInstance(instance); if (mappedDocument !== undefined) { isCardiacGated = isCardiacGated || mappedDocument.triggerTime !== undefined || mappedDocument.cardiacNumberOfImages !== undefined; const instanceId = mappedDocument.instanceNumber; if (instanceId !== undefined) { seenInstanceIds.add(instanceId); } if (mappedDocument.modality) { modalities.add(mappedDocument.modality); } mappedInstanceDocuments.push(mappedDocument); } } return { instanceCount: instances.length, isCardiacGated, mappedInstanceDocuments, missingInstancesDetected: seenInstanceIds.size < instances.length, modalities: [...modalities], totalFileSizeMb }; })(); } mapDocumentToInstance({ metadata, seriesUid, sopInstanceUID, studyUid }) { if (!metadata) return; const typedMetadata = metadata; return { accessionNumber: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.AccessionNumber), bitsAllocated: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.BitsAllocated), bitsStored: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.BitsStored), cardiacNumberOfImages: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.CardiacNumberOfImages), columns: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.Columns), highBit: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.HighBit), imageOrientationPatient: typedMetadata[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.ImageOrientationPatient]?.Value, imagePositionPatient: typedMetadata[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.ImagePositionPatient]?.Value, instanceNumber: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.InstanceNumber), institutionName: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.InstitutionName), modality: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.Modality), numberOfTemporalPositions: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.NumberOfTemporalPositions), patientBirthDate: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PatientBirthDate), patientID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PatientID), patientName: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PatientName)?.Alphabetic, patientSex: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PatientSex), photometricInterpretation: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PhotometricInterpretation), pixelRepresentation: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PixelRepresentation), pixelSpacing: typedMetadata[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.PixelSpacing]?.Value, rawMetadata: metadata, rescaleIntercept: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.RescaleIntercept), rescaleSlope: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.RescaleSlope), rows: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.Rows), samplesPerPixel: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SamplesPerPixel), seriesDate: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SeriesDate), seriesDescription: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SeriesDescription), seriesInstanceUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SeriesInstanceUID) ?? seriesUid, seriesNumber: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SeriesNumber), seriesTime: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SeriesTime), sliceLocation: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SliceLocation), sliceOrientation: 'Axial', // For now, it's always going to be Axial sliceThickness: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.SliceThickness), sopInstanceUID: sopInstanceUID, studyDate: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.StudyDate), studyDescription: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.StudyDescription), studyID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.StudyID), studyInstanceUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.StudyInstanceUID) ?? studyUid, studyTime: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.StudyTime), temporalPositionIdentifier: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.TemporalPositionIdentifier), transferSyntaxUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.TransferSyntaxUID), triggerTime: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.TriggerTime), windowCenter: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.WindowCenter), windowWidth: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_18__.getTagValue)(metadata, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_17__.DicomTagId.WindowWidth) }; } static ɵfac = function DicomDatabaseService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomDatabaseService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵdefineInjectable"]({ token: DicomDatabaseService, factory: DicomDatabaseService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 67189 /*!*************************************************************!*\ !*** ./libs/data-access/src/lib/db/rxdb-manager.service.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RXDB_CONFIG: () => (/* binding */ RXDB_CONFIG), /* harmony export */ RXDB_DEFAULT_STORAGE: () => (/* binding */ RXDB_DEFAULT_STORAGE), /* harmony export */ RxdbManager: () => (/* binding */ RxdbManager) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 87675); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 27588); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxdb */ 49813); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxdb */ 39352); /* harmony import */ var rxdb_premium_plugins_storage_indexeddb__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxdb-premium/plugins/storage-indexeddb */ 5775); /* harmony import */ var rxdb_plugins_attachments__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxdb/plugins/attachments */ 17850); /* harmony import */ var rxdb_plugins_cleanup__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! rxdb/plugins/cleanup */ 26240); /* harmony import */ var rxdb_plugins_dev_mode__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! rxdb/plugins/dev-mode */ 64585); /* harmony import */ var rxdb_plugins_leader_election__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! rxdb/plugins/leader-election */ 5019); /* harmony import */ var rxdb_plugins_local_documents__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! rxdb/plugins/local-documents */ 70712); /* harmony import */ var rxdb_plugins_migration_schema__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! rxdb/plugins/migration-schema */ 70400); /* harmony import */ var rxdb_plugins_update__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! rxdb/plugins/update */ 25757); /* harmony import */ var rxdb_plugins_validate_ajv__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! rxdb/plugins/validate-ajv */ 228); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); /* harmony import */ var _services_auth_service__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../services/auth.service */ 52807); /* harmony import */ var _work_session_work_session_collection__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./work-session/work-session.collection */ 32159); const RXDB_CONFIG = new _angular_core__WEBPACK_IMPORTED_MODULE_2__.InjectionToken('RXDB_CONFIG'); const RXDB_DEFAULT_STORAGE = new _angular_core__WEBPACK_IMPORTED_MODULE_2__.InjectionToken('RXDB_DEFAULT_STORAGE', { factory: () => rxdb_premium_plugins_storage_indexeddb__WEBPACK_IMPORTED_MODULE_10__.getRxStorageIndexedDB, providedIn: 'root' }); class RxdbManager { http = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpClient); authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_services_auth_service__WEBPACK_IMPORTED_MODULE_21__.AuthService); config = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(RXDB_CONFIG); defaultStorage = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(RXDB_DEFAULT_STORAGE); currentDb; dbInstance$ = new rxjs__WEBPACK_IMPORTED_MODULE_3__.ReplaySubject(1); workSessionReplicationState; // Set once by init() - remove() needs the same resolved name used when the database was // opened, not just this.config.name (which may be undefined and fall back to // defaultRxdbConfig.name). resolvedDatabaseName; init() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this.currentDb) return; const { apiUrl, devMode, name, options, storage } = { ..._tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_20__.defaultRxdbConfig, ..._this.config }; const resolvedDatabaseName = name ?? _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_20__.defaultRxdbConfig.name; _this.resolvedDatabaseName = resolvedDatabaseName; const resolvedStorage = storage ?? _this.defaultStorage(); _this.setupPlugins(devMode); const { database, workSessionReplicationState } = yield _this.openDatabase(resolvedDatabaseName, resolvedStorage, options, apiUrl); _this.currentDb = database; _this.workSessionReplicationState = workSessionReplicationState; _this.dbInstance$.next(database); })(); } openDatabase(name, storage, options, apiUrl) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const database = yield (0,rxdb__WEBPACK_IMPORTED_MODULE_9__.createRxDatabase)({ name, storage: (0,rxdb_plugins_validate_ajv__WEBPACK_IMPORTED_MODULE_18__.wrappedValidateAjvStorage)({ storage }), ...options }); try { yield database.addCollections({ dicomInstances: { // v0 to v1 added the store-scoped composite primary key. Pre-store docs // can't be re-keyed (no storeUid), so drop them. They re-fetch on demand. // v1 to v2 only added an index on syncStatus; no data shape change. // eslint-disable-next-line unicorn/no-null migrationStrategies: { 1: () => null, 2: instanceDocument => instanceDocument }, schema: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_19__.dicomSchema }, dicomSeries: { // eslint-disable-next-line unicorn/no-null migrationStrategies: { 1: () => null, 2: seriesDocument => seriesDocument }, schema: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_19__.dicomSeriesSchema } }); const workSessionReplicationState = yield (0,_work_session_work_session_collection__WEBPACK_IMPORTED_MODULE_22__.setupWorkSessionCollection)(database, _this2.http, _this2.authService, apiUrl); return { database, workSessionReplicationState }; } catch (error) { // Release any handles this partially-opened database holds before the failure propagates, // so a leaked handle from this failed attempt can't interfere with a later retry. yield database.close().catch(() => { // Best-effort - the original error above is what actually gets propagated. }); throw error; } })(); } // Bounded: awaitInSync retries forever while offline, and callers (sign-out) // must not hang on it. awaitWorkSessionsInSync() { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (timeoutMs = 5000) { const replicationState = _this3.workSessionReplicationState; if (!replicationState) return; yield Promise.race([replicationState.awaitInSync(), new Promise(resolve => setTimeout(resolve, timeoutMs))]); }).apply(this, arguments); } // Destructive cleanup: cancels replication, closes the database, and deletes the local RxDB // cache. Use when the signed-in user's session data must be discarded. remove() { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!_this4.currentDb) { const { name, options, storage } = { ..._tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_20__.defaultRxdbConfig, ..._this4.config }; yield (0,rxdb__WEBPACK_IMPORTED_MODULE_9__.removeRxDatabase)(_this4.resolvedDatabaseName ?? name ?? _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_20__.defaultRxdbConfig.name, (0,rxdb_plugins_validate_ajv__WEBPACK_IMPORTED_MODULE_18__.wrappedValidateAjvStorage)({ storage: storage ?? _this4.defaultStorage() }), options?.multiInstance, options?.password); return; } const database = _this4.currentDb; _this4.dbInstance$.next(undefined); yield _this4.workSessionReplicationState?.cancel(); _this4.workSessionReplicationState = undefined; yield database.remove(); _this4.currentDb = undefined; })(); } get activeDb$() { return this.dbInstance$.asObservable(); } // The closed-collection filter must sit AFTER shareReplay(1), not before it: shareReplay caches // whatever value last passed through, and that collection is always still open at the moment it // flows through map() - it only becomes closed *later*, in place, via a separate remove() call // that never pushes a new value through this pipe. A filter placed before shareReplay would // never actually catch that (it only ever sees the collection while it's still open); placed // after, it re-evaluates .closed on every delivery, including replayed ones, so a new // subscriber joining between a remove() and the next init() (e.g. a cold boot's initial "not // authenticated yet" tick before sign-in completes) doesn't get handed the stale, closed // collection RxDB's live-query engine can never recover a result from - it correctly waits for // the next (valid) emission instead. Before this, only a full page reload recovered from that. dicomSeries$ = this.activeDb$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.map)(database => database.dicomSeries), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.shareReplay)(1), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(collection => !collection.closed)); dicomInstances$ = this.activeDb$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.map)(database => database.dicomInstances), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.shareReplay)(1), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(collection => !collection.closed)); workSessions$ = this.activeDb$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.map)(database => database?.workSession), (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.shareReplay)(1)); getSeriesCollection() { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return yield (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.firstValueFrom)(_this5.dicomSeries$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(collection => !collection.closed))); })(); } getInstancesCollection() { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return yield (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.firstValueFrom)(_this6.dicomInstances$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(collection => !collection.closed))); })(); } getWorkSessionCollection() { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.firstValueFrom)(_this7.workSessions$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(collection => !!collection && !collection.closed))); })(); } setupPlugins(devMode) { (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_attachments__WEBPACK_IMPORTED_MODULE_11__.RxDBAttachmentsPlugin); (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_cleanup__WEBPACK_IMPORTED_MODULE_12__.RxDBCleanupPlugin); (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_leader_election__WEBPACK_IMPORTED_MODULE_14__.RxDBLeaderElectionPlugin); (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_local_documents__WEBPACK_IMPORTED_MODULE_15__.RxDBLocalDocumentsPlugin); (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_migration_schema__WEBPACK_IMPORTED_MODULE_16__.RxDBMigrationSchemaPlugin); (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_update__WEBPACK_IMPORTED_MODULE_17__.RxDBUpdatePlugin); if (devMode) (0,rxdb__WEBPACK_IMPORTED_MODULE_8__.addRxPlugin)(rxdb_plugins_dev_mode__WEBPACK_IMPORTED_MODULE_13__.RxDBDevModePlugin); } static ɵfac = function RxdbManager_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RxdbManager)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: RxdbManager, factory: RxdbManager.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 86515 /*!**********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/index.ts ***! \**********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MIGRATION_STRATEGIES: () => (/* binding */ MIGRATION_STRATEGIES), /* harmony export */ applyMigrations: () => (/* binding */ applyMigrations) /* harmony export */ }); /* harmony import */ var _v1__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./v1 */ 93066); /* harmony import */ var _v2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./v2 */ 69583); /* harmony import */ var _v3__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./v3 */ 30560); /* harmony import */ var _v4__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./v4 */ 73133); /* harmony import */ var _v5__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./v5 */ 438); /* harmony import */ var _v6__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./v6 */ 35531); /* harmony import */ var _v7__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./v7 */ 12204); /* harmony import */ var _v8__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./v8 */ 83577); /* harmony import */ var _v9__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./v9 */ 338); /* harmony import */ var _v10__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./v10 */ 43744); /* harmony import */ var _v11__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./v11 */ 24783); /* harmony import */ var _v12__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./v12 */ 65674); /* harmony import */ var _v13__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./v13 */ 7985); /* harmony import */ var _v14__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./v14 */ 19500); /* harmony import */ var _v15__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./v15 */ 48715); /* harmony import */ var _v16__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./v16 */ 7222); /* harmony import */ var _v17__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./v17 */ 51226); /* harmony import */ var _v18__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./v18 */ 99912); /* harmony import */ var _v19__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./v19 */ 27543); /* harmony import */ var _v20__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./v20 */ 89371); /* harmony import */ var _v21__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./v21 */ 59900); /* harmony import */ var _v22__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./v22 */ 69245); /* harmony import */ var _v23__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./v23 */ 12646); /* harmony import */ var _v24__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./v24 */ 42399); /* harmony import */ var _v25__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./v25 */ 84400); /* harmony import */ var _v26__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./v26 */ 48385); /* harmony import */ var _v27__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./v27 */ 83034); // For documents pulled from the backend — RxDB only migrates locally stored // documents. Returns null when a strategy drops the document (e.g. pre-store // sessions at v19). function applyMigrations(document, fromVersion, toVersion) { let migrated = document; for (let version = fromVersion + 1; version <= toVersion && migrated; version++) { const strategy = MIGRATION_STRATEGIES[version]; if (!strategy) { throw new Error(`No work-session migration strategy for v${version}`); } migrated = strategy(migrated); } return migrated; } const MIGRATION_STRATEGIES = { 1: _v1__WEBPACK_IMPORTED_MODULE_0__.migrateToV1, 2: _v2__WEBPACK_IMPORTED_MODULE_1__.migrateToV2, 3: _v3__WEBPACK_IMPORTED_MODULE_2__.migrateToV3, 4: _v4__WEBPACK_IMPORTED_MODULE_3__.migrateToV4, 5: _v5__WEBPACK_IMPORTED_MODULE_4__.migrateToV5, 6: _v6__WEBPACK_IMPORTED_MODULE_5__.migrateToV6, 7: _v7__WEBPACK_IMPORTED_MODULE_6__.migrateToV7, 8: _v8__WEBPACK_IMPORTED_MODULE_7__.migrateToV8, 9: _v9__WEBPACK_IMPORTED_MODULE_8__.migrateToV9, 10: _v10__WEBPACK_IMPORTED_MODULE_9__.migrateToV10, 11: _v11__WEBPACK_IMPORTED_MODULE_10__.migrateToV11, 12: _v12__WEBPACK_IMPORTED_MODULE_11__.migrateToV12, 13: _v13__WEBPACK_IMPORTED_MODULE_12__.migrateToV13, 14: _v14__WEBPACK_IMPORTED_MODULE_13__.migrateToV14, 15: _v15__WEBPACK_IMPORTED_MODULE_14__.migrateToV15, 16: _v16__WEBPACK_IMPORTED_MODULE_15__.migrateToV16, 17: _v17__WEBPACK_IMPORTED_MODULE_16__.migrateToV17, 18: _v18__WEBPACK_IMPORTED_MODULE_17__.migrateToV18, 19: _v19__WEBPACK_IMPORTED_MODULE_18__.migrateToV19, 20: _v20__WEBPACK_IMPORTED_MODULE_19__.migrateToV20, 21: _v21__WEBPACK_IMPORTED_MODULE_20__.migrateToV21, 22: _v22__WEBPACK_IMPORTED_MODULE_21__.migrateToV22, 23: _v23__WEBPACK_IMPORTED_MODULE_22__.migrateToV23, 24: _v24__WEBPACK_IMPORTED_MODULE_23__.migrateToV24, 25: _v25__WEBPACK_IMPORTED_MODULE_24__.migrateToV25, 26: _v26__WEBPACK_IMPORTED_MODULE_25__.migrateToV26, 27: _v27__WEBPACK_IMPORTED_MODULE_26__.migrateToV27 }; /***/ }, /***/ 93066 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v1.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV1: () => (/* binding */ migrateToV1) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); /* harmony import */ var _tomoverse_utils_dicom_windowing_presets__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils/dicom/windowing-presets */ 21423); /* harmony import */ var _tomoverse_utils_volume_viewer_map_viewport_to_orientation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils/volume-viewer/map-viewport-to-orientation */ 3009); const migrateToV1 = oldDocument => ({ ...oldDocument, name: `${_tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.ANALYSIS_BASE_NAME} 1`, schemaVersion: 1, viewportStates: oldDocument.viewportStates.map(viewportState => ({ ...viewportState, axialPlane: viewportState.AX, cameraState: undefined, coronalPlane: viewportState.CC, fieldOfView: viewportState.FOV, isDarkMode: false, isPosterior: false, orientation: viewportState.orientation ?? (0,_tomoverse_utils_volume_viewer_map_viewport_to_orientation__WEBPACK_IMPORTED_MODULE_3__.mapViewportIdToOrientation)(viewportState.viewportId), sagittalPlane: viewportState.RL, type: viewportState.type ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportType.ORTHOGRAPHIC, windowPresetName: viewportState.windowPresetName ?? `${_tomoverse_utils_dicom_windowing_presets__WEBPACK_IMPORTED_MODULE_2__.PRESET_NAME_PREFIX} ${new Date().toISOString()}` })) }); /***/ }, /***/ 43744 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v10.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV10: () => (/* binding */ migrateToV10) /* harmony export */ }); // An enum was modified between V9-V10 with values that weren't previous // used, so this migration is basically a no-op const migrateToV10 = oldDocument => { return { ...oldDocument, schemaVersion: 10 }; }; /***/ }, /***/ 24783 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v11.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV11: () => (/* binding */ migrateToV11) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const migrateToV11 = oldDocument => { return { ...oldDocument, annotations: // eslint-disable-next-line @typescript-eslint/no-explicit-any oldDocument.annotations?.map(annotation => { // Previously used `uid` const newAnnotation = { ...annotation, id: annotation.uid }; delete newAnnotation.uid; // Previously converted `position` to `points[0]` if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.AnnotationSourceType.POINT) { newAnnotation.position = annotation.points[0]; delete newAnnotation.points; } return newAnnotation; }) ?? [], schemaVersion: 11 }; }; /***/ }, /***/ 65674 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v12.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV12: () => (/* binding */ migrateToV12) /* harmony export */ }); // The only difference between V11-V12 is enabling attachments // and adding new fields to some annotation types, // so this migration is basically a no-op const migrateToV12 = oldDocument => { return { ...oldDocument, schemaVersion: 12 }; }; /***/ }, /***/ 7985 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v13.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV13: () => (/* binding */ migrateToV13) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const DEFAULT_VASCULAR_PRESET = { ambient: 0.27, bloodCalciumThreshold: 1000, clusterSize: 10_000, diffuse: 0.84, distalDepth: -150, erosionRadius: 2, gridStep: 15, hasAcceptedSegmentation: false, imageQuality: 70, label: 'Vascular', maxHU: 1000, minHU: 170, opacityTransitionWidth: 1, outlierOpacity: 0, proximalDepth: 150, selectedPreset: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.VASCULAR, specular: 0.4, specularPower: 20, tissueBloodThreshold: 170 }; // Vascular preset introduced with segmentation fields in V13. // Also inserts the full default vascular preset for sessions created before vascular mode existed. const migrateToV13 = oldDocument => { const presets = oldDocument.renderSettings.volumeRenderPresets; const hasVascular = presets.some(p => p.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.VASCULAR); const updatedPresets = presets.map(preset => { if (preset.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.VASCULAR) return preset; return { clusterSize: 10_000, erosionRadius: 2, gridStep: 15, hasAcceptedSegmentation: false, maxHU: 1000, minHU: 170, outlierOpacity: 0, ...preset }; }); return { ...oldDocument, renderSettings: { ...oldDocument.renderSettings, volumeRenderPresets: hasVascular ? updatedPresets : [...updatedPresets, DEFAULT_VASCULAR_PRESET] }, schemaVersion: 13 }; }; /***/ }, /***/ 19500 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v14.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV14: () => (/* binding */ migrateToV14) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const OBJECT3D_TYPES = new Set([_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.AnnotationSourceType.CYLINDER, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.AnnotationSourceType.HOLLOW_CYLINDER, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.AnnotationSourceType.STL]); // V13 → V14 adds `locked` (all Object3D types) and optional `centerOfRotation` (STL). // Backfill `locked: false` on pre-existing 3D objects; `centerOfRotation` stays // unset and falls back to the mesh centroid at render time. const migrateToV14 = oldDocument => ({ ...oldDocument, annotations: // eslint-disable-next-line @typescript-eslint/no-explicit-any oldDocument.annotations?.map(annotation => OBJECT3D_TYPES.has(annotation.type) && annotation.locked === undefined ? { ...annotation, locked: false } : annotation) ?? [], schemaVersion: 14 }); /***/ }, /***/ 48715 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v15.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV15: () => (/* binding */ migrateToV15) /* harmony export */ }); // Ensure the `protocols` section is added to documents const migrateToV15 = oldDocument => ({ ...oldDocument, protocols: { definitions: [], instances: [] }, schemaVersion: 15 }); /***/ }, /***/ 7222 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v16.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV16: () => (/* binding */ migrateToV16) /* harmony export */ }); // `storeUid` is required (store-scoped viewer). Pre-store sessions can't target a // store, so drop them (return null). A fresh session is created when reopened. const migrateToV16 = oldDocument => // eslint-disable-next-line unicorn/no-null oldDocument.storeUid ? { ...oldDocument, schemaVersion: 16 } : null; /***/ }, /***/ 51226 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v17.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV17: () => (/* binding */ migrateToV17) /* harmony export */ }); // Split the V16 "protocols" property so that the protocol definitions // are in the top-level worksession, and the instances are in the volume const migrateToV17 = oldDocument => { // V16 may have dropped the document (returned null for a pre-store session). // Propagate that instead of dereferencing a null document. if (!oldDocument) return oldDocument; return { ...oldDocument, protocolDefinitions: oldDocument.protocols?.definitions ?? [], schemaVersion: 17, volumes: oldDocument.volumes.map((volume, index) => ({ ...volume, protocolData: index === 0 ? { instances: oldDocument.protocols?.instances ?? [] } : { instances: [] } })) }; }; /***/ }, /***/ 99912 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v18.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV18: () => (/* binding */ migrateToV18) /* harmony export */ }); // V17 → V18: clamp stored vascular slab depths and imageQuality to the new faster // defaults, preserving tighter user-chosen values. Literals are historical snapshots, // not references to the live constants. const VASCULAR_PRESET_NAME = 'CT-Vascular'; const MAX_PROXIMAL_DEPTH = 75; const MIN_DISTAL_DEPTH = -75; const MAX_IMAGE_QUALITY = 50; const clampVascularPreset = preset => { if (preset?.selectedPreset !== VASCULAR_PRESET_NAME) return preset; const next = { ...preset }; if (typeof next.proximalDepth === 'number') { next.proximalDepth = Math.min(next.proximalDepth, MAX_PROXIMAL_DEPTH); } if (typeof next.distalDepth === 'number') { next.distalDepth = Math.max(next.distalDepth, MIN_DISTAL_DEPTH); } if (typeof next.imageQuality === 'number') { next.imageQuality = Math.min(next.imageQuality, MAX_IMAGE_QUALITY); } return next; }; const clampRenderSettings = renderSettings => { if (!renderSettings?.volumeRenderPresets) return renderSettings; return { ...renderSettings, volumeRenderPresets: renderSettings.volumeRenderPresets.map(preset => clampVascularPreset(preset)) }; }; const migrateToV18 = oldDocument => { const document = oldDocument; return { ...document, renderSettings: clampRenderSettings(document.renderSettings), schemaVersion: 18, volumes: (document.volumes ?? []).map(volume => ({ ...volume, renderSettings: clampRenderSettings(volume.renderSettings) })) }; }; /***/ }, /***/ 27543 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v19.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV19: () => (/* binding */ migrateToV19) /* harmony export */ }); // `storeUid` is required (store-scoped viewer). Pre-store sessions can't target a // store, so drop them (return null). A fresh session is created when reopened. const migrateToV19 = oldDocument => // eslint-disable-next-line unicorn/no-null oldDocument.storeUid ? { ...oldDocument, schemaVersion: 19 } : null; /***/ }, /***/ 69583 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v2.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV2: () => (/* binding */ migrateToV2) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); const migrateToV2 = oldDocument => ({ ...oldDocument, name: `${_tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.ANALYSIS_BASE_NAME} 2`, renderSettings: { forceLowQuality: false, selectedWindowPresetName: 'window1', volumeSettings: { ..._tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO] }, windowPresets: [] // Will be populated on first load }, schemaVersion: 2, viewportCamera: { ax: 0, cameraDistance: -10, intersection: [0, 0, 0], isocenter: [0, 0, 0], isPosterior: false, matrix: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.INIT_CAMERA_MATRIX, showCrosshairs: true, viewportAxisMapping: { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.ALTERNATEBOTTOMLEFT]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.ALTERNATETOPLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.AXIAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.BOTTOMLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.MIDDLEMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.RIGHTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.TOPLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxis.AXIAL }, zoom: 1 } }); /***/ }, /***/ 89371 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v20.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV20: () => (/* binding */ migrateToV20) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); // V19 → V20: adds vascularThresholdsAutoTuned so the histogram auto-tune heuristic can // tell "never touched" apart from "reset back to the default values" — pre-V20 sessions // already have real (possibly user-set) thresholds, so they must be marked as tuned // rather than left eligible for the heuristic to silently overwrite them. Also adds // vascularSegmentationState so the segmentation mode (none/previewing/applied) is // persisted alongside the thresholds it now governs — derived from the already-persisted // hasAcceptedSegmentation flag rather than defaulting everyone to "none". const backfillVascularPreset = preset => { if (preset?.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.VASCULAR) return preset; return { vascularSegmentationState: preset.hasAcceptedSegmentation ? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VascularSegmentationState.APPLIED : _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VascularSegmentationState.NONE, vascularThresholdsAutoTuned: true, ...preset }; }; const backfillRenderSettings = renderSettings => { if (!renderSettings?.volumeRenderPresets) return renderSettings; return { ...renderSettings, volumeRenderPresets: renderSettings.volumeRenderPresets.map(preset => backfillVascularPreset(preset)) }; }; const migrateToV20 = oldDocument => { const document = oldDocument; return { ...document, renderSettings: backfillRenderSettings(document.renderSettings), schemaVersion: 20, volumes: (document.volumes ?? []).map(volume => ({ ...volume, renderSettings: backfillRenderSettings(volume.renderSettings) })) }; }; /***/ }, /***/ 59900 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v21.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV21: () => (/* binding */ migrateToV21) /* harmony export */ }); // V20 → V21: backfills chambers on each volume. Pre-V21 local documents predate the // chambers field entirely, so without this they fail workSessionSchema validation on load. const migrateToV21 = oldDocument => { const document = oldDocument; return { ...document, schemaVersion: 21, volumes: (document.volumes ?? []).map(volume => ({ ...volume, chambers: volume.chambers ?? [] })) }; }; /***/ }, /***/ 69245 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v22.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV22: () => (/* binding */ migrateToV22) /* harmony export */ }); // Matches DEFAULT_S_CURVE_LINE_WIDTH in @tomoverse/dtos and the default `fontSize` // on ScaleComponent in @tomoverse/ui - the values these fields replace as hardcoded // constants. const DEFAULT_S_CURVE_LINE_WIDTH = 2; const DEFAULT_S_CURVE_GRAPH_FONT_SIZE = 9; // V21 → V22: backfills sCurves/sCurveRelativeMeasurements on each volume (with // per-curve `lineWidth`), and `sCurveGraphFontSize` on every renderSettings object // (root + per-volume). Pre-V22 local documents predate all of these fields entirely, // so without this they fail workSessionSchema validation on load. const migrateToV22 = oldDocument => { const document = oldDocument; const backfillRenderSettings = renderSettings => ({ ...renderSettings, sCurveGraphFontSize: renderSettings?.['sCurveGraphFontSize'] ?? DEFAULT_S_CURVE_GRAPH_FONT_SIZE }); return { ...document, renderSettings: backfillRenderSettings(document.renderSettings), schemaVersion: 22, volumes: (document.volumes ?? []).map(volume => ({ ...volume, renderSettings: backfillRenderSettings(volume.renderSettings), sCurveRelativeMeasurements: volume.sCurveRelativeMeasurements ?? [], sCurves: (volume.sCurves ?? []).map(sCurve => ({ ...sCurve, lineWidth: sCurve.lineWidth ?? DEFAULT_S_CURVE_LINE_WIDTH })) })) }; }; /***/ }, /***/ 12646 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v23.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV23: () => (/* binding */ migrateToV23) /* harmony export */ }); // Matches DEFAULT_S_CURVE_LINE_WIDTH in @tomoverse/dtos - line width moved from a // per-curve field to a single graph-wide renderSettings field (see DEFAULT_S_CURVE_GRAPH_FONT_SIZE // for the same pattern, backfilled in v22). const DEFAULT_S_CURVE_LINE_WIDTH = 2; // Pre-V23 documents have no single "the" line width - each curve could have its own. Take the // first explicit value found (volume order, then curve order) as the new graph-wide default, // rather than silently discarding every curve's customization in favor of the hardcoded default. function findLegacyLineWidth(volumes) { for (const volume of volumes) { for (const sCurve of volume.sCurves ?? []) { if (typeof sCurve.lineWidth === 'number') return sCurve.lineWidth; } } return undefined; } // V22 → V23: backfills `sCurveLineWidth` on every renderSettings object (root + per-volume), // deriving it from any legacy per-curve `lineWidth` when present so existing customization // isn't lost. Pre-V23 local documents predate this field, so without this they fail // workSessionSchema validation on load. Also strips the now-obsolete per-curve `lineWidth` - // `additionalProperties: false` on the sCurve schema means AJV rejects any document that still // carries it, which would otherwise fail migration for real users' existing curves. const migrateToV23 = oldDocument => { const document = oldDocument; const legacyLineWidth = findLegacyLineWidth(document.volumes ?? []); const defaultLineWidth = legacyLineWidth ?? DEFAULT_S_CURVE_LINE_WIDTH; const backfillRenderSettings = renderSettings => ({ ...renderSettings, sCurveLineWidth: renderSettings?.['sCurveLineWidth'] ?? defaultLineWidth }); return { ...document, renderSettings: backfillRenderSettings(document.renderSettings), schemaVersion: 23, volumes: (document.volumes ?? []).map(volume => ({ ...volume, renderSettings: backfillRenderSettings(volume.renderSettings), sCurves: (volume.sCurves ?? []).map(({ lineWidth, ...sCurve }) => sCurve) })) }; }; /***/ }, /***/ 42399 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v24.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV24: () => (/* binding */ migrateToV24) /* harmony export */ }); // Matches DEFAULT_S_CURVE_LINE_WIDTH's sibling pattern - `ax` (the viewport rotation slider // value) moved onto each chamber so "go to chamber" can restore it, alongside cameraOrientation. const DEFAULT_CHAMBER_AX = 0; // V23 → V24: backfills `ax` on each chamber. Pre-V24 local documents predate this field, so // without this they fail workSessionSchema validation on load. const migrateToV24 = oldDocument => { const document = oldDocument; return { ...document, schemaVersion: 24, volumes: (document.volumes ?? []).map(volume => ({ ...volume, chambers: (volume.chambers ?? []).map(chamber => ({ ...chamber, ax: chamber.ax ?? DEFAULT_CHAMBER_AX })) })) }; }; /***/ }, /***/ 84400 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v25.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV25: () => (/* binding */ migrateToV25) /* harmony export */ }); // V24 → V25: adds `isocenter`, `intersection`, and `crosshairRotation` to the chamber schema. // These are optional rather than backfilled - pre-V25 chambers never captured this state, so // there's no real value to fill in, and "go to chamber" skips restoring them when absent // instead of snapping to a fabricated position. No document rewriting is needed; only the // version bumps. const migrateToV25 = oldDocument => { return { ...oldDocument, schemaVersion: 25 }; }; /***/ }, /***/ 48385 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v26.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV26: () => (/* binding */ migrateToV26) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); const MIP_PRESET = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.MIP]; const backfillMipPreset = renderSettings => { if (!renderSettings?.volumeRenderPresets) return renderSettings; const hasMipPreset = renderSettings.volumeRenderPresets.some(preset => preset.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.MIP); if (hasMipPreset) return renderSettings; return { ...renderSettings, volumeRenderPresets: [...renderSettings.volumeRenderPresets, MIP_PRESET] }; }; // V25 -> V26: MIP was added as a volume-rendering preset. Pre-V26 sessions already // have persisted preset arrays, so append the default MIP preset without overwriting any // user-customized MIP preset that may already exist. const migrateToV26 = oldDocument => { const document = oldDocument; return { ...document, renderSettings: backfillMipPreset(document.renderSettings), schemaVersion: 26, volumes: document.volumes?.map(volume => ({ ...volume, renderSettings: backfillMipPreset(volume.renderSettings) })) }; }; /***/ }, /***/ 83034 /*!********************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v27.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV27: () => (/* binding */ migrateToV27) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); const rewriteProtocolData = protocolData => { if (!protocolData) return protocolData; return { ...protocolData, ...(typeof protocolData.activeProtocolId === 'string' ? { activeProtocolId: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.canonicalProtocolId)(protocolData.activeProtocolId) } : {}), ...(protocolData.instances ? { instances: protocolData.instances.map(instance => typeof instance.protocolId === 'string' ? { ...instance, protocolId: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.canonicalProtocolId)(instance.protocolId) } : instance) } : {}) }; }; // V26 -> V27: the TAVI protocol id was aligned with the annotation manual. The id is a primary // key across protocolDefinitions, protocolData.activeProtocolId and every instance's protocolId, // so all three are rewritten together - a partial rewrite would orphan the instances from their // definition. Non-TAVI ids pass through untouched. const migrateToV27 = oldDocument => { const document = oldDocument; return { ...document, protocolDefinitions: document.protocolDefinitions?.map(definition => typeof definition.id === 'string' ? { ...definition, id: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.canonicalProtocolId)(definition.id) } : definition), schemaVersion: 27, volumes: document.volumes?.map(volume => ({ ...volume, protocolData: rewriteProtocolData(volume.protocolData) })) }; }; /***/ }, /***/ 30560 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v3.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV3: () => (/* binding */ migrateToV3) /* harmony export */ }); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); const migrateToV3 = oldDocument => ({ ...oldDocument, name: `${_tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_0__.ANALYSIS_BASE_NAME} 3`, renderSettings: { forceLowQuality: false, selectedVolumePresetName: 'CT-Cardiac3', selectedWindowPresetName: 'window1', volumeRenderPresets: [], // Will be populated on first load windowPresets: [] // Will be populated on first load }, schemaVersion: 3 }); /***/ }, /***/ 73133 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v4.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV4: () => (/* binding */ migrateToV4) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); const migrateToV4 = oldDocument => ({ ...oldDocument, renderSettings: { ...oldDocument.renderSettings, volumeRenderPresets: oldDocument.renderSettings.volumeRenderPresets.map(preset => { switch (preset.value) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO: { return { airTissueThreshold: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO].airTissueThreshold, bloodCalciumThreshold: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO].bloodCalciumThreshold, distalDepth: preset.distalDepth, imageQuality: preset.imageQuality, label: preset.label, proximalDepth: preset.proximalDepth, selectedPreset: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO, tissueBloodThreshold: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO].tissueBloodThreshold }; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.FLUOROSCOPIC: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.XRAY: { const { value, ...rest } = preset; return { ...rest, selectedPreset: value }; } } }) }, schemaVersion: 4 }); /***/ }, /***/ 438 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v5.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV5: () => (/* binding */ migrateToV5) /* harmony export */ }); // Only optional fields were added between V4-V5, so this migration // is basically a no-op; const migrateToV5 = oldDocument => { return { ...oldDocument, schemaVersion: 5 }; }; /***/ }, /***/ 35531 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v6.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV6: () => (/* binding */ migrateToV6) /* harmony export */ }); // An enum was modified between V5-V6 with values that weren't previous // used, so this migration is basically a no-op const migrateToV6 = oldDocument => { return { ...oldDocument, schemaVersion: 6 }; }; /***/ }, /***/ 12204 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v7.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV7: () => (/* binding */ migrateToV7) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); const ENDO_DEFAULTS = _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_1__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO]; const migrateToV7 = oldDocument => { if (!oldDocument.renderSettings) return oldDocument; return { ...oldDocument, renderSettings: { ...oldDocument.renderSettings, volumeRenderPresets: oldDocument.renderSettings.volumeRenderPresets.map(preset => { if (preset.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.VolumeRenderingOption.ENDO) return preset; return { ...ENDO_DEFAULTS, ...preset }; }) }, schemaVersion: 7 }; }; /***/ }, /***/ 83577 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v8.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV8: () => (/* binding */ migrateToV8) /* harmony export */ }); const migrateToV8 = oldDocument => ({ ...oldDocument, annotationSize: 2, schemaVersion: 8 }); /***/ }, /***/ 338 /*!*******************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/migrations/v9.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ migrateToV9: () => (/* binding */ migrateToV9) /* harmony export */ }); // An enum was modified between V8-V9 with values that weren't previous // used, so this migration is basically a no-op const migrateToV9 = oldDocument => { return { ...oldDocument, schemaVersion: 9 }; }; /***/ }, /***/ 17818 /*!***********************************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/work-session-database.service.ts ***! \***********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionDatabaseService: () => (/* binding */ WorkSessionDatabaseService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 90015); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 8102); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxdb */ 73738); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxdb */ 99984); /* harmony import */ var _rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../rxdb-attachment-binary */ 94669); /* harmony import */ var _services_work_session_work_session_api_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../services/work-session/work-session-api.service */ 29039); /* harmony import */ var _rxdb_manager_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../rxdb-manager.service */ 67189); /* harmony import */ var _work_session_collection__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./work-session.collection */ 32159); class WorkSessionDatabaseService { rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_11__.RxdbManager); workSessionApi = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_work_session_work_session_api_service__WEBPACK_IMPORTED_MODULE_10__.WorkSessionApiService); find() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (filters = {}) { const collection = yield _this.rxdbManager.getWorkSessionCollection(); const documents = yield collection.find({ selector: filters }).exec(); return documents.map(workSessionDocument => workSessionDocument.toJSON()); }).apply(this, arguments); } get(uid) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this2.rxdbManager.getWorkSessionCollection(); const workSessionDocument = yield collection.findOne(uid).exec(); return workSessionDocument?.toJSON(); })(); } getAttachments(uid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this3.rxdbManager.getWorkSessionCollection(); const workSessionDocument = yield collection.findOne(uid).exec(); return workSessionDocument?.allAttachments(); })(); } get$(uid) { return this.rxdbManager.workSessions$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.switchMap)(collection => collection ? collection.findOne(uid).$ : rxjs__WEBPACK_IMPORTED_MODULE_3__.EMPTY), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.map)(workSessionDocument => workSessionDocument?.toJSON()), (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.distinctUntilChanged)(rxdb__WEBPACK_IMPORTED_MODULE_8__.deepEqual)); } workSessions$(filters = {}) { return this.rxdbManager.workSessions$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.switchMap)(collection => { if (!collection) return rxjs__WEBPACK_IMPORTED_MODULE_3__.EMPTY; return collection.find({ selector: filters }).$; }), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.map)(documents => documents.map(workSessionDocument => workSessionDocument.toJSON()))); } syncWorkSessionsFromServer(collection, filters) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const serverWorkSessions = yield _this4.workSessionApi.find(filters); if (serverWorkSessions.length === 0) return; const ids = serverWorkSessions.map(({ uid }) => uid); const existingDocuments = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.firstValueFrom)(collection.findByIds(ids).$); // Only update work sessions that have actually changed - otherwise the // `collection.preSave()` hook will update the `updatedAt` timestamp // on every work session fetched const changed = serverWorkSessions.filter(session => { const existing = existingDocuments.get(session.uid); if (!existing) return true; return existing.version < session.version; }); // We populate the each work session's attachments in a separate http call // because doing so in a batch call could hit response size limits const withAttachments = yield Promise.all(changed.map(session => _this4.ensureAttachments(session))); yield collection.bulkUpsert(withAttachments, { deleteExistingAttachments: false }); } catch (error) { console.error('Failed to refresh work sessions from server', error); } })(); } ensureAttachments(session) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // If there are no attachments for this work session, nothing else to do if (Object.keys(session._attachments).length === 0) { return session; } // Otherwise, fetch the full attachment data from the backend. try { const withAttachments = yield _this5.workSessionApi.get(session.uid, true); for (const attachment of Object.values(withAttachments._attachments)) { if (attachment.data) { // eslint-disable-next-line @typescript-eslint/no-explicit-any attachment.data = (0,_rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_9__.toRxdbAttachmentBinary)((0,rxdb__WEBPACK_IMPORTED_MODULE_7__.base64ToArrayBuffer)(attachment.data)); } } return withAttachments; } catch (error) { console.warn('Failed to fetch workSession attachments', error); return session; } })(); } save(_x) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (workSession, { attachments, incrementVersion } = {}) { const collection = yield _this6.rxdbManager.getWorkSessionCollection(); const update = { ...workSession, _attachments: attachments ? [...attachments] : undefined, version: incrementVersion ? workSession.version + 1 : workSession.version }; yield collection.incrementalUpsert(update, { deleteExistingAttachments: attachments !== undefined }); }).apply(this, arguments); } addAttachment(workSessionId, creator) { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this7.rxdbManager.getWorkSessionCollection(); const document = yield collection.findOne(workSessionId).exec(); yield document?.putAttachment(creator); })(); } delete(uid) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this8.rxdbManager.getWorkSessionCollection(); const workSessionDocument = yield collection.findOne(uid).exec(); if (workSessionDocument) { yield workSessionDocument.incrementalRemove(); } })(); } markDraft(uid) { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this9.rxdbManager.getWorkSessionCollection(); yield collection.upsertLocal((0,_work_session_collection__WEBPACK_IMPORTED_MODULE_12__.workSessionDraftKey)(uid), { draft: true }); })(); } clearDraft(uid) { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this0.rxdbManager.getWorkSessionCollection(); // Flip rather than remove: the push handler must see the finalization to // re-send attachment data its dropped draft-era pushes never delivered. yield collection.upsertLocal((0,_work_session_collection__WEBPACK_IMPORTED_MODULE_12__.workSessionDraftKey)(uid), { draft: false }); })(); } isDraft(uid) { var _this1 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const collection = yield _this1.rxdbManager.getWorkSessionCollection(); const marker = yield collection.getLocal((0,_work_session_collection__WEBPACK_IMPORTED_MODULE_12__.workSessionDraftKey)(uid)); return !!marker?.get('draft'); })(); } static ɵfac = function WorkSessionDatabaseService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionDatabaseService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: WorkSessionDatabaseService, factory: WorkSessionDatabaseService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 32159 /*!*****************************************************************************!*\ !*** ./libs/data-access/src/lib/db/work-session/work-session.collection.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ createWorkSessionPullHandler: () => (/* binding */ createWorkSessionPullHandler), /* harmony export */ createWorkSessionPushHandler: () => (/* binding */ createWorkSessionPushHandler), /* harmony export */ prepareIncomingWorkSession: () => (/* binding */ prepareIncomingWorkSession), /* harmony export */ setupWorkSessionCollection: () => (/* binding */ setupWorkSessionCollection), /* harmony export */ workSessionDraftKey: () => (/* binding */ workSessionDraftKey) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxdb */ 64062); /* harmony import */ var rxdb_plugins_replication__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxdb/plugins/replication */ 9350); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_utils_pipes_exponential_backoff_pipe__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/utils/pipes/exponential-backoff.pipe */ 4251); /* harmony import */ var _rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../rxdb-attachment-binary */ 94669); /* harmony import */ var _services_work_session_work_session_sse_client__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../services/work-session/work-session-sse-client */ 99335); /* harmony import */ var _migrations__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./migrations */ 86515); const workSessionDraftKey = uid => `draft-${uid}`; // RxDB records rows the handler drops as delivered, so pushes after finalization // omit the attachment data it believes the backend already has. Refill it from // local storage for this one push. const refillAttachmentData = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (collection, row) { const attachments = Object.entries(row.newDocumentState._attachments ?? {}); if (attachments.length === 0) return; const workSessionDocument = yield collection.findOne(row.newDocumentState.uid).exec(); if (!workSessionDocument) return; for (const [id, attachment] of attachments) { if ('data' in attachment && attachment.data) continue; const stored = workSessionDocument.getAttachment(id); if (!stored) continue; attachment.data = yield stored.getDataBase64(); } }); return function refillAttachmentData(_x, _x2) { return _ref.apply(this, arguments); }; }(); // Never-saved sessions stay off the backend. const partitionDraftRows = /*#__PURE__*/function () { var _ref2 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (collection, documents) { const pushable = []; const finalizedMarkers = []; for (const document of documents) { const uid = document.newDocumentState.uid; const marker = yield collection.getLocal(workSessionDraftKey(uid)); if (marker?.get('draft')) continue; if (marker) { yield refillAttachmentData(collection, document); finalizedMarkers.push({ marker, uid }); } pushable.push(document); } return { finalizedMarkers, pushable }; }); return function partitionDraftRows(_x3, _x4) { return _ref2.apply(this, arguments); }; }(); const createWorkSessionPushHandler = (collection, http, syncUrl) => (/*#__PURE__*/function () { var _ref3 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (documents) { const { finalizedMarkers, pushable } = yield partitionDraftRows(collection, documents); if (pushable.length === 0) return []; for (const document of pushable) { for (const attachment of Object.values(document.newDocumentState._attachments ?? {})) { // Can't directly serialize Blobs if ('data' in attachment && attachment.data instanceof Blob) { // eslint-disable-next-line @typescript-eslint/no-explicit-any attachment.data = yield (0,rxdb__WEBPACK_IMPORTED_MODULE_6__.blobToBase64String)(attachment.data); } } } const conflicts = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_1__.firstValueFrom)(http.post(`${syncUrl}/push`, pushable)); // Only for accepted documents: failed or conflicted pushes retry and must refill again. const conflictUids = new Set(conflicts.map(({ uid }) => uid)); for (const { marker, uid } of finalizedMarkers) { if (!conflictUids.has(uid)) yield marker.remove(); } return conflicts; }); return function (_x5) { return _ref3.apply(this, arguments); }; }()); // Migrates, normalizes and validates a document arriving from the backend. // Returns undefined to skip it: one rejected document would otherwise fail the // whole replication batch and stall the sync for good. const prepareIncomingWorkSession = workSession => { if (workSession._deleted) return workSession; let document = workSession; if (document.schemaVersion < _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_8__.WORK_SESSION_LATEST_SCHEMA) { try { const migrated = (0,_migrations__WEBPACK_IMPORTED_MODULE_12__.applyMigrations)(document, document.schemaVersion, _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_8__.WORK_SESSION_LATEST_SCHEMA); if (!migrated) return undefined; document = migrated; } catch (error) { console.warn('Failed to migrate work session', workSession.uid, error); return undefined; } } try { const normalized = { ...document, _attachments: Object.fromEntries(Object.entries(document._attachments ?? {}).map(([id, attachment]) => [id, { ...attachment, data: 'data' in attachment && (0,_ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.isString)(attachment.data) ? base64ToBlob(attachment.data) : undefined }])), volumes: document.volumes?.map(volume => ({ ...volume, annotations: volume.annotations?.map(annotation => ({ ...annotation, placeholderId: annotation.placeholderId ?? undefined })), chambers: volume.chambers ?? [] })) }; const { _attachments, _deleted, ...content } = normalized; const validation = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_8__.workSessionSchema.safeParse(content); if (!validation.success) { console.warn('Skipping invalid work session', workSession.uid, validation.error); return undefined; } return normalized; } catch (error) { console.warn('Skipping invalid work session', workSession.uid, error); return undefined; } }; const prepareIncomingWorkSessions = documents => documents.map(document => prepareIncomingWorkSession(document)).filter(document => document !== undefined); // A short batch tells RxDB it is fully synced, so dropped documents must not shrink the batch. const createWorkSessionPullHandler = (http, syncUrl) => (/*#__PURE__*/function () { var _ref4 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (lastCheckpoint, batchSize) { let checkpoint = lastCheckpoint; const prepared = []; for (;;) { const documents = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_1__.firstValueFrom)(http.get(`${syncUrl}/pull`, { params: { lastUpdatedAt: (checkpoint?.lastUpdatedAt ?? 0).toString(), limit: batchSize.toString() } })); // Checkpoint from the raw batch, so skipped documents aren't re-pulled forever. const last = documents.at(-1); if (last) checkpoint = { lastUpdatedAt: last.updatedAt }; prepared.push(...prepareIncomingWorkSessions(documents)); if (documents.length < batchSize || prepared.length >= batchSize) { return { checkpoint, documents: prepared }; } } }); return function (_x6, _x7) { return _ref4.apply(this, arguments); }; }()); function setupWorkSessionCollection(_x8, _x9, _x0, _x1) { return _setupWorkSessionCollection.apply(this, arguments); } function _setupWorkSessionCollection() { _setupWorkSessionCollection = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (database, http, authService, apiUrl) { const updatedDatabase = yield database.addCollections({ workSession: { conflictHandler: { isEqual: (a, b) => a.updatedAt === b.updatedAt, resolve: function () { var _ref5 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* ({ realMasterState }) { return realMasterState; }); return function resolve(_x10) { return _ref5.apply(this, arguments); }; }() }, localDocuments: true, migrationStrategies: _migrations__WEBPACK_IMPORTED_MODULE_12__.MIGRATION_STRATEGIES, schema: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_8__.workSessionRxdbJsonSchema } }); const { workSession: collection } = updatedDatabase; const syncUrl = `${apiUrl}/work-session/sync`; const sseClient = new _services_work_session_work_session_sse_client__WEBPACK_IMPORTED_MODULE_11__.WorkSessionSseClient(); collection.preInsert(data => { const userId = authService.currentUser()?.accountId; if (!userId) throw new Error('Authentication required'); const now = new Date().toISOString(); data.createdAt = now; data.createdByUid = userId; data.updatedAt = now; data.updatedByUid = userId; }, true); collection.preSave(data => { const userId = authService.currentUser()?.accountId; if (!userId) throw new Error('Authentication required'); data.updatedAt = new Date().toISOString(); data.updatedByUid = userId; }, true); const replicationState = (0,rxdb_plugins_replication__WEBPACK_IMPORTED_MODULE_7__.replicateRxCollection)({ collection, pull: { handler: createWorkSessionPullHandler(http, syncUrl), stream$: sseClient.stream(`${syncUrl}/stream`, { authProbe: function () { var _ref6 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // We start stream calls with this so that the // AuthInterceptor can refresh tokens / log out if necessary. try { yield (0,rxjs__WEBPACK_IMPORTED_MODULE_1__.firstValueFrom)(authService.fetchUser()); } catch (error) { yield authService.logout(); throw error; } }); return function authProbe() { return _ref6.apply(this, arguments); }; }(), getToken: () => authService.getAccessToken(), keepAlive: true }).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_4__.map)(data => JSON.parse(data)), (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.map)(({ checkpoint, documents }) => ({ checkpoint, documents: prepareIncomingWorkSessions(documents) })), (0,_tomoverse_utils_pipes_exponential_backoff_pipe__WEBPACK_IMPORTED_MODULE_9__.retryWithBackoff)(), (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.of)('RESYNC'))) }, push: { handler: createWorkSessionPushHandler(collection, http, syncUrl) }, replicationIdentifier: `work-session-replication-${syncUrl}`, // Waiting would stall the first sync after sign-out recreates the database. waitForLeadership: false }); return replicationState; }); return _setupWorkSessionCollection.apply(this, arguments); } function base64ToBlob(base64) { const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let index = 0; index < binary.length; index++) { // eslint-disable-next-line unicorn/prefer-code-point bytes[index] = binary.charCodeAt(index); } return (0,_rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_10__.toRxdbAttachmentBinary)(bytes); } /***/ }, /***/ 89967 /*!*******************************************************!*\ !*** ./libs/data-access/src/lib/guards/auth.guard.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ authGuard: () => (/* binding */ authGuard) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _services_auth_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../services/auth.service */ 52807); const PUBLIC_ROUTES = ['/login', '/sign-up']; const isPublicRoute = url => PUBLIC_ROUTES.some(route => url.startsWith(route)); const authGuard = (route, state) => { const authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_services_auth_service__WEBPACK_IMPORTED_MODULE_2__.AuthService); const router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_1__.Router); const publicRoute = isPublicRoute(state.url); const isAuthenticated = authService.isAuthenticated(); if (isAuthenticated && publicRoute) { return router.createUrlTree(['/']); } if (!isAuthenticated && !publicRoute) { return router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } }); } return true; }; /***/ }, /***/ 5138 /*!******************************************************************!*\ !*** ./libs/data-access/src/lib/guards/session-cleanup.guard.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ sessionCleanupGuard: () => (/* binding */ sessionCleanupGuard) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _services_auth_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../services/auth.service */ 52807); const sessionCleanupGuard = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_auth_service__WEBPACK_IMPORTED_MODULE_2__.AuthService); try { authService.currentUser.set(undefined); localStorage.clear(); } catch (error) { console.warn('Session cleanup skipped or failed:', error); } return true; }); return function sessionCleanupGuard() { return _ref.apply(this, arguments); }; }(); /***/ }, /***/ 94669 /*!************************************************************!*\ !*** ./libs/data-access/src/lib/rxdb-attachment-binary.ts ***! \************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ toRxdbAttachmentBinary: () => (/* binding */ toRxdbAttachmentBinary) /* harmony export */ }); /* harmony import */ var _tomoverse_electron_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/electron-utils */ 63940); /** * Electron's context bridge serializes Blobs as empty objects. RxDB supports * Uint8Array attachment data in Electron, but reads Blob.size before IPC. */ const toRxdbAttachmentBinary = (data, type = 'application/octet-stream', isElectronEnvironment = (0,_tomoverse_electron_utils__WEBPACK_IMPORTED_MODULE_0__.isElectron)()) => { const bytes = Uint8Array.from(data instanceof Uint8Array ? data : new Uint8Array(data)); if (!isElectronEnvironment) return new Blob([bytes], { type }); const electronBytes = bytes; Object.defineProperty(electronBytes, 'size', { value: electronBytes.byteLength }); return electronBytes; }; /***/ }, /***/ 44769 /*!***************************************************************!*\ !*** ./libs/data-access/src/lib/services/app-init.service.ts ***! \***************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AppInitService: () => (/* binding */ AppInitService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 13329); /* harmony import */ var _db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../db/rxdb-manager.service */ 67189); /* harmony import */ var _auth_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./auth.service */ 52807); /* harmony import */ var _preferences_preferences_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./preferences/preferences.service */ 4508); class AppInitService { authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_auth_service__WEBPACK_IMPORTED_MODULE_7__.AuthService); rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_6__.RxdbManager); preferences = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_preferences_preferences_service__WEBPACK_IMPORTED_MODULE_8__.PreferencesService); init() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.firstValueFrom)(_this.authService.fetchUser().pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.take)(1), (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.of)(undefined)))); if (!_this.authService.isAuthenticated()) { yield _this.authService.logout(); yield _this.rxdbManager.remove(); _this.preferences.clear(); return void 0; } yield _this.rxdbManager.init(); return void 0; })(); } static ɵfac = function AppInitService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AppInitService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: AppInitService, factory: AppInitService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 98765 /*!***********************************************************************!*\ !*** ./libs/data-access/src/lib/services/auth-interceptor.service.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AuthInterceptor: () => (/* binding */ AuthInterceptor) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs */ 84356); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 162); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 88412); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 27588); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _cornerstonejs_core_utilities_logger__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @cornerstonejs/core/utilities/logger */ 67821); /* harmony import */ var _tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils/injection-tokens/env-injection-token */ 42035); /* harmony import */ var ___WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../.. */ 42541); class AuthInterceptor { logger = (0,_cornerstonejs_core_utilities_logger__WEBPACK_IMPORTED_MODULE_7__.getLogger)(AuthInterceptor.name); authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(___WEBPACK_IMPORTED_MODULE_9__.AuthService); env = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__.ENV); staticHosts = this.env.staticHosts; refreshRequest$; intercept(request, next) { const isStaticHost = this.staticHosts.some(host => request.url.includes(host)); if (isStaticHost) { return next.handle(request); } const accessToken = this.authService.getAccessToken(); const outgoing = accessToken ? request.clone(this.createAuthHeader(accessToken)) : request; return next.handle(outgoing).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_3__.catchError)(error => { const isRefreshRequest = request.url.includes('/oauth/refresh-token'); if (error.status === 401 && !isRefreshRequest) { return this.handle401Error(outgoing, next); } return (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.throwError)(() => error); })); } handle401Error(request, next) { if (!this.refreshRequest$) { this.refreshRequest$ = this.authService.refreshTokens().pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_3__.catchError)(error => { this.logger.warn('Token refresh failed, logging out...'); return (0,rxjs__WEBPACK_IMPORTED_MODULE_1__.from)(this.authService.logout()).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_3__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.throwError)(() => error)), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.switchMap)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.throwError)(() => error))); }), (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.finalize)(() => { this.refreshRequest$ = undefined; }), (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.shareReplay)({ bufferSize: 1, refCount: false })); } return this.refreshRequest$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.switchMap)(({ accessToken }) => next.handle(request.clone(this.createAuthHeader(accessToken))))); } createAuthHeader(token) { return { setHeaders: { Authorization: `Bearer ${token}` } }; } static ɵfac = function AuthInterceptor_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AuthInterceptor)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: AuthInterceptor, factory: AuthInterceptor.ɵfac }); } /***/ }, /***/ 52807 /*!***********************************************************!*\ !*** ./libs/data-access/src/lib/services/auth.service.ts ***! \***********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AuthService: () => (/* binding */ AuthService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 45541); /* harmony import */ var _cornerstonejs_core_utilities_logger__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @cornerstonejs/core/utilities/logger */ 67821); /* harmony import */ var _tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils/injection-tokens/env-injection-token */ 42035); /* harmony import */ var _preferences_preferences_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./preferences/preferences.service */ 4508); class AuthService { environment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__.ENV); http = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpClient); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_4__.Router); preferences = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_preferences_preferences_service__WEBPACK_IMPORTED_MODULE_9__.PreferencesService); apiUrl = this.environment.apiUrl; accessTokenKey = 'accessToken'; refreshTokenKey = 'refreshToken'; logger = (0,_cornerstonejs_core_utilities_logger__WEBPACK_IMPORTED_MODULE_7__.getLogger)(AuthService.name); currentUser = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "currentUser" }] : [])); isAuthenticated = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => !!this.currentUser(), ...(ngDevMode ? [{ debugName: "isAuthenticated" }] : [])); login(email, password) { this.logger.debug('Logging in...'); return this.http.post(`${this.apiUrl}/oauth/login`, { email, password }).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(response => !!response.accessToken && !!response.refreshToken), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.tap)(response => this.setOauthTokens(response.accessToken, response.refreshToken))); } signUp(firstName, lastName, email, password) { return this.http.post(`${this.apiUrl}/oauth/register`, { email, lastName, name: firstName, password }).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.tap)(response => { if (response.accessToken && response.refreshToken) { this.setOauthTokens(response.accessToken, response.refreshToken); } })); } fetchUser() { return this.http.get(`${this.apiUrl}/user/profile`).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.tap)(user => this.currentUser.set(user))); } logout() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this.logger.debug('Logging out...'); _this.currentUser.set(undefined); _this.router.navigate(['/login']); localStorage.removeItem(_this.accessTokenKey); localStorage.removeItem(_this.refreshTokenKey); // Session-scoped preferences (last store, filters, sort, ...) must not carry over // into the next login — clear them here rather than relying on next-boot detection, // since logging back in rarely triggers a full page reload. _this.preferences.clear(); })(); } loginWith(provider) { globalThis.location.href = `${this.apiUrl}/oauth/${provider}`; } setOauthTokens(accessToken, refreshToken) { localStorage.setItem(this.accessTokenKey, accessToken); localStorage.setItem(this.refreshTokenKey, refreshToken); } getAccessToken() { return localStorage.getItem(this.accessTokenKey) ?? undefined; } getRefreshToken() { return localStorage.getItem(this.refreshTokenKey) ?? undefined; } refreshTokens() { this.logger.debug('Refreshing auth token...'); return this.http.post(`${this.apiUrl}/oauth/refresh-token`, { refreshToken: this.getRefreshToken() }).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.tap)(response => this.setOauthTokens(response.accessToken, response.refreshToken))); } static ɵfac = function AuthService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AuthService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: AuthService, factory: AuthService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 40911 /*!******************************************************************!*\ !*** ./libs/data-access/src/lib/services/dev-options.service.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DevelopmentOptionsService: () => (/* binding */ DevelopmentOptionsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); const DEFAULTS = { clearDicomCacheOnStartup: true }; const STORAGE_KEY = 'tvct.devOptions'; class DevelopmentOptionsService { _options = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(this.load(), ...(ngDevMode ? [{ debugName: "_options" }] : [])); clearDicomCacheOnStartup = () => this._options().clearDicomCacheOnStartup; set(key, value) { this._options.update(options => { const updated = { ...options, [key]: value }; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(updated)); } catch { // ignore storage errors } return updated; }); } load() { try { const stored = localStorage.getItem(STORAGE_KEY); if (stored) return { ...DEFAULTS, ...JSON.parse(stored) }; } catch { // ignore parse errors } return { ...DEFAULTS }; } static ɵfac = function DevelopmentOptionsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DevelopmentOptionsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: DevelopmentOptionsService, factory: DevelopmentOptionsService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 96269 /*!**********************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/dicom-api.service.ts ***! \**********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DicomApiService: () => (/* binding */ DicomApiService), /* harmony export */ batchFilesForUpload: () => (/* binding */ batchFilesForUpload) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/types */ 25575); /* harmony import */ var _tomoverse_utils_dicom_extract_dicom10__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/utils/dicom/extract-dicom10 */ 67227); /* harmony import */ var _tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils/injection-tokens/env-injection-token */ 42035); /* harmony import */ var _dicom_store_list_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./dicom-store-list.service */ 55643); const MAX_UPLOAD_BATCH_FILES = 100; /** * Groups files into batches that respect both a max file count and a max * cumulative byte size, so a batch never balloons past what the upload * endpoint's proxy will accept regardless of how large individual instances * are (a single-phase series has variable per-instance size, so capping only * file count still let a batch's total bytes run away). A single file that * alone exceeds maxBytes is still sent alone - splitting one DICOM instance's * bytes would produce an invalid file. */ function batchFilesForUpload(files, maxBytes = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__.MAX_UPLOAD_BATCH_BYTES, maxFiles = MAX_UPLOAD_BATCH_FILES) { if (!Number.isInteger(maxFiles) || maxFiles <= 0) { throw new Error(`batchFilesForUpload: maxFiles must be a positive integer, got ${maxFiles}`); } const batches = []; let currentBatch = []; let currentBytes = 0; for (const file of files) { const wouldExceedBytes = currentBatch.length > 0 && currentBytes + file.byteLength > maxBytes; const wouldExceedCount = currentBatch.length >= maxFiles; if (wouldExceedBytes || wouldExceedCount) { batches.push(currentBatch); currentBatch = []; currentBytes = 0; } currentBatch.push(file); currentBytes += file.byteLength; } if (currentBatch.length > 0) batches.push(currentBatch); return batches; } class DicomApiService { http = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpClient); environment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_8__.ENV); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_dicom_store_list_service__WEBPACK_IMPORTED_MODULE_9__.DicomStoreListService); /** Store-scoped WADO-RS/QIDO-RS proxy base. */ dicomWebUrl(storeUid) { return `${this.environment.apiUrl}/dicom/stores/${storeUid}/dicomweb`; } resolveVendor(storeUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const stores = yield _this.storeList.getEnabledStores(); return stores.find(store => store.uid === storeUid)?.vendor ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomVendor.ORTHANC; })(); } /** Omitting `limit` returns every study in the store. */ getStudies(storeUid, limit, offset) { let parameters = new _angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpParams().set('storeUids', storeUid); if (limit !== undefined) parameters = parameters.set('limit', limit); if (offset !== undefined) parameters = parameters.set('offset', offset); return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(this.http.get(`${this.environment.apiUrl}/dicom/studies`, { params: parameters })); } getSeriesForStudy(studyUid, storeUid) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const parameters = new _angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpParams().set('storeUids', storeUid); const { rows } = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this2.http.get(`${_this2.environment.apiUrl}/dicom/studies/${studyUid}/series`, { params: parameters })); return rows.map(row => ({ institutionName: row.institutionName, modality: row.modality, patientID: row.patientID, patientName: row.patientName, seriesDate: row.seriesDate, seriesDescription: row.seriesDescription, seriesInstanceUID: row.seriesInstanceUID, seriesNumber: row.seriesNumber, seriesTime: row.seriesTime, studyDate: row.studyDate, studyDescription: row.studyDescription, studyInstanceUID: row.studyInstanceUID || studyUid })); })(); } getInstancesForSeries(studyUid, seriesUid, storeUid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const dicomInstances = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this3.http.get(`${_this3.dicomWebUrl(storeUid)}/studies/${studyUid}/series/${seriesUid}/metadata`)); const instances = (dicomInstances ?? []).map(instance => { return { instanceNumber: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.InstanceNumber), modality: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.Modality), patientID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.PatientID), patientName: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.PatientName)?.Alphabetic, rawMetadata: instance, seriesDescription: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.SeriesDescription), seriesInstanceUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.SeriesInstanceUID), seriesNumber: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.SeriesNumber), sopInstanceUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.SOPInstanceUID), studyDescription: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.StudyDescription), studyInstanceUID: (0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_6__.getTagValue)(instance, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomTagId.StudyInstanceUID) }; }); instances.sort((a, b) => (a.instanceNumber ?? 0) - (b.instanceNumber ?? 0)); return instances; })(); } getInstanceImage(studyUid, seriesUid, instanceUid, storeUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const arrayBuffer = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this4.http.get(`${_this4.dicomWebUrl(storeUid)}/studies/${studyUid}/series/${seriesUid}/instances/${instanceUid}/rendered`, { headers: { Accept: 'image/jpeg' }, responseType: 'arraybuffer' })); const blob = new Blob([arrayBuffer], { type: 'image/jpeg' }); return blob; })(); } getInstanceDicomFile(studyUid, seriesUid, instanceUid, storeUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const isGoogleHealthcare = (yield _this5.resolveVendor(storeUid)) === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.DicomVendor.GOOGLE_HEALTHCARE; const acceptHeaders = isGoogleHealthcare ? [`application/dicom; transfer-syntax=${_this5.environment.transferSyntaxUid}`] : ['application/dicom', 'multipart/related; type=application/dicom']; let lastError; for (const acceptHeader of acceptHeaders) { try { const response = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this5.http.get(`${_this5.dicomWebUrl(storeUid)}/studies/${studyUid}/series/${seriesUid}/instances/${instanceUid}`, { headers: { Accept: acceptHeader }, observe: 'response', responseType: 'arraybuffer' })); const arrayBuffer = response.body; if (!arrayBuffer) { throw new Error('Empty DICOM instance response body'); } const bytes = new Uint8Array(arrayBuffer); const contentType = response.headers.get('content-type'); const isMultipart = _this5.isMultipartResponse(contentType, bytes); if (!isMultipart) { return arrayBuffer; } const dicomBytes = (0,_tomoverse_utils_dicom_extract_dicom10__WEBPACK_IMPORTED_MODULE_7__.extractDicomPart10)(bytes, { contentType }); return dicomBytes.buffer.slice(dicomBytes.byteOffset, dicomBytes.byteOffset + dicomBytes.byteLength); } catch (error) { lastError = error; } } if (lastError instanceof Error) { throw lastError; } throw new Error('Failed to retrieve DICOM instance'); })(); } uploadToStore(files, storeUid) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { let offset = 0; for (const batch of batchFilesForUpload(files)) { const form = new FormData(); for (const [index, file] of batch.entries()) { form.append('files', new Blob([file], { type: 'application/dicom' }), `instance-${offset + index}.dcm`); } yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this6.http.post(`${_this6.environment.apiUrl}/dicom/stores/${storeUid}/upload`, form)); offset += batch.length; } })(); } isMultipartResponse(contentType, bytes) { if (contentType) { const normalizedContentType = contentType.toLowerCase(); if (normalizedContentType.includes('multipart/related')) { return true; } if (normalizedContentType.includes('application/dicom')) { return false; } } const headerCheck = bytes.slice(0, Math.min(512, bytes.length)); const headerText = new TextDecoder('ascii', { fatal: false }).decode(headerCheck); if (/^(HTTP\/|Content-Type:|Content-Length:)/i.test(headerText)) { return true; } const dicmMagic = [0x44, 0x49, 0x43, 0x4d]; if (this.hasMagicAt(bytes, dicmMagic, 128) || this.hasMagicAt(bytes, dicmMagic, 0)) { return false; } return true; } hasMagicAt(bytes, magic, position) { if (bytes.length < position + magic.length) { return false; } return magic.every((byte, index) => bytes[position + index] === byte); } static ɵfac = function DicomApiService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomApiService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: DicomApiService, factory: DicomApiService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 67430 /*!*************************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/dicom-import.service.ts ***! \*************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DicomImportService: () => (/* binding */ DicomImportService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../db/rxdb-manager.service */ 67189); /* harmony import */ var _rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../rxdb-attachment-binary */ 94669); /* harmony import */ var _dicom_store_list_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./dicom-store-list.service */ 55643); const PARALLEL_FILE_IMPORTS = 4; class DicomImportService { rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_6__.RxdbManager); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_dicom_store_list_service__WEBPACK_IMPORTED_MODULE_8__.DicomStoreListService); uploadProgress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "uploadProgress" }] : [])); parseProgress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "parseProgress" }] : [])); totalProgress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => Math.round((this.uploadProgress() + this.parseProgress()) / 2), ...(ngDevMode ? [{ debugName: "totalProgress" }] : [])); isImporting = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "isImporting" }] : [])); fileProgress = []; totalBytes = 0; worker = new Worker(__webpack_require__.tu(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("libs_data-access_src_lib_services_dicom_worker_dicom-parse_worker_ts"), __webpack_require__.b)), { type: undefined }); pendingRequests = new Map(); constructor() { // eslint-disable-next-line unicorn/prefer-add-event-listener this.worker.onmessage = ({ data }) => { const pending = this.pendingRequests.get(data.id); if (!pending) return; this.pendingRequests.delete(data.id); if (data.ok) { pending.resolve(data.payload); return; } pending.reject(new Error(data.error)); }; } onFilesSelected(fileList, storeUid) { const files = Array.prototype.slice.call(fileList); if (files.length === 0) { console.warn('No files selected'); return; } const orderedFiles = this.interleaveByDirectory(files); this.isImporting.set(true); this.uploadProgress.set(0); this.parseProgress.set(0); this.fileProgress = Array.from({ length: orderedFiles.length }, () => 0); this.totalBytes = orderedFiles.reduce((total, file) => total + file.size, 0); this.processFiles(orderedFiles, storeUid).catch(error => { console.error('DICOM import failed', error); }); } /** * Reorders files round-robin across their parent directories. Exported DICOM * folders keep one series per directory, so this makes every imported series * show up in the staging table early instead of after the previous series. */ interleaveByDirectory(files) { const groups = new Map(); for (const file of files) { const path = file.webkitRelativePath || file.name; const directory = path.slice(0, path.lastIndexOf('/') + 1); const group = groups.get(directory); if (group) { group.push(file); } else { groups.set(directory, [file]); } } if (groups.size <= 1) return files; const buckets = [...groups.values()]; const interleaved = []; let round = 0; while (interleaved.length < files.length) { for (const bucket of buckets) { const file = bucket[round]; if (file) interleaved.push(file); } round += 1; } return interleaved; } processFiles(files, storeUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const targetStoreUid = storeUid ?? (yield _this.storeList.resolveStoreUid()); let parsedCount = 0; let nextIndex = 0; const importFromQueue = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { while (nextIndex < files.length) { const index = nextIndex++; const file = files[index]; if (!file) continue; try { const { buffer } = yield _this.readFileBuffer(file, index); _this.updateProgress(index, file.size); yield _this.arrayBufferToDicomWebJson(buffer, file, targetStoreUid); } catch (error) { // A file that became unreadable after selection must not abort the // remaining queue or leave the progress stuck below 100. console.error(`Failed to import ${file.name}`, error); _this.updateProgress(index, file.size); } parsedCount += 1; _this.parseProgress.set(Math.round(parsedCount / files.length * 100)); } }); return function importFromQueue() { return _ref.apply(this, arguments); }; }(); yield Promise.all(Array.from({ length: Math.min(PARALLEL_FILE_IMPORTS, files.length) }, importFromQueue)); } finally { _this.isImporting.set(false); } })(); } readFileBuffer(file, index) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const stream = file.stream?.(); if (!stream) { const buffer = yield file.arrayBuffer(); _this2.updateProgress(index, file.size); return { buffer, file, relativePath: file.webkitRelativePath || file.name }; } const reader = stream.getReader(); const chunks = []; let loaded = 0; while (true) { const { done, value } = yield reader.read(); if (done) break; if (value) { chunks.push(value); loaded += value.byteLength; _this2.updateProgress(index, Math.min(loaded, file.size)); } } const totalLength = chunks.reduce((total, chunk) => total + chunk.byteLength, 0); const combined = new Uint8Array(totalLength); let offset = 0; for (const chunk of chunks) { combined.set(chunk, offset); offset += chunk.byteLength; } return { buffer: combined.buffer, file, relativePath: file.webkitRelativePath || file.name }; })(); } updateProgress(index, loaded) { this.fileProgress[index] = loaded; const uploadedBytes = this.fileProgress.reduce((total, currentFileBytes) => total + currentFileBytes, 0); this.uploadProgress.set(this.totalBytes > 0 ? Math.round(uploadedBytes / this.totalBytes * 100) : 0); } arrayBufferToDicomWebJson(buffer, file, storeUid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const { metadata, naturalDataset } = yield _this3.parseInWorker(buffer); const seriesUid = naturalDataset.SeriesInstanceUID; const sopUid = naturalDataset.SOPInstanceUID; const studyUid = naturalDataset.StudyInstanceUID; if (!seriesUid || !sopUid || !studyUid) { return; } const seriesCollection = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this3.rxdbManager.dicomSeries$); const dicomSeries = { createdAt: Date.now(), id: (0,_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__.dicomSeriesId)(storeUid, seriesUid), institutionName: naturalDataset.InstitutionName, modality: naturalDataset.Modality ?? undefined, patientID: naturalDataset.PatientID ?? undefined, patientName: naturalDataset.PatientName?.[0]?.Alphabetic ?? undefined, seriesDate: naturalDataset.SeriesDate ?? naturalDataset['00080021'], seriesDescription: naturalDataset.SeriesDescription, seriesInstanceUID: seriesUid, seriesNumber: naturalDataset.SeriesNumber, storeUid, studyDate: naturalDataset.StudyDate ?? naturalDataset['00080020'], studyDescription: naturalDataset.StudyDescription, studyInstanceUID: studyUid }; yield seriesCollection.insertIfNotExists(dicomSeries); const instancesCollection = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this3.rxdbManager.dicomInstances$); const instance = { createdAt: Date.now(), id: (0,_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__.dicomInstanceId)(storeUid, sopUid), instanceNumber: naturalDataset.InstanceNumber, metadata, seriesUid, sopInstanceUID: sopUid, storeUid, studyUid, syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.RxDBSyncStatus.LOCAL }; let dicomDocument = yield instancesCollection.insertIfNotExists(instance); if (dicomDocument.syncStatus !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.RxDBSyncStatus.LOCAL) { dicomDocument = yield dicomDocument.incrementalPatch({ syncStatus: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.RxDBSyncStatus.LOCAL }); } const fileBuffer = yield file.arrayBuffer(); yield dicomDocument.putAttachment({ data: (0,_rxdb_attachment_binary__WEBPACK_IMPORTED_MODULE_7__.toRxdbAttachmentBinary)(fileBuffer), id: 'pixelData', type: 'application/dicom' }); } catch (error) { console.error('DICOM parse error', error); return; } })(); } parseInWorker(buffer) { return new Promise((resolve, reject) => { const id = crypto.randomUUID(); this.pendingRequests.set(id, { reject, resolve }); this.worker.postMessage({ buffer, id }, [buffer]); }); } static ɵfac = function DicomImportService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomImportService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: DicomImportService, factory: DicomImportService.ɵfac }); } /***/ }, /***/ 55643 /*!*****************************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/dicom-store-list.service.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DicomStoreListService: () => (/* binding */ DicomStoreListService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils/injection-tokens/env-injection-token */ 42035); /* harmony import */ var _preferences_preferences_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../preferences/preferences.service */ 4508); class DicomStoreListService { http = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpClient); environment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_4__.ENV); preferences = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_preferences_preferences_service__WEBPACK_IMPORTED_MODULE_5__.PreferencesService); enabledStores; /** Enabled stores only, sorted by `name`. Cached across the session. */ getEnabledStores() { this.enabledStores ??= this.fetchEnabledStores().catch(error => { this.enabledStores = undefined; throw error; }); return this.enabledStores; } /** * The persisted store if it is still enabled, otherwise the first enabled store. */ resolveStoreUid() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const stores = yield _this.getEnabledStores(); const persisted = _this.preferences.get().storeUid; if (persisted && stores.some(store => store.uid === persisted)) return persisted; const first = stores[0]; if (!first) throw new Error('No enabled DICOM store available.'); return first.uid; })(); } /** * Enabled stores that also respond to a ping — safe to show in store-selection UI. * Not cached: reachability can change between opens. */ getReachableStores() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const enabled = yield _this2.getEnabledStores(); const results = yield Promise.allSettled(enabled.map(store => (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this2.http.get(`${_this2.environment.apiUrl}/dicom/stores/${store.uid}/ping`)))); return enabled.filter((_, index) => { const result = results[index]; return result?.status === 'fulfilled' && result.value.reachable; }); })(); } /** * Store-wide statistics for one store. Not cached: contents change with imports. */ getStoreStatistics(storeUid) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(this.http.get(`${this.environment.apiUrl}/dicom/stores/${storeUid}/stats`)); } fetchEnabledStores() { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const stores = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this3.http.get(`${_this3.environment.apiUrl}/v1/dicom-store`)); return stores.filter(store => store.enabled).map(({ enabled, name, uid, url, vendor }) => ({ enabled, name, uid, url, vendor })).toSorted((a, b) => a.name.localeCompare(b.name)); })(); } static ɵfac = function DicomStoreListService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomStoreListService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: DicomStoreListService, factory: DicomStoreListService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 68453 /*!*****************************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/rendering-engine.service.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RenderingEngineService: () => (/* binding */ RenderingEngineService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @cornerstonejs/core */ 70611); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @cornerstonejs/core */ 50600); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @cornerstonejs/core */ 77569); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @cornerstonejs/core */ 38277); /* harmony import */ var _cornerstonejs_core_enums__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @cornerstonejs/core/enums */ 15247); /* harmony import */ var _kitware_vtk_js_Common_DataModel_DataSet_Constants__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/DataSet/Constants */ 78865); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_post_process__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/post-process */ 16352); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils */ 49585); const DEFAULT_HIT_RADIUS = 5; class RenderingEngineService { cornerstoneInit = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.CornerstoneInitService); cornerstoneRenderingEngine; viewportsReady = false; volumeLoaded = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "volumeLoaded" }] : [])); /** One pipeline per offscreen render window. Cornerstone shares * render windows across viewports, so the key is the window. */ pipelines = new Map(); setViewportsReady() { this.viewportsReady = true; } constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.DestroyRef).onDestroy(() => { this.destroy(); }); } init() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this.viewportsReady = false; _this.destroy(); yield _this.cornerstoneInit.ensureInitialized(); })(); } ENGINE_ID = 'tomoverse-rendering-engine'; enable(element, options) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this2.cornerstoneRenderingEngine = _this2.cornerstoneRenderingEngine ?? (0,_cornerstonejs_core__WEBPACK_IMPORTED_MODULE_4__.getRenderingEngine)(_this2.ENGINE_ID) ?? new _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_2__["default"](_this2.ENGINE_ID); const { id: viewportId, volumeId } = options; const viewportInput = { defaultOptions: { background: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.cssVariableToNormalizedRgb)('--p-app-viewport-background'), suppressEvents: true // Prevent cornerstone from handling keyboard/mouse events }, element, type: options?.type ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportType.ORTHOGRAPHIC, viewportId }; const existing = _this2.getViewport(viewportId); if (existing?.element === element) return; _this2.cornerstoneRenderingEngine.enableElement(viewportInput); const viewport = _this2.getViewport(viewportId); if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.isBaseVolumeViewportLike)(viewport)) { _this2.configureHardwareSelector(viewport); yield viewport.setVolumes([{ volumeId }]); // The 3D viewport hosts vascular/endo rendering and scalar masking, // which needs vtk.js's stock multi-input volume mapper. // Cornerstone installs its streaming mapper by default, so swap it here. if (options?.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportType.VOLUME_3D) { for (const { actor } of viewport.getActors()) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.swapToStandardVolumeMapper)(actor); } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.installTransparentSampleEarlyOut)(viewport); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyVolume3dSampleDistance)(viewport); } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.initAnnotationOverlay)(viewport); } _this2.installPostProcessPipelineFor(viewportId); })(); } /** Append a `PostProcessPipeline` after vtk.js's `vtkForwardPass`, * with the outline pass installed. */ installPostProcessPipelineFor(viewportId) { const renderWindow = this.getRenderWindow(viewportId); if (!renderWindow) return; if (this.pipelines.has(renderWindow)) return; const pipeline = _tomoverse_post_process__WEBPACK_IMPORTED_MODULE_9__.vtkPostProcessPipeline.newInstance(); pipeline.addPass(new _tomoverse_post_process__WEBPACK_IMPORTED_MODULE_9__.OutlineEffectPass()); if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.getDebugFlagByName)('postProcess')) { pipeline.addPass(new _tomoverse_post_process__WEBPACK_IMPORTED_MODULE_9__.MaskPreviewPass()); } renderWindow.setRenderPasses([...renderWindow.getRenderPasses(), pipeline]); this.pipelines.set(renderWindow, pipeline); } /** Returns every installed pass with the given id across all active pipelines. */ getPostProcessPassesById(id) { const passes = []; for (const pipeline of this.pipelines.values()) { const pass = pipeline.getPass(id); if (pass) passes.push(pass); } return passes; } renderAll() { this.cornerstoneRenderingEngine?.render(); } renderViewports(viewportIds) { if (viewportIds.length === 0) return; this.cornerstoneRenderingEngine?.renderViewports(viewportIds); } disable(viewportId) { this.cornerstoneRenderingEngine?.disableElement(viewportId); } updateMPRWindow(windowWidth, windowLevel, render = true) { if (!this.cornerstoneRenderingEngine) return; const mprViewports = this.cornerstoneRenderingEngine.getViewports().filter(viewport => { return viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportType.PERSPECTIVE || viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportType.ORTHOGRAPHIC; }); for (const viewport of mprViewports) { if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.isBaseVolumeViewportLike)(viewport)) break; this.applyVOI(viewport, windowWidth, windowLevel); } if (render) this.renderAll(); } updateVolume3dViewportWindow({ brightness, lighting, presetName, render, threshold, thresholds, volume3dViewport, widths }) { if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.isBaseVolumeViewportLike)(volume3dViewport)) return; switch (presetName) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.VolumeRenderingOption.ENDO: { this.applyEndoPreset(volume3dViewport, presetName, thresholds, render, lighting, widths); return; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.VolumeRenderingOption.FLUOROSCOPIC: { this.applyFluoroscopicPreset(volume3dViewport, presetName, false, threshold, brightness); return; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.VolumeRenderingOption.MIP: { this.applyMipPreset(volume3dViewport, presetName, threshold, brightness, render); return; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.VolumeRenderingOption.VASCULAR: { if (thresholds !== undefined) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyVascularPresetToViewport)(volume3dViewport, thresholds.tissueBloodThreshold, thresholds.bloodCalciumThreshold, thresholds.outlierOpacity ?? 0, render, lighting, widths?.opacityTransitionWidth); } return; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.VolumeRenderingOption.XRAY: { this.applyFluoroscopicPreset(volume3dViewport, presetName, true, threshold, brightness); return; } } if (render) volume3dViewport.render(); } applyEndoPreset(viewport, presetName, thresholds, render, lighting, widths) { if (thresholds?.airTissueThreshold === undefined) { this.applyPreset(viewport.id, presetName, render); return; } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyEndoPresetToViewport)(viewport, thresholds.airTissueThreshold, thresholds.tissueBloodThreshold, thresholds.bloodCalciumThreshold, render, lighting, widths?.opacityTransitionWidth, widths?.rgbTransitionWidth); } destroy() { if (this.cornerstoneRenderingEngine) { // Cornerstone calls registered widgets back mid-destroy, after the context pool // they need is gone; a throw there strands the engine in its global cache. for (const viewport of this.cornerstoneRenderingEngine.getViewports()) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.detachAnnotationOverlay)(viewport); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.clearViewportWidgets)(viewport); } this.cornerstoneRenderingEngine.destroy(); this.cornerstoneRenderingEngine = undefined; } for (const pipeline of this.pipelines.values()) pipeline.delete(); this.pipelines.clear(); _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_5__["default"].purgeCache(); } getWorldPosition(viewportId, screenPos) { const viewport = this.getViewport(viewportId); if (!viewport) return; return viewport.canvasToWorld(screenPos); } /** Projects a world point to canvas coordinates. * Inverse of canvasToWorld on the click plane */ worldToCanvas(viewportId, worldPos) { return this.getViewport(viewportId)?.worldToCanvas(worldPos); } /** World-space pick ray. Branches on viewport type. */ getWorldRay(viewportId, screenPos) { const viewport = this.getViewport(viewportId); if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"]) return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.rayFromCamera)(viewport, screenPos); const mpr = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.getMprViewport)(viewport); return mpr ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.rayFromSlicePlane)(mpr, screenPos) : undefined; } /** Returns the t-parameter range for valid intersection points along an MPR slab ray. Returns undefined for 3D viewports. */ getSliceTRange(viewportId, zeroSlabEpsilon = 0.5) { const viewport = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.getMprViewport)(this.getViewport(viewportId)); if (!viewport) return undefined; const thickness = viewport.getSlabThickness?.() ?? 0; const half = thickness > 0 ? thickness / 2 : zeroSlabEpsilon; return [-half, half]; } /** Returns the right and up unit vectors that span the MPR slab plane. Returns undefined for 3D viewports. */ cameraSlabPlaneAxes(viewportId) { const viewport = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.getMprViewport)(this.getViewport(viewportId)); return viewport ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.slabAxesForViewport)(viewport) : undefined; } /** True when a viewport canvas's size no longer matches its CSS size * devicePixelRatio. * * DPR belongs to the display, not the window (OS scale change, move to a differently-scaled * monitor), so it can change without a usable `resize` event. */ hasStaleCanvasResolution() { const dpr = window.devicePixelRatio || 1; return this.getActiveViewports().some(({ canvas }) => { if (!canvas || canvas.clientWidth === 0 || canvas.clientHeight === 0) return false; return Math.abs(canvas.width - canvas.clientWidth * dpr) > 1 || Math.abs(canvas.height - canvas.clientHeight * dpr) > 1; }); } resetCameraForResize() { // `vtkOffscreenMultiRenderWindow.resize()` does an unguarded render // that bypasses cornerstone's per-pass widget toggling. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.silenceAnnotationOverlays)(); this.cornerstoneRenderingEngine?.resize(true, true); this.fixActorMappers(); // Cornerstone re-tiles its offscreen canvas on resize — each primary // renderer gets a new viewport rectangle, so overlays must follow. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.resyncAnnotationOverlayViewports)(this.getActiveViewports()); } fixActorMappers() { // When the rendering engine resizes, the existing vtkMapper instances // stop working and all actors disappear. // This appears to be because Cornerstone created a new WebGL context internally, // so we have to mark the mappers/actors as modified to refresh them. for (const viewport of this.getActiveViewports()) { const actors = [...viewport.getActors().map(entry => entry.actor), ...(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.getAnnotationActors)(viewport.id)]; for (const actor of actors) { const mapper = actor.getMapper(); if (mapper) { mapper.modified(); actor.modified(); } } } } /** hitRadius defaults to the standard pick tolerance - callers pass a larger value to * widen the search window for a specific target (see AnnotationCreateInteraction/ * HoverInteraction's closed-spline first-point checks). */ getScreenPositionActor(viewportId, screenPos, hitRadius = DEFAULT_HIT_RADIUS) { if (!this.viewportsReady) return undefined; const viewport = this.getViewport(viewportId); if (!viewport) return undefined; // Offset mousePos to the viewport's location on the offscreen canvas. // Also account for devicePixelRatio for different devices/zoom levels. const dpr = window.devicePixelRatio || 1; const [vtkX, vtkY] = [Math.floor(screenPos[0] * dpr + viewport.sx), Math.floor(viewport.sHeight - screenPos[1] * dpr + viewport.sy) // Flip y ]; const view = viewport.getRenderer().getRenderWindow().getInteractor().getView(); const selector = view.getSelector(); selector.setArea([vtkX - hitRadius, vtkY - hitRadius, vtkX + hitRadius, vtkY + hitRadius]); const overlayActor = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.pickFromOverlay)(viewportId, selector, view, vtkX, vtkY, hitRadius); if (overlayActor) return overlayActor; if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"]) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.pickFromVolume3DPrimary)(viewport, selector, view, vtkX, vtkY, hitRadius); } return undefined; } getActiveViewports() { return this.cornerstoneRenderingEngine?.getViewports() ?? []; } /** * Rebind each base-volume viewport to a different volume (a phase swap) without rendering, so the * caller can re-apply render settings before the first paint and avoid a flash of reset state. */ setActiveVolume(volumeIds) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const updates = _this3.getActiveViewports().filter(viewport => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.isBaseVolumeViewportLike)(viewport)).map(viewport => { const volumeId = viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"] ? volumeIds.volume3dId : volumeIds.mprVolumeId; return viewport.setVolumes([{ volumeId }], false); }); yield Promise.all(updates); // setVolumes recreates actors/mappers: the shared mapper comes back (GPU // vascular masking needs the stock one), shader replacements drop, and // sampling reverts to the half-voxel default — redo all three. for (const viewport of _this3.getActiveViewports()) { if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"]) { for (const { actor } of viewport.getActors()) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.swapToStandardVolumeMapper)(actor); } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.installTransparentSampleEarlyOut)(viewport); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyVolume3dSampleDistance)(viewport); } } })(); } getViewport(viewportId) { return this.cornerstoneRenderingEngine?.getViewport(viewportId); } getRenderWindow(viewportId) { const viewports = this.getActiveViewports(); if (!this.cornerstoneRenderingEngine || viewports.length === 0) return; const offscreenRenderWindow = this.cornerstoneRenderingEngine.getOffscreenMultiRenderWindow(viewportId ?? viewports[0]?.id); return offscreenRenderWindow.getOpenGLRenderWindow(); } waitForViewportIsReady(viewportId) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return new Promise(resolve => { const checkViewport = () => { const viewport = _this4.getViewportIfReady(viewportId); if (viewport) { resolve(viewport); } else { requestAnimationFrame(checkViewport); } }; checkViewport(); }); })(); } applyPreset(viewportId, selectedPreset, render = true) { const viewport = this.getViewport(viewportId); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"])) { console.warn('Not a VolumeViewport3D', viewportId); return; } viewport.setProperties({ preset: selectedPreset }); if (render) viewport.render(); } applyFluoroscopicPreset(viewport, presetName, isXray, threshold, brightness) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyFluoroscopicPresetToViewport)(viewport, presetName, isXray, threshold, brightness); } applyMipPreset(viewport, presetName, threshold, brightness, render) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.applyMipPresetToViewport)(viewport, presetName, threshold, brightness, render); } adjustClippingPlane(viewportId, proximalDistance, distalDistance) { if (proximalDistance <= distalDistance + 1) { return; } const viewport = this.getViewport(viewportId); if (!viewport || !(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"])) { console.warn('Viewport not found for adjusting clipping planes', viewportId); return; } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.adjustProximalAndDistalClippingPlanes)(viewport, proximalDistance, distalDistance); viewport.render(); } configureHardwareSelector(viewport) { const selector = viewport.getRenderer().getRenderWindow().getInteractor().getView().getSelector(); selector.setCaptureZValues(true); selector.setFieldAssociation(_kitware_vtk_js_Common_DataModel_DataSet_Constants__WEBPACK_IMPORTED_MODULE_7__.FieldAssociations.FIELD_ASSOCIATION_CELLS); } applyVOI(viewport, width, level) { const lower = level - width / 2; const upper = level + width / 2; viewport.setProperties({ voiRange: { lower, upper } }); } isViewportReady(viewportId) { return !!this.getViewportIfReady(viewportId); } getViewportIfReady(viewportId) { const viewport = this.getViewport(viewportId); if (viewport?.viewportStatus !== _cornerstonejs_core_enums__WEBPACK_IMPORTED_MODULE_6__["default"].RENDERED) { return; } return viewport; } static ɵfac = function RenderingEngineService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RenderingEngineService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: RenderingEngineService, factory: RenderingEngineService.ɵfac }); } /***/ }, /***/ 75826 /*!**************************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/study-search.provider.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ClientStudySearchProvider: () => (/* binding */ ClientStudySearchProvider), /* harmony export */ StudySearchProvider: () => (/* binding */ StudySearchProvider) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 46046); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 84356); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 27588); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _dicom_api_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./dicom-api.service */ 96269); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @angular/core */ 14975); class StudySearchProvider {} /** * Client-side adapter: fetches the whole store into memory once, then filters, sorts and slices each requested page from that cache * instantly. Aggregates are computed over the full filtered set. */ class ClientStudySearchProvider extends StudySearchProvider { api = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_dicom_api_service__WEBPACK_IMPORTED_MODULE_8__.DicomApiService); caches = new Map(); search(query) { return this.accumulate(query.storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_4__.map)(accumulated => toPage(accumulated, query))); } invalidate(storeUid) { if (storeUid) this.caches.delete(storeUid);else this.caches.clear(); } accumulate(storeUid) { let cached = this.caches.get(storeUid); if (!cached) { cached = (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.defer)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.from)(this.fetchAll(storeUid))).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.shareReplay)(1)); this.caches.set(storeUid, cached); } return cached; } /** One request for the whole store, the backend returns every study when no limit is sent. */ fetchAll(storeUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { rows, total } = yield _this.api.getStudies(storeUid); return { rows, truncated: total !== undefined && rows.length < total }; })(); } static ɵfac = /*@__PURE__*/(() => { let ɵClientStudySearchProvider_BaseFactory; return function ClientStudySearchProvider_Factory(__ngFactoryType__) { return (ɵClientStudySearchProvider_BaseFactory || (ɵClientStudySearchProvider_BaseFactory = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵgetInheritedFactory"](ClientStudySearchProvider)))(__ngFactoryType__ || ClientStudySearchProvider); }; })(); static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: ClientStudySearchProvider, factory: ClientStudySearchProvider.ɵfac }); } function withReviewStatus(rows, statuses) { return rows.map(row => { const reviewStatus = statuses?.get(row.studyInstanceUID) ?? 'none'; return { ...row, reviewStatus, reviewStatusRank: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_6__.reviewStatusRank)(reviewStatus) }; }); } function toPage(accumulated, query) { const rows = withReviewStatus(accumulated.rows, query.reviewStatuses); const filtered = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_7__.filterStudies)(rows, query.criteria); const sorted = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_7__.sortRows)(filtered, query.sort); const { limit, offset } = query.page; return { aggregates: { instanceSum: sumIfKnown(filtered, row => row.numberOfInstances), seriesSum: sumIfKnown(filtered, row => row.numberOfSeries) }, rows: sorted.slice(offset, offset + limit), total: filtered.length, truncated: accumulated.truncated }; } /** Sums a count over rows, or `undefined` when no row provides it (so the UI omits it, not shows 0). */ function sumIfKnown(rows, pick) { let sum; for (const row of rows) { const value = pick(row); if (value !== undefined) sum = (sum ?? 0) + value; } return sum; } /***/ }, /***/ 79950 /*!**************************************************************************!*\ !*** ./libs/data-access/src/lib/services/dicom/volume-loader.service.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VolumeLoaderService: () => (/* binding */ VolumeLoaderService), /* harmony export */ parseImageId: () => (/* binding */ parseImageId), /* harmony export */ separateSeriesPhases: () => (/* binding */ separateSeriesPhases) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncIterator_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncIterator.js */ 75105); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var dicom_parser__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! dicom-parser */ 99564); /* harmony import */ var dicom_parser__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(dicom_parser__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/types */ 25575); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); /* harmony import */ var _tomoverse_utils_cornerstone_cornerstone_core_token__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/utils/cornerstone/cornerstone-core.token */ 83283); /* harmony import */ var _tomoverse_utils_cornerstone_tomoverse_volume_scheme__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils/cornerstone/tomoverse-volume-scheme */ 3389); /* harmony import */ var _tomoverse_utils_dicom_dicom_image_loader_token__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/utils/dicom/dicom-image-loader.token */ 14007); /* harmony import */ var _tomoverse_utils_dicom_extract_window_metadata__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils/dicom/extract-window-metadata */ 1712); /* harmony import */ var _tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/utils/multiphase */ 71717); /* harmony import */ var _db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../db/dicom/dicom-database.service */ 30860); const IMAGE_SCHEME = 'tomoverse-dcm'; const IMAGE_ID_SEPARATOR = '|'; function buildImageId(storeUid, seriesUid, sopInstanceUID) { return `${IMAGE_SCHEME}:${[storeUid, seriesUid, sopInstanceUID].join(IMAGE_ID_SEPARATOR)}`; } function parseImageId(imageId) { const [storeUid, seriesUid, sopInstanceUID] = imageId.replace(`${IMAGE_SCHEME}:`, '').split(IMAGE_ID_SEPARATOR); if (!storeUid || !seriesUid || !sopInstanceUID) { throw new Error(`Invalid imageId: ${imageId}`); } return { seriesUid, sopInstanceUID, storeUid }; } // Pure (no cornerstone/prefetch) — reused by the pre-load modal. function buildVolumeSeriesPhases(entries) { const phaseInstances = entries.map(entry => ({ id: entry.imageId, metadata: entry.metadata, sortOrder: entry.sortOrder })); const metadataByImageId = new Map(entries.map(entry => [entry.imageId, entry.metadata])); const phases = (0,_tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__.separatePhases)(phaseInstances); if (phases.length > 1) { return { phases: phases.map(phase => ({ id: phase.id, identification: (0,_tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__.describePhase)(metadataByImageId.get(phase.memberIds[0] ?? '')), imageIds: phase.memberIds, label: phase.label, order: phase.order })), unseparable: false }; } const sortedEntries = entries.toSorted((a, b) => a.sortOrder - b.sortOrder); return { phases: [{ id: 'default:0', identification: (0,_tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__.describePhase)(sortedEntries[0]?.metadata), imageIds: sortedEntries.map(({ imageId }) => imageId), label: '1', order: 1 }], unseparable: (0,_tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__.looksMultiphase)(phaseInstances) }; } // Metadata-only (no prefetch); takes the root db so it runs before the viewer exists. function separateSeriesPhases(_x, _x2, _x3, _x4, _x5) { return _separateSeriesPhases.apply(this, arguments); } function _separateSeriesPhases() { _separateSeriesPhases = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (database, studyUid, seriesUid, storeUid, onInstance) { const entries = []; var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { for (var _iterator = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncIterator_js__WEBPACK_IMPORTED_MODULE_1__["default"])(database.streamSeriesMetadata(studyUid, seriesUid, storeUid)), _step; _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done; _iteratorAbruptCompletion = false) { const { instanceNumber, metadata, sopInstanceUID } = _step.value; { // imageId carries storeUid so the on-demand `loadImage` callback (which // only receives an imageId) fetches from the right store, and the // cornerstone metaDataManager is store-scoped. const imageId = buildImageId(storeUid, seriesUid, sopInstanceUID); onInstance?.(imageId, metadata); const metadataValue = metadata; const metadataInstanceNumber = (0,_tomoverse_utils_multiphase__WEBPACK_IMPORTED_MODULE_11__.toFiniteNumber)((0,_tomoverse_types__WEBPACK_IMPORTED_MODULE_5__.getTagValue)(metadataValue, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.DicomTagId.InstanceNumber)); entries.push({ imageId, metadata: metadataValue, sortOrder: (typeof instanceNumber === 'number' ? instanceNumber : undefined) ?? metadataInstanceNumber ?? entries.length }); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (_iteratorAbruptCompletion && _iterator.return != null) { yield _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return buildVolumeSeriesPhases(entries); }); return _separateSeriesPhases.apply(this, arguments); } function sopUidsForPhases(phases, selectedPhaseIds) { const selected = new Set(selectedPhaseIds); return phases.filter(phase => selected.has(phase.id)).flatMap(phase => phase.imageIds).map(imageId => parseImageId(imageId).sopInstanceUID); } class VolumeLoaderService { dicomImageLoader = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_dicom_dicom_image_loader_token__WEBPACK_IMPORTED_MODULE_9__.DICOM_IMAGE_LOADER); cornerstoneCore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_cornerstone_cornerstone_core_token__WEBPACK_IMPORTED_MODULE_7__.CORNERSTONE_CORE); datasets = new Map(); loadingTasks = new Map(); phaseLoadingTasks = new Map(); unseparableSeries = new Map(); activePrefetchCount = 0; customLoaderRegistered = false; dicomDatabaseService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_db_dicom_dicom_database_service__WEBPACK_IMPORTED_MODULE_12__.DicomDatabaseService); isCachingSource = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(false, ...(ngDevMode ? [{ debugName: "isCachingSource" }] : [])); init() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this.dicomImageLoader.init({ decodeConfig: { wasmUrlCodecCharls: './charlswasm_decode.wasm', wasmUrlCodecLibJpegTurbo8bit: './libjpegturbowasm_decode.wasm', wasmUrlCodecOpenJpeg: './openjpegwasm_decode.wasm', wasmUrlCodecOpenJph: './openjphjs.wasm' }, // @ToDo: Remove once Cornerstone fixes the custom webworker path issue: https://github.com/cornerstonejs/cornerstone3D/pull/1982 webWorkerFactory: () => { return new Worker(__webpack_require__.tu(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u("apps_viewer_src_cornerstone-image-decoder_worker_ts"), __webpack_require__.b))); } }); if (!_this.customLoaderRegistered) { _this.cornerstoneCore.volumeLoader.registerVolumeLoader(_tomoverse_utils_cornerstone_tomoverse_volume_scheme__WEBPACK_IMPORTED_MODULE_8__.TOMOVERSE_IMAGE_VOLUME_SCHEME, (volumeId, options) => _this.cornerstoneCore.cornerstoneStreamingImageVolumeLoader(volumeId, options)); _this.cornerstoneCore.imageLoader.registerImageLoader(IMAGE_SCHEME, imageId => ({ promise: _this.loadImage(imageId) })); _this.cornerstoneCore.metaData.addProvider((type, imageId) => { if (!imageId.startsWith(`${IMAGE_SCHEME}:`)) return; try { const dataSet = _this.datasets.get(imageId); if (!dataSet) return; return _this.dicomImageLoader.wadouri.metaData.metadataForDataset(type, imageId, dataSet); } catch { return; } }, 1000); _this.customLoaderRegistered = true; } })(); } getWindowMetadata(imageIds) { const firstImage = imageIds[0]; if (firstImage) { const firstImageMetadata = this.dicomImageLoader.wadors.metaDataManager.get(firstImage); return (0,_tomoverse_utils_dicom_extract_window_metadata__WEBPACK_IMPORTED_MODULE_10__.extractWindowMetadata)(firstImageMetadata, { level: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_6__.DEFAULT_WINDOW_PRESET.level, width: _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_6__.DEFAULT_WINDOW_PRESET.width }); } throw new Error('No images found. Make sure that images are loaded first.'); } streamSeriesCacheProgress(seriesUid, storeUid) { return this.dicomDatabaseService.streamSeriesCacheProgress(seriesUid, storeUid); } ensureImageIds(studyUid, seriesUid, storeUid) { const cacheKey = `${storeUid}:${studyUid}:${seriesUid}`; const existing = this.loadingTasks.get(cacheKey); if (existing) return existing; const phasePromise = this.ensureSeriesPhases(studyUid, seriesUid, storeUid); return this.loadingTasks.get(cacheKey) ?? phasePromise.then(phases => phases.flatMap(phase => phase.imageIds)); } /** * Separate a series into its phases (multiphase) or a single phase (everything else), registering * each instance's metadata as it streams. Caches the result; flags the series unseparable when it * looks multiphase but cannot be split. `selectedPhaseIds` scopes the prefetch to those phases. */ ensureSeriesPhases(studyUid, seriesUid, storeUid, selectedPhaseIds) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const cacheKey = `${storeUid}:${studyUid}:${seriesUid}`; const existing = _this2.phaseLoadingTasks.get(cacheKey); if (existing) return existing; const loadPromise = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { phases, unseparable } = yield separateSeriesPhases(_this2.dicomDatabaseService, studyUid, seriesUid, storeUid, (imageId, metadata) => _this2.dicomImageLoader.wadors.metaDataManager.add(imageId, metadata)); _this2.unseparableSeries.set(cacheKey, unseparable); // Warm the binary cache for the selected phases (all when none specified); don't block on it. const sopInstanceUIDs = selectedPhaseIds && selectedPhaseIds.length > 0 ? sopUidsForPhases(phases, selectedPhaseIds) : undefined; _this2.markPrefetchStarted(); _this2.dicomDatabaseService.prefetchInstanceBinaries(studyUid, seriesUid, storeUid, sopInstanceUIDs).catch(error => console.error('Series prefetch failed', error)).finally(() => _this2.markPrefetchFinished()); return phases; })(); // Mirror the in-flight work into loadingTasks so concurrent ensureImageIds() callers share it // (as flat image ids); both keys are cleared together below. _this2.phaseLoadingTasks.set(cacheKey, loadPromise); _this2.loadingTasks.set(cacheKey, loadPromise.then(phases => phases.flatMap(phase => phase.imageIds))); return loadPromise.finally(() => { _this2.phaseLoadingTasks.delete(cacheKey); _this2.loadingTasks.delete(cacheKey); }); })(); } /** Whether the last separation of this series found it multiphase but could not split it. */ wasSeriesUnseparable(studyUid, seriesUid, storeUid) { return this.unseparableSeries.get(`${storeUid}:${studyUid}:${seriesUid}`) ?? false; } markPrefetchStarted() { this.activePrefetchCount += 1; this.isCachingSource.set(true); } markPrefetchFinished() { this.activePrefetchCount = Math.max(0, this.activePrefetchCount - 1); this.isCachingSource.set(this.activePrefetchCount > 0); } /** * If `seriesUid` is a TOMOVERSE OT annotation export, reads the source CT series UID * (tag 0099,1004) and the list of CT instance UIDs (tag 0099,1005) from the single OT * instance. Returns undefined for normal CT series. * * Tags are read directly from the DICOM binary rather than WADO-RS metadata because * WADO-RS LO values are limited to 64 chars per component — a long backslash-joined * UID list would be truncated and only the first UID would survive indexing. */ resolveSourceInfo(studyUid, seriesUid, storeUid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instances = yield _this3.dicomDatabaseService.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid); const first = instances[0]; if (!first) return undefined; // Use public Manufacturer tag — always indexed in WADO-RS (unlike private creator tags). const meta = first.toJSON().metadata; if (String(meta?.['00080070']?.Value?.[0] ?? '').trim() !== 'Tomoverse Imaging') return undefined; // Read tags directly from the binary to avoid WADO-RS UT truncation. const binary = yield _this3.dicomDatabaseService.getBinary(first.sopInstanceUID, storeUid); const sourceSeriesUid = _this3.readSequenceItemTag(binary, 0x00_08, 0x11_15, 0x00_20, 0x00_0e); if (!sourceSeriesUid) return undefined; const sourceInstanceUids = new Set(_this3.readSequenceItemTags(binary, 0x00_08, 0x21_12, 0x00_08, 0x11_55)); return { sourceInstanceUids, sourceSeriesUid }; })(); } /** Parse a DICOM binary, returning undefined on failure. */ parseBinary(buffer) { try { return dicom_parser__WEBPACK_IMPORTED_MODULE_3___default().parseDicom(new Uint8Array(buffer)); } catch { return undefined; } } /** Decode element bytes to a trimmed string. */ decodeElement(dataSet, element) { return new TextDecoder().decode(dataSet.byteArray.slice(element.dataOffset, element.dataOffset + element.length)).replaceAll('\0', '').trim(); } elementKey(group, element) { return `x${(group * 0x1_00_00 + element).toString(16).padStart(8, '0')}`; } /** Read the first item of a sequence tag and return the value of a child tag. */ readSequenceItemTag(buffer, sqGroup, sqElement, childGroup, childElement) { const dataSet = this.parseBinary(buffer); if (!dataSet) return undefined; const itemSet = dataSet.elements[this.elementKey(sqGroup, sqElement)]?.items?.[0]?.dataSet; if (!itemSet) return undefined; const element = itemSet.elements[this.elementKey(childGroup, childElement)]; return element ? this.decodeElement(itemSet, element) : undefined; } /** Read a child tag value from every item in a sequence tag. */ readSequenceItemTags(buffer, sqGroup, sqElement, childGroup, childElement) { const dataSet = this.parseBinary(buffer); if (!dataSet) return []; const uids = []; for (const item of dataSet.elements[this.elementKey(sqGroup, sqElement)]?.items ?? []) { const itemSet = item.dataSet; if (!itemSet) continue; const element = itemSet.elements[this.elementKey(childGroup, childElement)]; if (element) uids.push(this.decodeElement(itemSet, element)); } return uids; } loadImage(imageId) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { sopInstanceUID, storeUid } = parseImageId(imageId); // getBinary's own network fetch queues on DicomDatabaseService's shared, single global // concurrency limit - no separate limiter needed here (see that limiter's comment for why // having two independently-sized ones was actually letting more fetches run at once, not // fewer). const buffer = yield _this4.dicomDatabaseService.getBinary(sopInstanceUID, storeUid); const blob = new Blob([buffer], { type: 'application/dicom' }); const file = new File([blob], `${sopInstanceUID}.dcm`, { type: 'application/dicom' }); const fileImageId = _this4.dicomImageLoader.wadouri.fileManager.add(file); const image = yield _this4.cornerstoneCore.imageLoader.loadAndCacheImage(fileImageId); return image; })(); } static ɵfac = function VolumeLoaderService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || VolumeLoaderService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: VolumeLoaderService, factory: VolumeLoaderService.ɵfac }); } /***/ }, /***/ 4508 /*!******************************************************************************!*\ !*** ./libs/data-access/src/lib/services/preferences/preferences.service.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PreferencesService: () => (/* binding */ PreferencesService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); const PREFERENCES_STORAGE_KEY = 'tvct.preferences'; /** * Generic localStorage-backed preferences store.. */ class PreferencesService { get() { try { const raw = localStorage.getItem(PREFERENCES_STORAGE_KEY); return raw ? JSON.parse(raw) : {}; } catch { return {}; } } patch(preferences) { try { const next = { ...this.get(), ...preferences }; localStorage.setItem(PREFERENCES_STORAGE_KEY, JSON.stringify(next)); } catch { // Ignore storage errors } } clear() { try { localStorage.removeItem(PREFERENCES_STORAGE_KEY); } catch { // Ignore storage errors } } static ɵfac = function PreferencesService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PreferencesService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: PreferencesService, factory: PreferencesService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 23974 /*!***************************************************************************!*\ !*** ./libs/data-access/src/lib/services/recent-work-sessions.service.ts ***! \***************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RecentWorkSessionsService: () => (/* binding */ RecentWorkSessionsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 69042); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/utils/constants */ 11280); /* harmony import */ var _db_work_session_work_session_database_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../db/work-session/work-session-database.service */ 17818); /* harmony import */ var _auth_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./auth.service */ 52807); /** * Tracks the last opened work sessions (capped at `MAX_RECENT_WORK_SESSIONS`). * Held in memory only and is cleared on sign-out so tabs can't leak into the next login. * Sessions whose local document is deleted are pruned automatically. */ class RecentWorkSessionsService { authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_auth_service__WEBPACK_IMPORTED_MODULE_8__.AuthService); destroyRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef); workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_db_work_session_work_session_database_service__WEBPACK_IMPORTED_MODULE_7__.WorkSessionDatabaseService); _sessions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "_sessions" }] : [])); sessions = this._sessions.asReadonly(); // Tracks when each session was last opened so eviction targets the least // recently opened tab while tab positions stay stable. Kept outside the // signal so re-opening an already tracked tab doesn't retrigger subscribers. lastOpenedSequence = new Map(); nextOpenedSequence = 0; constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { if (this.authService.isAuthenticated()) return; this.lastOpenedSequence.clear(); this._sessions.set([]); }); // Watch each tracked session's local document and drop the tab when the // document disappears. The app is offline-first, so a recorded session // always exists locally and an absent document means it was deleted. // Removing a uid re-runs the switchMap without it, so the feedback into // `_sessions` settles after one pass. (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_1__.toObservable)(this._sessions).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.switchMap)(references => (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.merge)(...references.map(reference => this.workSessionDb.get$(reference.workSessionUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_3__.filter)(session => !session), (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.map)(() => reference.workSessionUid))))), (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_1__.takeUntilDestroyed)(this.destroyRef)).subscribe(workSessionUid => this.remove(workSessionUid)); } /** * Register a session as opened. Already-tracked sessions keep their tab * position, new ones are appended. When full (MAX_RECENT_WORK_SESSIONS), * the least recently opened session is evicted. */ record(reference) { this.lastOpenedSequence.set(reference.workSessionUid, this.nextOpenedSequence++); const current = this._sessions(); if (current.some(session => session.workSessionUid === reference.workSessionUid)) return; let next = [...current, reference]; if (next.length > _tomoverse_utils_constants__WEBPACK_IMPORTED_MODULE_6__.MAX_RECENT_WORK_SESSIONS) { let evicted = reference; for (const session of next) { if (this.openedSequence(session) < this.openedSequence(evicted)) evicted = session; } this.lastOpenedSequence.delete(evicted.workSessionUid); next = next.filter(session => session !== evicted); } this._sessions.set(next); } remove(workSessionUid) { this.lastOpenedSequence.delete(workSessionUid); const current = this._sessions(); const next = current.filter(session => session.workSessionUid !== workSessionUid); if (next.length === current.length) return; this._sessions.set(next); } openedSequence(reference) { return this.lastOpenedSequence.get(reference.workSessionUid) ?? -1; } static ɵfac = function RecentWorkSessionsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecentWorkSessionsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: RecentWorkSessionsService, factory: RecentWorkSessionsService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 29039 /*!************************************************************************************!*\ !*** ./libs/data-access/src/lib/services/work-session/work-session-api.service.ts ***! \************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionApiService: () => (/* binding */ WorkSessionApiService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils/injection-tokens/env-injection-token */ 42035); class WorkSessionApiService { http = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpClient); environment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils_injection_tokens_env_injection_token__WEBPACK_IMPORTED_MODULE_4__.ENV); apiUrl = `${this.environment.apiUrl}/v1/work-session`; get(_x) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (workSessionId, fullAttachments = false) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this.http.get(`${_this.apiUrl}/${workSessionId}`, { params: fullAttachments ? { fullAttachments: true } : {} })); }).apply(this, arguments); } find() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (filters = {}) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this2.http.get(_this2.apiUrl, { params: filters })); }).apply(this, arguments); } create(workSession) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this3.http.post(_this3.apiUrl, workSession)); })(); } update(workSessionId, workSession) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this4.http.put(`${_this4.apiUrl}/${workSessionId}`, workSession)); })(); } delete(workSessionId) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(_this5.http.delete(`${_this5.apiUrl}/${workSessionId}`)); })(); } static ɵfac = function WorkSessionApiService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionApiService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineInjectable"]({ token: WorkSessionApiService, factory: WorkSessionApiService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 60923 /*!*******************************************************************************************!*\ !*** ./libs/data-access/src/lib/services/work-session/work-session-navigation.service.ts ***! \*******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionNavigationService: () => (/* binding */ WorkSessionNavigationService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../db/rxdb-manager.service */ 67189); class WorkSessionNavigationService { rxdbManager = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_db_rxdb_manager_service__WEBPACK_IMPORTED_MODULE_2__.RxdbManager); saveWorkSessionRequested = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "saveWorkSessionRequested" }] : [])); exportWorkSessionRequested = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "exportWorkSessionRequested" }] : [])); flushHandler; save() { this.saveWorkSessionRequested.update(v => v + 1); } export() { this.exportWorkSessionRequested.update(v => v + 1); } registerFlushHandler(handler) { this.flushHandler = handler; return () => { if (this.flushHandler === handler) this.flushHandler = undefined; }; } awaitPendingSync() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this.rxdbManager.awaitWorkSessionsInSync(); })(); } // Persists the live viewer state and waits for it to reach the backend. // Called before sign-out and window close; must never block them. flushPendingChanges() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { yield _this2.flushHandler?.(); yield _this2.awaitPendingSync(); } catch (error) { console.warn('Failed to flush pending work session changes', error); } })(); } static ɵfac = function WorkSessionNavigationService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionNavigationService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: WorkSessionNavigationService, factory: WorkSessionNavigationService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 99335 /*!***********************************************************************************!*\ !*** ./libs/data-access/src/lib/services/work-session/work-session-sse-client.ts ***! \***********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionSseClient: () => (/* binding */ WorkSessionSseClient) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs */ 57417); class WorkSessionSseClient { stream(url, options = {}) { var _this = this; const { authProbe, getToken, keepAlive = true, reconnectionDelay = 3000, responseType = 'text' } = options; return new rxjs__WEBPACK_IMPORTED_MODULE_1__.Observable(subscriber => { let eventSource; let reconnectTimer; let isDestroyed = false; let isConnecting = false; const _connect = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (isDestroyed || isConnecting) return; isConnecting = true; try { yield authProbe?.(); } catch (error) { isConnecting = false; subscriber.error(new Error('Auth probe failed', { cause: error })); return; } if (isDestroyed) { isConnecting = false; return; } const authenticatedUrl = _this.buildUrl(url, getToken?.()); eventSource = new EventSource(authenticatedUrl); eventSource.addEventListener('message', event => _this.handleMessage(event, responseType, subscriber)); eventSource.addEventListener('error', error => { eventSource?.close(); if (keepAlive && !isDestroyed) { reconnectTimer = setTimeout(_connect, reconnectionDelay); } else { subscriber.error(error); } }); isConnecting = false; }); return function connect() { return _ref.apply(this, arguments); }; }(); _connect(); return () => { isDestroyed = true; clearTimeout(reconnectTimer); eventSource?.close(); }; }); } buildUrl(baseUrl, token) { if (!token) return baseUrl; const url = new URL(baseUrl, globalThis.location.origin); url.searchParams.set('access_token', token); return url.toString(); } handleMessage(event, type, subscriber) { try { const data = type === 'json' ? JSON.parse(event.data) : event.data; subscriber.next(data); } catch (error) { subscriber.error(new Error(`Failed to parse SSE message: ${error}`)); } } } /***/ }, /***/ 78210 /*!******************************************************************!*\ !*** ./libs/domain/src/lib/selectors/annotation-measurements.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getBatchMeasurements: () => (/* binding */ getBatchMeasurements), /* harmony export */ getMeasurements: () => (/* binding */ getMeasurements) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./annotation-selectors */ 66817); /* harmony import */ var _spline_selectors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./spline-selectors */ 28713); function getBatchMeasurements(annotations, volume) { return Object.fromEntries(Object.entries(annotations).map(([id, annotation]) => { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationHasRelationship)(annotation)) { return [id, getMeasurements(annotation, volume, ...annotation.relationship.sourceIds.map(sId => annotations[sId]))]; } return [id, getMeasurements(annotation, volume)]; })); } // Passing in `IImageVolume` instead of raw voxel data for better memoization. const getMeasurements = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.memoizeByReference)((annotation, volume, ...parents) => { switch (annotation.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE: { return getAngleMeasurements(annotation); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE: { return getClosedSplineMeasurements(annotation); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CYLINDER: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.HOLLOW_CYLINDER: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.STL: { return getObject3DMeasurements(annotation); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE: { return getDistanceMeasurements(annotation); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.OPEN_SPLINE: { return getOpenSplineMeasurements(annotation, parents); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT: { return getPointMeasurements(annotation, volume, parents); } } }, // Can key by just `annotation` even though there are multiple args, // any changes to those will be caught in the reference check _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getId); function getAngleMeasurements(angle) { return [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.ANGLE, value: `${(0,_annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getAngle)(angle).toFixed(1).replace('.0', '')}°` }]; } function getPointMeasurements(point, volume, parents) { const position = (0,_annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getPosition)(point); const measurements = [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.POSITION, value: formatPosition(position) }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.PIXEL_VALUE, value: volume ? `${getVolumeValue(volume, point.position).toString()} HU` : '0 HU' }]; if (point.relationship?.type === 'curvature-point') { const spline = parents[0]; if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsSpline)(spline)) { measurements.push({ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.POSITION_ALONG_SPLINE, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getDistanceAtPosition)(spline, position)) }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.RADIUS_OF_CURVATURE, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getCurvatureRadiusAtPosition)(spline, position)) }); } } return measurements; } function getClosedSplineMeasurements(spline) { const perimeter = (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getSplineLength)(spline); const pDerivedDiameter = perimeter / Math.PI; const area = (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getClosedSplineArea)(spline); const aDerivedDiameter = 2 * Math.sqrt(area / Math.PI); return [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.PERIMETER, value: `${formatMM(perimeter)} (⌀ ${formatMM(pDerivedDiameter)})` }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.AREA, value: `${formatMM(area)}² (⌀ ${formatMM(aDerivedDiameter)})` }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.MAXIMUM_DIAMETER, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getClosedSplineMaximumDiameter)(spline)) }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.HEIGHT, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getClosedSplineHeight)(spline)) }, { name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.EN_FACE_VIEW, value: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.formatAngulationtxt)((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getClosedSplineEnFaceView)(spline), false) }]; } function getOpenSplineMeasurements(spline, parents) { const measurements = [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.LENGTH, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getSplineLength)(spline)) }]; if (spline.relationship?.type === 'attached-spline' && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsOpenSpline)(parents[0]) && spline.points[0]) { measurements.unshift({ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.BIFURCATION_POSITION, value: formatMM((0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getDistanceAtPosition)(parents[0], spline.points[0])) }); } return measurements; } function getDistanceMeasurements(distance) { return [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.DISTANCE, value: formatMM((0,_annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getDistance)(distance)) }]; } function getObject3DMeasurements(object3d) { return [{ name: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.MeasurementName.EN_FACE_VIEW, value: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.formatAngulationtxt)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.angulationFromOrientation)(object3d.orientation), false) }]; } function getVolumeValue(volume, position) { try { const ijkCoords = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.worldToIndex)(volume, [...position]); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.getAtIJK)(volume, Math.round(ijkCoords[0]), Math.round(ijkCoords[1]), Math.round(ijkCoords[2])) ?? 0; } catch { // There are occasional race conditions where reads can fail return 0; } } function formatPosition(position) { const [x, y, z] = position; return `(${x.toFixed(1).replace('.0', '')}, ${y.toFixed(1).replace('.0', '')}, ${z.toFixed(1).replace('.0', '')}) mm`; } function formatMM(value) { return `${value.toFixed(1).replace('.0', '')} mm`; } /***/ }, /***/ 66817 /*!***************************************************************!*\ !*** ./libs/domain/src/lib/selectors/annotation-selectors.ts ***! \***************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getAngle: () => (/* binding */ getAngle), /* harmony export */ getCentroid: () => (/* binding */ getCentroid), /* harmony export */ getDistance: () => (/* binding */ getDistance), /* harmony export */ getDistanceNormal: () => (/* binding */ getDistanceNormal), /* harmony export */ getId: () => (/* binding */ getId), /* harmony export */ getNormal: () => (/* binding */ getNormal), /* harmony export */ getPath: () => (/* binding */ getPath), /* harmony export */ getPosition: () => (/* binding */ getPosition), /* harmony export */ getValid: () => (/* binding */ getValid), /* harmony export */ isRenderable: () => (/* binding */ isRenderable) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _spline_selectors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./spline-selectors */ 28713); /** * Return the centroid of the provided annotation. * @param annotation * @returns */ function getCentroid(annotation) { if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.POINT) { return annotation.position; } if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.DISTANCE) { const [start, end] = annotation.points; return [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2, (start[2] + end[2]) / 2]; } if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.ANGLE) { return (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getTriangleCentroid)(annotation.points); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsSpline)(annotation)) { return (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getSplineCentroid)(annotation); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsObject3D)(annotation)) { return annotation.position; } return [0, 0, 0]; } function getNormal(annotation) { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationHasPoints)(annotation)) { const points = annotation.points; if (points.length < 3) { return getDistanceNormal(points[0], points[1]); } const p0 = points[0]; let nx = 0, ny = 0, nz = 0; for (let index = 1; index < points.length - 1; index++) { const [p1, p2] = [points[index], points[index + 1]]; if (!p1 || !p2 || !p0) continue; // Vectors from p0 const v1 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]); const v2 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]); // Cross product v1 × v2 const cross = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(cross, v1, v2); nx += cross[0]; ny += cross[1]; nz += cross[2]; } // Normalize the result const length = Math.hypot(nx, ny, nz); if (length === 0) { throw new Error('Points do not form a valid plane'); } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.position)(nx / length, ny / length, nz / length); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsObject3D)(annotation)) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.object3dSymmetryAxis)(annotation.orientation, (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsStl)(annotation) ? annotation.axisOfSymmetryRotation : undefined); } return undefined; } function getDistanceNormal(p0, p1) { // direction vector const direction = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]); const directionLength = Math.hypot(direction[0], direction[1], direction[2]); if (directionLength === 0) { throw new Error('Points must be different'); } // Normalize direction const d = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(direction[0] / directionLength, direction[1] / directionLength, direction[2] / directionLength); // choose a reference vector not parallel to d let reference = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(0, 0, 1); const dot = d[0] * reference[0] + d[1] * reference[1] + d[2] * reference[2]; if (Math.abs(dot) > 0.9) { reference = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.fromValues(0, 1, 0); } // cross product → perpendicular const perp = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(perp, d, reference); // Step 4: normalize result const length = Math.hypot(perp[0], perp[1], perp[2]); return [perp[0] / length, perp[1] / length, perp[2] / length]; } /** * Return the position of the provided annotation. * @param annotation * @returns */ function getPosition(annotation) { return annotation.position; } /** * Return the id of the provided annotation. * @param annotation * @returns */ function getId(annotation) { return annotation.id; } /** * Return the distance value between a Distance's start and end points. */ const getDistance = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(distance => { const [start, end] = distance.points; if (start === undefined || end === undefined) { return 0; } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateDistanceBetweenPoints)(start, end); }, getId); /** * Return the angle value between an Angle's line [a, b] and [b, c] line segments. */ const getAngle = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(angle => { const [start, center, end] = angle.points; if (!start || !center || !end) { return 0; } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateAngleBetweenPoints)(start, center, end); }, getId); /** * Return whether the provided annotation is valid, eg. whether it is * complete and can be added to the collection. */ // eslint-disable-next-line sonarjs/cyclomatic-complexity function getValid(annotation) { switch (annotation.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.ANGLE: { return annotation.points.length === 3; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.CLOSED_SPLINE: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.OPEN_SPLINE: { return annotation.points.length > 1; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.CYLINDER: { return annotation.diameter > 0 && annotation.height > 0 && annotation.sides >= 3 && isFiniteQuat(annotation.orientation) && isFinitePosition(annotation.position); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.DISTANCE: { return annotation.points.length === 2; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.HOLLOW_CYLINDER: { return annotation.height > 0 && annotation.innerDiameter > 0 && annotation.outerDiameter > annotation.innerDiameter && annotation.sides >= 3 && isFiniteQuat(annotation.orientation) && isFinitePosition(annotation.position); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.POINT: { return true; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.STL: { return annotation.fileName.length > 0 && isFiniteQuat(annotation.orientation) && annotation.axisOfSymmetryRotation.length === 16 && annotation.axisOfSymmetryRotation.every(element => Number.isFinite(element)) && isFinitePosition(annotation.position); } } } /** * Return whether the provided annotation is able to be rendered correctly. * @param annotation * @returns */ const isRenderable = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(annotation => { // Uninitialized points are generally present in incomplete annotation, // or certain invalid states (eg. "Angle between splines" with parallel splines.) if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationHasPoints)(annotation)) { return !annotation.points.some(point => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.positionIsUninitialized)(point)); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationHasPosition)(annotation)) { return !(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.positionIsUninitialized)(annotation.position); } return true; }, getId); const getPath = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(annotation => { switch (annotation.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.ANGLE: { const [start, middle, end] = annotation.points; if (!start || !middle || !end) { return annotation.points; } const pathA = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateSplinePath)([start, middle], false); const [, ...pathB] = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateSplinePath)([middle, end], false); return [...pathA, ...pathB]; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.CLOSED_SPLINE: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.OPEN_SPLINE: { return (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_4__.getSplinePath)(annotation); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.DISTANCE: { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateSplinePath)(annotation.points, false); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.POINT: { return [annotation.position]; } default: { return []; } } }, getId); function isFiniteQuat(q) { return q.length === 4 && q.every(element => Number.isFinite(element)); } function isFinitePosition(p) { return p.length === 3 && p.every(element => Number.isFinite(element)); } /***/ }, /***/ 26172 /*!****************************************************************!*\ !*** ./libs/domain/src/lib/selectors/dicom-store-selectors.ts ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ STORE_TYPE_ORDER: () => (/* binding */ STORE_TYPE_ORDER), /* harmony export */ storeTypeForVendor: () => (/* binding */ storeTypeForVendor) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /** Fixed display order of store groups in store-selector menus. */ const STORE_TYPE_ORDER = [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.StoreType.CLOUD, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.StoreType.DIMSE, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.StoreType.DICOM_WEB]; /** * Connection category for a vendor. */ function storeTypeForVendor(vendor) { switch (vendor) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.DicomVendor.GOOGLE_HEALTHCARE: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.DicomVendor.ORTHANC: { return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.StoreType.DICOM_WEB; } } } /***/ }, /***/ 27531 /*!************************************************!*\ !*** ./libs/domain/src/lib/selectors/index.ts ***! \************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ STORE_TYPE_ORDER: () => (/* reexport safe */ _dicom_store_selectors__WEBPACK_IMPORTED_MODULE_2__.STORE_TYPE_ORDER), /* harmony export */ canPlaceholderBeAutocreated: () => (/* reexport safe */ _placeholder_selectors__WEBPACK_IMPORTED_MODULE_4__.canPlaceholderBeAutocreated), /* harmony export */ canPlaceholderBeCompleted: () => (/* reexport safe */ _placeholder_selectors__WEBPACK_IMPORTED_MODULE_4__.canPlaceholderBeCompleted), /* harmony export */ canProceedFromProtocolForm: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.canProceedFromProtocolForm), /* harmony export */ compareBy: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.compareBy), /* harmony export */ compareValues: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.compareValues), /* harmony export */ createAnnotationFromPlaceholder: () => (/* reexport safe */ _placeholder_selectors__WEBPACK_IMPORTED_MODULE_4__.createAnnotationFromPlaceholder), /* harmony export */ filterStudies: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.filterStudies), /* harmony export */ getAngle: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getAngle), /* harmony export */ getBatchMeasurements: () => (/* reexport safe */ _annotation_measurements__WEBPACK_IMPORTED_MODULE_1__.getBatchMeasurements), /* harmony export */ getCentroid: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getCentroid), /* harmony export */ getClosedSplineArea: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getClosedSplineArea), /* harmony export */ getClosedSplineEnFaceView: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getClosedSplineEnFaceView), /* harmony export */ getClosedSplineHeight: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getClosedSplineHeight), /* harmony export */ getClosedSplineMaximumDiameter: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getClosedSplineMaximumDiameter), /* harmony export */ getCurvatureRadiusAtPosition: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getCurvatureRadiusAtPosition), /* harmony export */ getDistance: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getDistance), /* harmony export */ getDistanceAtPosition: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getDistanceAtPosition), /* harmony export */ getDistanceNormal: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getDistanceNormal), /* harmony export */ getGeometryOctree: () => (/* reexport safe */ _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__.getGeometryOctree), /* harmony export */ getId: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getId), /* harmony export */ getMeasurements: () => (/* reexport safe */ _annotation_measurements__WEBPACK_IMPORTED_MODULE_1__.getMeasurements), /* harmony export */ getNextPlaceholder: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.getNextPlaceholder), /* harmony export */ getNormal: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getNormal), /* harmony export */ getObject3DGeometry: () => (/* reexport safe */ _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DGeometry), /* harmony export */ getObject3DOctree: () => (/* reexport safe */ _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DOctree), /* harmony export */ getObject3DTransformMatrix: () => (/* reexport safe */ _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DTransformMatrix), /* harmony export */ getPath: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getPath), /* harmony export */ getPosition: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getPosition), /* harmony export */ getPreviousPlaceholder: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.getPreviousPlaceholder), /* harmony export */ getSCurveAngleDegrees: () => (/* reexport safe */ _s_curve_relative_measurement_selectors__WEBPACK_IMPORTED_MODULE_6__.getSCurveAngleDegrees), /* harmony export */ getSCurveEnFaceAngle: () => (/* reexport safe */ _s_curve_selectors__WEBPACK_IMPORTED_MODULE_7__.getSCurveEnFaceAngle), /* harmony export */ getSCurveIntersectionAngulation: () => (/* reexport safe */ _s_curve_relative_measurement_selectors__WEBPACK_IMPORTED_MODULE_6__.getSCurveIntersectionAngulation), /* harmony export */ getSCurveIntersectionPosition: () => (/* reexport safe */ _s_curve_relative_measurement_selectors__WEBPACK_IMPORTED_MODULE_6__.getSCurveIntersectionPosition), /* harmony export */ getSCurvePath: () => (/* reexport safe */ _s_curve_selectors__WEBPACK_IMPORTED_MODULE_7__.getSCurvePath), /* harmony export */ getSCurveSvgPath: () => (/* reexport safe */ _s_curve_selectors__WEBPACK_IMPORTED_MODULE_7__.getSCurveSvgPath), /* harmony export */ getSplineBestFitNormal: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getSplineBestFitNormal), /* harmony export */ getSplineCentroid: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getSplineCentroid), /* harmony export */ getSplineLength: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getSplineLength), /* harmony export */ getSplinePath: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getSplinePath), /* harmony export */ getTriangleCentroid: () => (/* reexport safe */ _spline_selectors__WEBPACK_IMPORTED_MODULE_8__.getTriangleCentroid), /* harmony export */ getValid: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.getValid), /* harmony export */ inDateRange: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.inDateRange), /* harmony export */ isProtocolComplete: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.isProtocolComplete), /* harmony export */ isProtocolEmpty: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.isProtocolEmpty), /* harmony export */ isProtocolFormValid: () => (/* reexport safe */ _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__.isProtocolFormValid), /* harmony export */ isRenderable: () => (/* reexport safe */ _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__.isRenderable), /* harmony export */ matchesAnyOf: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.matchesAnyOf), /* harmony export */ matchesReviewStatus: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.matchesReviewStatus), /* harmony export */ matchesText: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.matchesText), /* harmony export */ snapPositionToObject3D: () => (/* reexport safe */ _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__.snapPositionToObject3D), /* harmony export */ sortRows: () => (/* reexport safe */ _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__.sortRows), /* harmony export */ storeTypeForVendor: () => (/* reexport safe */ _dicom_store_selectors__WEBPACK_IMPORTED_MODULE_2__.storeTypeForVendor) /* harmony export */ }); /* harmony import */ var _annotation_selectors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./annotation-selectors */ 66817); /* harmony import */ var _annotation_measurements__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./annotation-measurements */ 78210); /* harmony import */ var _dicom_store_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dicom-store-selectors */ 26172); /* harmony import */ var _object3d_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./object3d-selectors */ 90180); /* harmony import */ var _placeholder_selectors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./placeholder-selectors */ 20333); /* harmony import */ var _protocol_selectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./protocol-selectors */ 47536); /* harmony import */ var _s_curve_relative_measurement_selectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./s-curve-relative-measurement-selectors */ 80263); /* harmony import */ var _s_curve_selectors__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./s-curve-selectors */ 95823); /* harmony import */ var _spline_selectors__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./spline-selectors */ 28713); /* harmony import */ var _study_search_selectors__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./study-search-selectors */ 96964); /***/ }, /***/ 90180 /*!*************************************************************!*\ !*** ./libs/domain/src/lib/selectors/object3d-selectors.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getGeometryOctree: () => (/* binding */ getGeometryOctree), /* harmony export */ getObject3DGeometry: () => (/* binding */ getObject3DGeometry), /* harmony export */ getObject3DOctree: () => (/* binding */ getObject3DOctree), /* harmony export */ getObject3DTransformMatrix: () => (/* binding */ getObject3DTransformMatrix), /* harmony export */ snapPositionToObject3D: () => (/* binding */ snapPositionToObject3D) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 95329); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_selectors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./annotation-selectors */ 66817); const getObject3DGeometry = (() => { let stlFetcher; const memo = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(annotation => { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.annotationIsCylinder)(annotation)) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.withShell)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateCylinderGeometry)(annotation.diameter / 2, annotation.height, annotation.sides)); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.annotationIsHollowCylinder)(annotation)) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.withShell)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.calculateHollowCylinderGeometry)(annotation.innerDiameter / 2, annotation.outerDiameter / 2, annotation.height, annotation.sides)); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.annotationIsStl)(annotation) && stlFetcher) { return stlFetcher(annotation); } throw new Error('Unsupported geometry request'); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_4__.getId); // eslint-disable-next-line @typescript-eslint/no-explicit-any memo.setStlFetcher = fetcher => { stlFetcher = fetcher; }; return memo; })(); const getObject3DOctree = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(annotation => { const geometry = getObject3DGeometry(annotation); return getGeometryOctree(geometry); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_4__.getId); // NOTE: We want to memoize at the Geometry level instead of Annotation because otherwise // we are going to rebuild the octree any time the annotation changes (movement, rotation, etc) const getGeometryOctree = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(geometry => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.buildOctree)(geometry)); function snapPositionToObject3D(point, geometry, geometryTransform, octree) { // Apply inverse translation/rotation to point so it is // local to the geometry const localPoint = gl_matrix__WEBPACK_IMPORTED_MODULE_1__.transformMat4(gl_matrix__WEBPACK_IMPORTED_MODULE_1__.create(), point, gl_matrix__WEBPACK_IMPORTED_MODULE_0__.invert(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), geometryTransform)); const projectedPoint = octree ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.projectPointOnOctree)(localPoint, geometry, octree) : (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.projectPointOnGeometry)(localPoint, geometry); // Bring the projected point back into world space. gl_matrix__WEBPACK_IMPORTED_MODULE_1__.transformMat4(projectedPoint, projectedPoint, geometryTransform); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.vec3ToPosition)(projectedPoint); } const getObject3DTransformMatrix = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.memoizeByReference)(object3d => { const geometry = getObject3DGeometry(object3d); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.buildObject3dTransform)(object3d, geometry.centroid); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_4__.getId); /***/ }, /***/ 20333 /*!****************************************************************!*\ !*** ./libs/domain/src/lib/selectors/placeholder-selectors.ts ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ canPlaceholderBeAutocreated: () => (/* binding */ canPlaceholderBeAutocreated), /* harmony export */ canPlaceholderBeCompleted: () => (/* binding */ canPlaceholderBeCompleted), /* harmony export */ createAnnotationFromPlaceholder: () => (/* binding */ createAnnotationFromPlaceholder) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Determines whether a placeholder's annotation can be created automatically, * based on the presence of a relationship and the type of relationship. */ function canPlaceholderBeAutocreated(placeholder) { switch (placeholder.relationship?.type) { // These relationship types require no user input case 'angle-between-spline-axes': case 'angle-between-splines': case 'closest-distance-between-annotations': case 'distance-between': case 'projected-distance-from-point': { return true; } default: { return false; } } } /** * Returns true if the all the placeholder's source annotations are available */ function canPlaceholderBeCompleted(placeholder, instance) { if (placeholder.relationship === undefined) { return true; } return placeholder.relationship.sourceIds.every(sourceId => !!instance.placeholderMappings[sourceId]); } function createAnnotationFromPlaceholder(placeholder, protocolInstance) { const base = { color: placeholder.color, hidden: false, name: placeholder.name }; switch (placeholder.annotationType) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE: { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.angle)({ ...base, points: relationshipPoints(placeholder), relationship: mapRelationship(placeholder.relationship, protocolInstance.placeholderMappings) }); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE: { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.closedSpline)({ ...base, points: relationshipPoints(placeholder) }); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE: { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.distance)({ ...base, points: relationshipPoints(placeholder), relationship: mapRelationship(placeholder.relationship, protocolInstance.placeholderMappings) }); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.OPEN_SPLINE: { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.openSpline)({ ...base, points: relationshipPoints(placeholder), relationship: mapRelationship(placeholder.relationship, protocolInstance.placeholderMappings) }); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT: { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.point)({ ...base, position: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, relationship: mapRelationship(placeholder.relationship, protocolInstance.placeholderMappings) }); } default: { return; } } } function mapRelationship(relationship, mappings) { if (!relationship) return undefined; return { ...relationship, sourceIds: relationship.sourceIds.map(id => mappings[id] ?? '') }; } // eslint-disable-next-line sonarjs/cyclomatic-complexity function relationshipPoints(placeholder) { if (!placeholder || !hasSourceIds(placeholder.relationship)) { return []; } switch (placeholder?.relationship?.type) { case 'angle-between-spline-axes': case 'angle-between-splines': { return [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT]; } case 'attached-distance': case 'attached-spline': case 'closest-distance-between-annotations': case 'projected-distance-from-point': { return [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT]; } case 'center-distance': case 'closest-distance-to-one-annotation': case 'projected-distance': { return [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT]; } default: { return []; } } } function hasSourceIds(relationship) { return typeof relationship === 'object' && relationship !== null && 'sourceIds' in relationship; } /***/ }, /***/ 47536 /*!*************************************************************!*\ !*** ./libs/domain/src/lib/selectors/protocol-selectors.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ canProceedFromProtocolForm: () => (/* binding */ canProceedFromProtocolForm), /* harmony export */ getNextPlaceholder: () => (/* binding */ getNextPlaceholder), /* harmony export */ getPreviousPlaceholder: () => (/* binding */ getPreviousPlaceholder), /* harmony export */ isProtocolComplete: () => (/* binding */ isProtocolComplete), /* harmony export */ isProtocolEmpty: () => (/* binding */ isProtocolEmpty), /* harmony export */ isProtocolFormValid: () => (/* binding */ isProtocolFormValid) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _validators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../validators */ 74208); /* harmony import */ var _placeholder_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./placeholder-selectors */ 20333); function isProtocolComplete(definition, instance) { if (definition.id !== instance?.protocolId) return false; // TODO: Maybe also ensure the annotation exists? return definition.placeholders.every(placeholder => instance.placeholderMappings[placeholder.id] !== undefined); } function isProtocolEmpty(instance) { return Object.keys(instance?.placeholderMappings ?? {}).length === 0; } /** * Returns the next placeholder in the protocol that has not been filled * and has all the prerequisite sources, if it is a relative measurement. */ function getNextPlaceholder(definition, instance, { afterPlaceholderId, loopBack = false, prioritizeAutoCreate = false } = {}) { if (instance && definition.id !== instance.protocolId) return; const afterIndex = afterPlaceholderId ? definition.placeholders.findIndex(({ id }) => id === afterPlaceholderId) : -1; // If there is a placeholder that can be autocreated, // that always comes first if (prioritizeAutoCreate) { const toAutocreate = definition.placeholders.find((placeholder, index) => { // Skip any placeholders that can't be autocreated if (!(0,_placeholder_selectors__WEBPACK_IMPORTED_MODULE_2__.canPlaceholderBeAutocreated)(placeholder)) { return false; } // If `afterPlaceholderId` was provided, skip entries before it if (index <= afterIndex) { return false; } // Skip placeholders that have already been filled if (instance?.placeholderMappings[placeholder.id] !== undefined) { return false; } // Return if all sources are available for creation return placeholder.relationship && placeholder.relationship.sourceIds.every(sourceId => instance?.placeholderMappings[sourceId] !== undefined); }); if (toAutocreate !== undefined) { return toAutocreate; } } const next = definition.placeholders.find((placeholder, index) => { // If `afterPlaceholderId` was provided, skip entries before it if (index <= afterIndex) { return false; } // Skip placeholders that have already been filled if (instance?.placeholderMappings[placeholder.id] !== undefined) { return false; } // Skip relative measurements without their sources if (placeholder.relationship) { return placeholder.relationship.sourceIds.every(sourceId => instance?.placeholderMappings[sourceId] !== undefined); } return true; }); if (next === undefined && loopBack && afterPlaceholderId !== undefined) { return getNextPlaceholder(definition, instance, { afterPlaceholderId: undefined, loopBack: false, prioritizeAutoCreate }); } return next; } function getPreviousPlaceholder(definition, instance, currentId, { loopBack = true } = {}) { if (definition.id !== instance.protocolId) return; const currentIndex = currentId ? definition.placeholders.findIndex(({ id }) => id === currentId) : -1; const previous = definition.placeholders.findLast((placeholder, index) => index < currentIndex && !(0,_placeholder_selectors__WEBPACK_IMPORTED_MODULE_2__.canPlaceholderBeAutocreated)(placeholder) && instance.placeholderMappings[placeholder.id] !== undefined); if (previous === undefined && loopBack) { return definition.placeholders.findLast((placeholder, index) => index > currentIndex && !(0,_placeholder_selectors__WEBPACK_IMPORTED_MODULE_2__.canPlaceholderBeAutocreated)(placeholder) && instance.placeholderMappings[placeholder.id] !== undefined); } return previous; } function isProtocolFormValid(formDefinition, formValues) { // No form to validate if (formDefinition === undefined) { return true; } if (formValues === undefined) { return false; } return (0,_validators__WEBPACK_IMPORTED_MODULE_1__.validateProtocolForm)(formDefinition.validation, formValues).valid; } function canProceedFromProtocolForm(formDefinition, formValues) { if (formDefinition?.required === true) { if (!isProtocolFormValid(formDefinition, formValues)) { return false; } if (formDefinition.canProceedRule) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isPass)((0,_validators__WEBPACK_IMPORTED_MODULE_1__.validateProtocolFormField)(formDefinition.canProceedRule, 'form', formValues ?? {})); } } return true; } /***/ }, /***/ 80263 /*!*********************************************************************************!*\ !*** ./libs/domain/src/lib/selectors/s-curve-relative-measurement-selectors.ts ***! \*********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getSCurveAngleDegrees: () => (/* binding */ getSCurveAngleDegrees), /* harmony export */ getSCurveIntersectionAngulation: () => (/* binding */ getSCurveIntersectionAngulation), /* harmony export */ getSCurveIntersectionPosition: () => (/* binding */ getSCurveIntersectionPosition) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _s_curve_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./s-curve-selectors */ 95823); const resolveByIds = (a, b) => `${a.id}:${b.id}`; /** * Returns the angle (in degrees, always within [0, 90]) between two s-curves, * derived from the cross-plane angle between their defining direction vectors. */ const getSCurveAngleDegrees = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.memoizeByReference)((a, b) => { const v1 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)((0,_s_curve_selectors__WEBPACK_IMPORTED_MODULE_2__.getSCurveEnFaceAngle)(a)); const v2 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)((0,_s_curve_selectors__WEBPACK_IMPORTED_MODULE_2__.getSCurveEnFaceAngle)(b)); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.rad2deg)(Math.acos((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.clampRange)(Math.abs(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(v1, v2)), -1, 1))); }, resolveByIds); // Below this, the cross product is too close to the zero vector to normalize // into a meaningful direction (parallel/antipodal en-face vectors - no single // intersection direction is defined). const MIN_CROSS_PRODUCT_SQUARED_LENGTH = 1e-10; /** * Flips a normalized direction vector into a canonical hemisphere (z, then y, * then x tie-broken non-negative) in place. cross(a, b) === -cross(b, a), so * without this, swapping the source-curve order would flip which of the two * antipodal directions is returned - this makes the result order-independent. */ function canonicalizeAxisSign(vector) { const x = vector[0]; const y = vector[1]; const z = vector[2]; const isNegativeHemisphere = z < 0 || z === 0 && (y < 0 || y === 0 && x < 0); if (isNegativeHemisphere) gl_matrix__WEBPACK_IMPORTED_MODULE_0__.negate(vector, vector); } /** * Returns the angulation at which two s-curves intersect, derived from the * (normalized) cross product of their defining direction vectors. Returns * `undefined` when the curves' en-face directions are parallel or antipodal, * since no single intersection direction exists in that case. */ const getSCurveIntersectionAngulation = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.memoizeByReference)((a, b) => { const v1 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)((0,_s_curve_selectors__WEBPACK_IMPORTED_MODULE_2__.getSCurveEnFaceAngle)(a)); const v2 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)((0,_s_curve_selectors__WEBPACK_IMPORTED_MODULE_2__.getSCurveEnFaceAngle)(b)); const n3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), v1, v2); if (gl_matrix__WEBPACK_IMPORTED_MODULE_0__.squaredLength(n3) < MIN_CROSS_PRODUCT_SQUARED_LENGTH) return; gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(n3, n3); canonicalizeAxisSign(n3); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vectorToAngulation)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vec3ToPosition)(n3)); }, resolveByIds); /** * Returns the graph position ([rl, cc]) at which two s-curves intersect, or * `undefined` when no single intersection direction exists (see * `getSCurveIntersectionAngulation`). */ function getSCurveIntersectionPosition(a, b) { const angulation = getSCurveIntersectionAngulation(a, b); if (!angulation) return undefined; const { cc, rl } = angulation; return [rl, cc]; } /***/ }, /***/ 95823 /*!************************************************************!*\ !*** ./libs/domain/src/lib/selectors/s-curve-selectors.ts ***! \************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getSCurveEnFaceAngle: () => (/* binding */ getSCurveEnFaceAngle), /* harmony export */ getSCurvePath: () => (/* binding */ getSCurvePath), /* harmony export */ getSCurveSvgPath: () => (/* binding */ getSCurveSvgPath) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./annotation-selectors */ 66817); /* harmony import */ var _spline_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./spline-selectors */ 28713); // Making this number larger will make rendering faster at the expense of resolution // The educational version uses 2 const CURVE_PATH_STEP = 2; /** * Generates an SVG-ready path for the given S-Curve. */ const getSCurveSvgPath = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.memoizeByReference)(curve => { const points = getSCurvePath(curve); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.buildSvgPath)(points); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getId); const getSCurveEnFaceAngle = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.memoizeByReference)(scurve => { switch (scurve.type) { case 'control-point': { const [one, two] = scurve.controlPoints; if (one !== undefined && two !== undefined) { const [rl1, cc1] = one; const [rl2, cc2] = two; const n1 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)({ ax: 0, cc: cc1, rl: rl1 }); const n2 = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationToVector)({ ax: 0, cc: cc2, rl: rl2 }); const n3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), n1, n2); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(n3, n3); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vectorToAngulation)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vec3ToPosition)(n3)); } else if (one === undefined) { console.warn('Invalid number of control points found'); return { ax: 0, cc: 0, rl: 0 }; } else { const [rl, cc] = one; return { ax: 0, cc, rl }; } } case 'spline': { return (0,_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getClosedSplineEnFaceView)(scurve.spline); } } }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getId); const getSCurvePath = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.memoizeByReference)(curve => { const path = []; const angle = getSCurveEnFaceAngle(curve); for (let rl = -90; rl <= 90; rl += CURVE_PATH_STEP) { const cc = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.sCurvePointOnPath)(rl, angle); path.push([rl, cc]); } // We need to interpolate by a fixed distance so that we can smoothly // move along very steep parts of the path. return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.linearInterpolationByDistance2D)(path, 0.5); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getId); /***/ }, /***/ 28713 /*!***********************************************************!*\ !*** ./libs/domain/src/lib/selectors/spline-selectors.ts ***! \***********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getClosedSplineArea: () => (/* binding */ getClosedSplineArea), /* harmony export */ getClosedSplineEnFaceView: () => (/* binding */ getClosedSplineEnFaceView), /* harmony export */ getClosedSplineHeight: () => (/* binding */ getClosedSplineHeight), /* harmony export */ getClosedSplineMaximumDiameter: () => (/* binding */ getClosedSplineMaximumDiameter), /* harmony export */ getCurvatureRadiusAtPosition: () => (/* binding */ getCurvatureRadiusAtPosition), /* harmony export */ getDistanceAtPosition: () => (/* binding */ getDistanceAtPosition), /* harmony export */ getSplineBestFitNormal: () => (/* binding */ getSplineBestFitNormal), /* harmony export */ getSplineCentroid: () => (/* binding */ getSplineCentroid), /* harmony export */ getSplineLength: () => (/* binding */ getSplineLength), /* harmony export */ getSplinePath: () => (/* binding */ getSplinePath), /* harmony export */ getTriangleCentroid: () => (/* binding */ getTriangleCentroid) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./annotation-selectors */ 66817); const getSplinePath = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.memoizeByReference)(spline => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateSplinePath)(spline.points, (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(spline)), _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getId); const getSplineCentroid = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.memoizeByReference)(spline => { const path = getSplinePath(spline); const length = path.length; const c = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); const v = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); for (const point of path) { gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(v, point[0] / length, point[1] / length, point[2] / length); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.add(c, c, v); } return [c[0], c[1], c[2]]; }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getId); const getTriangleCentroid = points => { const [p0, p1, p2] = points; return [(p0[0] + p1[0] + p2[0]) / 3, (p0[1] + p1[1] + p2[1]) / 3, (p0[2] + p1[2] + p2[2]) / 3]; }; const getSplineBestFitNormal = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.memoizeByReference)(spline => { const path = getSplinePath(spline); const centroid = getSplineCentroid.unmemoized(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateClosedSplineBestFitNormal)(path, centroid); }, _annotation_selectors__WEBPACK_IMPORTED_MODULE_3__.getId); // NOTE: Currently only used in measurements (which are memoized), // so we'll keep the following functions unmemoized function getClosedSplineEnFaceView(spline) { const bestFitNormal = getSplineBestFitNormal(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.vectorToAngulation)(bestFitNormal); } function getClosedSplineArea(spline) { const path = getSplinePath(spline); const centroid = getSplineCentroid(spline); const bestFitNormal = getSplineBestFitNormal(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateClosedSplineArea)(path, centroid, bestFitNormal); } function getClosedSplineHeight(spline) { const path = getSplinePath(spline); const centroid = getSplineCentroid(spline); const bestFitNormal = getSplineBestFitNormal(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateClosedSplineHeight)(path, centroid, bestFitNormal); } function getClosedSplineMaximumDiameter(spline) { const path = getSplinePath(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculatePathMaximumDiameter)(path); } function getDistanceAtPosition(spline, position) { const path = getSplinePath(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateDistanceOnPath)(path, position); } function getCurvatureRadiusAtPosition(spline, position) { const path = getSplinePath(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculateCurvatureRadius)(path, position); } function getSplineLength(spline) { const path = getSplinePath(spline); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.calculatePathDistance)(path, (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(spline)); } /***/ }, /***/ 96964 /*!*****************************************************************!*\ !*** ./libs/domain/src/lib/selectors/study-search-selectors.ts ***! \*****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ compareBy: () => (/* binding */ compareBy), /* harmony export */ compareValues: () => (/* binding */ compareValues), /* harmony export */ filterStudies: () => (/* binding */ filterStudies), /* harmony export */ inDateRange: () => (/* binding */ inDateRange), /* harmony export */ matchesAnyOf: () => (/* binding */ matchesAnyOf), /* harmony export */ matchesReviewStatus: () => (/* binding */ matchesReviewStatus), /* harmony export */ matchesText: () => (/* binding */ matchesText), /* harmony export */ sortRows: () => (/* binding */ sortRows) /* harmony export */ }); /** Case-insensitive substring match. An empty/undefined term means "no filter". */ function matchesText(value, term) { if (!term) return true; return (value ?? '').toLowerCase().includes(term.toLowerCase()); } /** Any-overlap match: the row's value list intersects the allowed list. Empty/undefined list means "no filter". */ function matchesAnyOf(values, allowed) { if (!allowed || allowed.length === 0) return true; return values.some(value => allowed.includes(value)); } /** Exact review-status match. No wanted status means "no filter". */ function matchesReviewStatus(value, wanted) { return !wanted || value === wanted; } /** Inclusive DICOM YYYYMMDD range match (lexical = chronological). */ function inDateRange(value, from, to) { if (!from && !to) return true; if (!value) return false; return (!from || value >= from) && (!to || value <= to); } /** Reads a possibly-dotted path off a row. */ function readPath(row, path) { let current = row; for (const key of path.split('.')) { if (!current || typeof current !== 'object') return; current = current[key]; } return current; } /** Null-safe compare. `0`/`false` are real values, numeric when both numbers. */ function compareValues(a, b) { if (a == undefined && b == undefined) return 0; if (a == undefined) return -1; if (b == undefined) return 1; if (typeof a === 'number' && typeof b === 'number') return a - b; return String(a).localeCompare(String(b)); } /** Comparator for a `SortSpec` over rows. */ function compareBy(sort) { return (a, b) => compareValues(readPath(a, sort.field), readPath(b, sort.field)) * sort.direction; } /** Immutable sort. Returns the rows unchanged when no sort is requested (native order). */ function sortRows(rows, sort) { return sort ? rows.toSorted(compareBy(sort)) : [...rows]; } /** Filters study rows by the (substring, modality list, and date-range) criteria. */ function filterStudies(rows, criteria) { return rows.filter(row => { const matchesTextCriteria = matchesText(row.patientName, criteria.patientName) && matchesText(row.patientID, criteria.patientID) && matchesText(row.studyDescription, criteria.description) && matchesText(row.institutionName, criteria.institution); return matchesTextCriteria && matchesAnyOf(row.modalities, criteria.modalities) && inDateRange(row.studyDate, criteria.studyDateFrom, criteria.studyDateTo) && matchesReviewStatus(row.reviewStatus, criteria.reviewStatus); }); } /***/ }, /***/ 77939 /*!*************************************************************!*\ !*** ./libs/domain/src/lib/updaters/annotation-updaters.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ addPointAt: () => (/* binding */ addPointAt), /* harmony export */ appendPoint: () => (/* binding */ appendPoint), /* harmony export */ changeColor: () => (/* binding */ changeColor), /* harmony export */ clone: () => (/* binding */ clone), /* harmony export */ hide: () => (/* binding */ hide), /* harmony export */ move: () => (/* binding */ move), /* harmony export */ movePoint: () => (/* binding */ movePoint), /* harmony export */ prependPoint: () => (/* binding */ prependPoint), /* harmony export */ removePointAt: () => (/* binding */ removePointAt), /* harmony export */ rename: () => (/* binding */ rename), /* harmony export */ resetOrientation: () => (/* binding */ resetOrientation), /* harmony export */ rotateAboutAxis: () => (/* binding */ rotateAboutAxis), /* harmony export */ setAxisOfSymmetryRotation: () => (/* binding */ setAxisOfSymmetryRotation), /* harmony export */ setCenterOfRotation: () => (/* binding */ setCenterOfRotation), /* harmony export */ setOrientation: () => (/* binding */ setOrientation), /* harmony export */ setPlaceholderId: () => (/* binding */ setPlaceholderId), /* harmony export */ setPoints: () => (/* binding */ setPoints), /* harmony export */ show: () => (/* binding */ show), /* harmony export */ toggleLock: () => (/* binding */ toggleLock) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 85648); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! uuid */ 69083); /** * Return a copy of the provided annotation with the specified point * added to the point list at the specified index. * @param annotation The annotation to update * @param pointIndex The index to add the new point at * @param position The position of the new point * @returns Updated copy of the annotation with the new point */ function addPointAt(annotation, pointIndex, position) { const points = [...annotation.points]; points.splice(pointIndex, 0, position); return { ...annotation, points }; } /** * Return a copy of the provided annotation with a point removed * removed from the point list at the specified index. * @param annotation The annotation to update * @param pointIndex The index toe remove the point from * @returns Updated copy of the annotation with the removed point */ function removePointAt(annotation, pointIndex) { if (annotation.points.length < pointIndex) return annotation; return { ...annotation, points: annotation.points.toSpliced(pointIndex, 1) }; } /** * Return a copy of the provided annotation with the specified point * added to the end of the point list. * @param annotation The annotation to update * @param position The position of the new point * @returns Updated copy of the annotation with the new point */ function appendPoint(annotation, position) { return { ...annotation, points: [...annotation.points, position] }; } /** * Return a copy of the provided annotation (or s-curve) with the specified color. * @param annotation The annotation to update * @param color The new color * @returns Updated copy of the annotation with the new color */ function changeColor(annotation, color) { return { ...annotation, color }; } /** * Return a copy of the provided annotation (or s-curve) with a new id, and optionally * any other fields provided. * @param annotation The annotation (or s-curve) to clone * @param changes Any other fields to update * @returns Clone of the annotation with new id (and any other updates) */ function clone(annotation, changes = {}) { return { ...annotation, ...changes, id: (0,uuid__WEBPACK_IMPORTED_MODULE_2__["default"])() }; } /** * Return a copy of the provided annotation (or s-curve) with hidden set to `true`. * @param annotation The annotation (or s-curve) to update * @returns The hidden copy of the annotation */ function hide(annotation) { return { ...annotation, hidden: true }; } /** * Return a copy of the provided annotation moved to the specified position. * @param annotation The annotation to update * @param position The new position * @returns Updated copy of the annotation with the new position */ function move(annotation, position) { return { ...annotation, position }; } /** * Return a copy of the provided annotation with the specified point moved * to the specified position. * @param annotation The annotation to update * @param pointIndex The point to update * @param position The new position * @returns Updated copy of the annotation with the new point position */ function movePoint(annotation, pointIndex, position) { return { ...annotation, points: annotation.points.toSpliced(pointIndex, 1, position) }; } /** * Return a copy of the provided annotation with the points replaced * with the specified points * @param annotation The annotation to update * @param points The new points * @returns Updated copy of the annotation with the new points */ function setPoints(annotation, points) { return { ...annotation, points }; } /** * Return a copy of the provided annotation with the specified point * added to the beginning of the point list. * @param annotation The annotation to update * @param position The position of the new point * @returns Updated copy of the annotation with the new point */ function prependPoint(annotation, position) { return { ...annotation, points: [position, ...annotation.points] }; } /** * Return a copy of the provided annotation (or s-curve) with the specified name. * @param annotation The annotation (or s-curve) to update * @param name The new name * @returns Updated copy of the annotation with the new name */ function rename(annotation, name) { return { ...annotation, name }; } /** * Return a copy of the provided annotation with the specified placeholderId * @param annotation The annotation to update * @param placeholderId The new placeholderId * @returns Updated copy of the annotation with the new placeholderId */ function setPlaceholderId(annotation, placeholderId) { return { ...annotation, placeholderId }; } /** * Return a copy of the provided annotation (or s-curve) with hidden set to `false`. * @param annotation The annotation (or s-curve) to update * @returns The visible copy of the annotation */ function show(annotation) { return { ...annotation, hidden: false }; } /** * Pre-multiply the Object3D's orientation by a rotation about a world-space axis. */ function rotateAboutAxis(annotation, axis, angleRad) { const normalizedAxis = gl_matrix__WEBPACK_IMPORTED_MODULE_1__.normalize(gl_matrix__WEBPACK_IMPORTED_MODULE_1__.create(), axis); if (!Number.isFinite(normalizedAxis[0])) return annotation; // Axis–angle → unit quaternion: delta = (axis · sin(θ/2), cos(θ/2)). const delta = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.setAxisAngle(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), normalizedAxis, angleRad); // Axis is in world space, the new rotation in the world frame on top of the existing orientation,so: // right-drag updates compose in screen space ("stick with the cursor") rather than in the // object's local frame. Post-multiplying (current * delta) would rotate about the object's // own axes instead, which is not what a drag gesture wants. const next = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.multiply(next, delta, annotation.orientation); // Arrest floating-point drift because repeated multiplications slowly denormalize the quaternion, gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(next, next); return { ...annotation, orientation: [next[0], next[1], next[2], next[3]] }; } /** * Toggle whether an Object3D is locked. A locked object cannot be translated or rotated. */ function toggleLock(annotation) { return { ...annotation, locked: !annotation.locked }; } /** Replace the Object3D's orientation quaternion. */ function setOrientation(annotation, orientation) { return { ...annotation, orientation }; } /** Reset the Object3D's orientation to identity (no rotation). */ function resetOrientation(annotation) { return { ...annotation, orientation: [0, 0, 0, 1] }; } /** Set the STL mesh's pivot (center of rotation). */ function setCenterOfRotation(annotation, centerOfRotation) { return { ...annotation, centerOfRotation }; } /** Replace the STL mesh's axis-of-symmetry rotation matrix (column-major, length 16). */ function setAxisOfSymmetryRotation(annotation, axisOfSymmetryRotation) { return { ...annotation, axisOfSymmetryRotation }; } /***/ }, /***/ 84249 /*!***********************************************!*\ !*** ./libs/domain/src/lib/updaters/index.ts ***! \***********************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ addPointAt: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.addPointAt), /* harmony export */ appendPoint: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.appendPoint), /* harmony export */ changeColor: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.changeColor), /* harmony export */ clearAllPlaceholderAnnotations: () => (/* reexport safe */ _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__.clearAllPlaceholderAnnotations), /* harmony export */ clearPlaceholderAnnotations: () => (/* reexport safe */ _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__.clearPlaceholderAnnotations), /* harmony export */ clearProtocolFormValues: () => (/* reexport safe */ _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__.clearProtocolFormValues), /* harmony export */ clone: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.clone), /* harmony export */ hide: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.hide), /* harmony export */ move: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.move), /* harmony export */ movePoint: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.movePoint), /* harmony export */ prependPoint: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.prependPoint), /* harmony export */ removePointAt: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.removePointAt), /* harmony export */ rename: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.rename), /* harmony export */ resetOrientation: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.resetOrientation), /* harmony export */ rotateAboutAxis: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.rotateAboutAxis), /* harmony export */ setAxisOfSymmetryRotation: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.setAxisOfSymmetryRotation), /* harmony export */ setCenterOfRotation: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.setCenterOfRotation), /* harmony export */ setOrientation: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.setOrientation), /* harmony export */ setPlaceholderAnnotation: () => (/* reexport safe */ _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__.setPlaceholderAnnotation), /* harmony export */ setPlaceholderId: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.setPlaceholderId), /* harmony export */ setPoints: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.setPoints), /* harmony export */ setProtocolFormValues: () => (/* reexport safe */ _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__.setProtocolFormValues), /* harmony export */ show: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.show), /* harmony export */ toggleLock: () => (/* reexport safe */ _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__.toggleLock), /* harmony export */ updateRelativeMeasurement: () => (/* reexport safe */ _relative_measurements__WEBPACK_IMPORTED_MODULE_0__.updateRelativeMeasurement) /* harmony export */ }); /* harmony import */ var _relative_measurements__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./relative-measurements */ 44216); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./annotation-updaters */ 77939); /* harmony import */ var _protocol_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./protocol-updaters */ 12300); /***/ }, /***/ 12300 /*!***********************************************************!*\ !*** ./libs/domain/src/lib/updaters/protocol-updaters.ts ***! \***********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ clearAllPlaceholderAnnotations: () => (/* binding */ clearAllPlaceholderAnnotations), /* harmony export */ clearPlaceholderAnnotations: () => (/* binding */ clearPlaceholderAnnotations), /* harmony export */ clearProtocolFormValues: () => (/* binding */ clearProtocolFormValues), /* harmony export */ setPlaceholderAnnotation: () => (/* binding */ setPlaceholderAnnotation), /* harmony export */ setProtocolFormValues: () => (/* binding */ setProtocolFormValues) /* harmony export */ }); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! rxdb */ 99984); function setPlaceholderAnnotation(instance, placeholderId, annotationId) { if (instance.placeholderMappings[placeholderId] === annotationId) { return instance; } return { ...instance, placeholderMappings: { ...instance.placeholderMappings, [placeholderId]: annotationId } }; } function clearPlaceholderAnnotations(instance, ...placeholderIds) { if (placeholderIds.length === 0) { return instance; } const newMappings = Object.fromEntries(Object.entries(instance.placeholderMappings).filter(([k]) => !placeholderIds.includes(k))); if ((0,rxdb__WEBPACK_IMPORTED_MODULE_0__.deepEqual)(instance.placeholderMappings, newMappings)) { return instance; } return { ...instance, placeholderMappings: newMappings }; } function clearAllPlaceholderAnnotations(instance) { if (Object.keys(instance.placeholderMappings).length === 0) { return instance; } return { ...instance, placeholderMappings: {} }; } function clearProtocolFormValues(instance) { if (instance.formValues === undefined) { return instance; } return { ...instance, formValues: undefined }; } function setProtocolFormValues(instance, formValues) { return { ...instance, formValues: { ...formValues } }; } /***/ }, /***/ 47686 /*!*****************************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/angle-between-spline-axes.ts ***! \*****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ angleBetweenSplineAxes: () => (/* binding */ angleBetweenSplineAxes) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../selectors/spline-selectors */ 28713); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../annotation-updaters */ 77939); function angleBetweenSplineAxes(annotation, sources) { const [spline1, spline2] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(spline1) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(spline2)) { console.warn('Missing or invalid parent inputs'); return annotation; } // Adapted from `AngleBetweenSplineAxesTool::bestAngleBetweenSplineAxes()` const [n1, n2] = [gl_matrix__WEBPACK_IMPORTED_MODULE_0__.clone((0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineBestFitNormal)(spline1)), gl_matrix__WEBPACK_IMPORTED_MODULE_0__.clone((0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineBestFitNormal)(spline2))]; gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(n1, n1); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(n2, n2); const n3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), n1, n2); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(n3, n3); const [p1, p2] = [(0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineCentroid)(spline1), (0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineCentroid)(spline2)]; // get point midway between two splines centers const p3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.add(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), p1, p2); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scale(p3, p3, 0.5); // Projects p1 and p2 onto the plane defined by n3 const d1 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), p1, p3); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scaleAndAdd(d1, p1, n3, -1 * gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(n3, d1)); const d2 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), p2, p3); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scaleAndAdd(d2, p2, n3, -1 * gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(n3, d2)); // Calculate the point of intersection of the two lines // use fomula d1 + l*n1 where l = ±|n2 x (d2-d1)| / |n2 x n1| // d3 starts as d2 - d1 const d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), d2, d1); const n2xd3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), n2, d3); const n2xd3Length = Math.sqrt(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(n2xd3, n2xd3)); const n2xn1 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), n2, n1); const n2xn1Length = Math.sqrt(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(n2xn1, n2xn1)); const l = n2xd3Length / n2xn1Length; // Calculate the point of intersection of the two lines and store in d3 gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scaleAndAdd(d3, d1, n1, l); // We need to ensure that sign of l is correct // Calculate the angle between the two lines segments d1-d3 and d2-d3 const d1d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), d1, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(d1d3, d1d3); const d2d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), d2, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(d2d3, d2d3); const angle1 = Math.acos(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(d1d3, d2d3)); // Calculate the angle between the two vectors n1 and n2 const angle2 = Math.acos(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(n1, n2)); // Ensure that the sign of `l` is correct by checking if the angle // between the two lines segments and the vectors is similar if (Math.abs(angle1 - angle2) % Math.PI > Math.PI / 180 || Math.abs(2 * Math.PI - angle1 + angle2) % Math.PI - Math.PI > Math.PI / 180) { gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scaleAndAdd(d3, d1, n1, -1 * l); } // Calculate distance between center point and both spline center midway point. if too far do not draw angle // and prevent go to const pMiddle = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.add(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), p1, p2); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scale(pMiddle, pMiddle, 0.5); const vSplines = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), p2, p1); const vAngle = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), pMiddle, d3); // If failure conditions are present, return UNINIT points, // which will not be rendered. if (!isValidAngle(angle1, angle2, vAngle, vSplines)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_4__.setPoints)(annotation, [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.UNINIT]); } return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_4__.setPoints)(annotation, [(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.vec3ToPosition)(d1), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.vec3ToPosition)(d3), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.vec3ToPosition)(d2)]); } function isValidAngle(angle1, angle2, vAngle, vSplines) { const p3Distance = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.length(vAngle); const splineDistance = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.length(vSplines); if (Number.isNaN(angle1) || Number.isNaN(angle2)) { return false; } if (p3Distance > 2 * splineDistance) { return false; } return true; } /***/ }, /***/ 23077 /*!*************************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/angle-between-splines.ts ***! \*************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ angleBetweenSplines: () => (/* binding */ angleBetweenSplines) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 97339); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gl-matrix */ 93067); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../selectors/spline-selectors */ 28713); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../annotation-updaters */ 77939); function angleBetweenSplines(annotation, sources) { const [spline1, spline2] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsClosedSpline)(spline1) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsClosedSpline)(spline2)) { console.warn('Missing or invalid parent inputs'); return annotation; } // Adapted from `AngleBetweenSplinesTool::bestAngleBetweenSplineTools()` const [normal1, normal2] = [gl_matrix__WEBPACK_IMPORTED_MODULE_2__.clone((0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineBestFitNormal)(spline1)), gl_matrix__WEBPACK_IMPORTED_MODULE_2__.clone((0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineBestFitNormal)(spline2))]; gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(normal1, normal1); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(normal2, normal2); const normal3 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), normal1, normal2); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(normal3, normal3); const [centroid1, centroid2] = [(0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineCentroid)(spline1), (0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineCentroid)(spline2)]; const index = normal3.map(number_ => Math.abs(number_)).indexOf(Math.max(...normal3)); const a = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); if (index === 3) { gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(a, normal1[0], normal2[0], normal1[1], normal2[1]); } else if (index === 2) { gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(a, normal1[0], normal2[0], normal1[2], normal2[2]); } else { gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(a, normal1[1], normal2[1], normal1[2], normal2[2]); } const b = gl_matrix__WEBPACK_IMPORTED_MODULE_1__.fromValues(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal1, centroid1), gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal2, centroid2)); const invA = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.invert(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), a); if (invA === null) { console.warn("can't invert!"); gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(invA, a[0], a[1], a[2], a[3]); } const p = gl_matrix__WEBPACK_IMPORTED_MODULE_1__.transformMat2(gl_matrix__WEBPACK_IMPORTED_MODULE_1__.create(), b, invA); const p3 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(); if (index === 3) { gl_matrix__WEBPACK_IMPORTED_MODULE_2__.set(p3, p[0], p[1], 0); } else if (index === 2) { gl_matrix__WEBPACK_IMPORTED_MODULE_2__.set(p3, p[0], 0, p[1]); } else { gl_matrix__WEBPACK_IMPORTED_MODULE_2__.set(p3, 0, p[0], p[1]); } const d1 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), centroid1, p3); const l1 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal3, d1); const d2 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), centroid2, p3); const l2 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal3, d2); const d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scaleAndAdd(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), p3, normal3, (l1 + l2) * 0.5); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(d1, centroid1, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scaleAndAdd(d1, centroid1, normal3, -1 * gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal3, d1)); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(d2, centroid2, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scaleAndAdd(d2, centroid2, normal3, -1 * gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal3, d2)); const [perimeter1, perimeter2] = [(0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineLength)(spline1), (0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineLength)(spline2)]; const r1 = perimeter1 / 2 / Math.PI; gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(normal1, d1, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(normal1, normal1); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scaleAndAdd(d1, d1, normal1, r1); const r2 = perimeter2 / 2 / Math.PI; gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(normal2, d2, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(normal2, normal2); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scaleAndAdd(d2, d2, normal2, r2); // If failure conditions are present, return UNINIT points, // which will not be rendered. if (!isValidAngle(normal1, normal2, centroid1, centroid2, d1, d2, d3)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_6__.setPoints)(annotation, [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.UNINIT, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.UNINIT]); } return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_6__.setPoints)(annotation, [(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.vec3ToPosition)(d1), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.vec3ToPosition)(d3), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.vec3ToPosition)(d2)]); } function isValidAngle(normal1, normal2, centroid1, centroid2, d1, d2, d3) { const angle1 = Math.acos(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(normal1, normal2)); if (Number.isNaN(angle1)) { return false; } // Calculate the angle between the two lines segments d1-d3 and d2-d3 const d1d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), d1, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(d1d3, d1d3); const d2d3 = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), d2, d3); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.normalize(d2d3, d2d3); const angle2 = Math.acos(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.dot(d1d3, d2d3)); if (Number.isNaN(angle2)) { return false; } // Calculate distance between center point and both spline center midway points. // Ensure it is not too far eg. a very small angle const pMiddle = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.add(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), centroid1, centroid2); gl_matrix__WEBPACK_IMPORTED_MODULE_2__.scale(pMiddle, pMiddle, 0.5); const vSplines = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), centroid2, centroid1); const vAngle = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.sub(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), pMiddle, d3); const p3Distance = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.length(vAngle); const splineDistance = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.length(vSplines); return p3Distance <= 2 * splineDistance; } /***/ }, /***/ 24076 /*!*********************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/attached-distance.ts ***! \*********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ attachedDistance: () => (/* binding */ attachedDistance) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils */ 87653); /** * Updates the provided Distance so that the first point still sits within the * source annotation's path. * * @param annotation The Distance annotation to be updated * @param sources The parent which the Distance is bound to */ function attachedDistance(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start] = annotation.points; if (!start) { return annotation; } const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(start, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, start)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.movePoint)(annotation, 0, snapped); } return annotation; } /***/ }, /***/ 47041 /*!******************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/attached-point.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ attachedPoint: () => (/* binding */ attachedPoint) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils */ 87653); /** * Updates the provided Point so that it sits within the * source annotation's path. * * @param annotation The Point annotation to be updated * @param sources The parent which the Point is bound to */ function attachedPoint(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(annotation.position, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, annotation.position)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.move)(annotation, snapped); } return annotation; } /***/ }, /***/ 78670 /*!*******************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/attached-spline.ts ***! \*******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ attachedSpline: () => (/* binding */ attachedSpline) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ 87653); /** * Updates the provided Spline so that the first point still sits within the * source annotation's path. * * @param annotation The Spline annotation to be updated * @param sources The parent which the Spline is bound to */ function attachedSpline(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start, ...rest] = annotation.points; if (!start) { console.warn('Expected points on distance!'); return annotation; } const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.snapToAnnotation)(start, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, start)) { return { ...annotation, points: [snapped, ...rest] }; } return annotation; } /***/ }, /***/ 65743 /*!*******************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/center-distance.ts ***! \*******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ centerDistance: () => (/* binding */ centerDistance) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../selectors/annotation-selectors */ 66817); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../annotation-updaters */ 77939); function centerDistance(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start] = annotation.points; if (!start) { return annotation; } const centroid = (0,_selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(centroid, start)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_3__.movePoint)(annotation, 0, centroid); } return annotation; } /***/ }, /***/ 45298 /*!*********************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/chord.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ chord: () => (/* binding */ chord) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils */ 87653); /** * Updates the provided Distance so that the points sit within the * source annotation's path. * * @param annotation The Distance annotation to be updated * @param sources The parent which the Distance is bound to */ function chord(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start, end] = annotation.points; if (!start) { return annotation; } if (!end) { // Only update the first point const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(start, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, start)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.movePoint)(annotation, 0, snapped); } return annotation; } const [snappedStart, snappedEnd] = [(0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(start, source), (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(end, source)]; if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snappedStart, start) || !(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snappedEnd, end)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.setPoints)(annotation, [snappedStart, snappedEnd]); } return annotation; } /***/ }, /***/ 14057 /*!****************************************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/closest-distance-between-annotations.ts ***! \****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ closestDistanceBetweenAnnotations: () => (/* binding */ closestDistanceBetweenAnnotations) /* harmony export */ }); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../selectors/annotation-selectors */ 66817); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /** * Updates the provided Distance so that the points sit within the paths * of each source annotation, at the positions closest to each other. * * @param annotation The Distance annotation to be updated * @param sources The parents which the Distance is bound to */ function closestDistanceBetweenAnnotations(annotation, sources) { const [from, to] = sources; if (!from || !to) { console.warn('Missing or invalid parent inputs'); return annotation; } const fromPath = (0,_selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_1__.getPath)(from); const toPath = (0,_selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_1__.getPath)(to); return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.setPoints)(annotation, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_0__.closestPointsBetweenPaths)(fromPath, toPath)); } /***/ }, /***/ 38892 /*!**************************************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/closest-distance-to-one-annotation.ts ***! \**************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ closestDistanceToOneAnnotation: () => (/* binding */ closestDistanceToOneAnnotation) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils */ 87653); /** * Updates the provided Distance so that the first point still sits within the * source annotation's path, based on the closest point to the end point. * * @param annotation The Distance annotation to be updated * @param sources The parent which the Distance is bound to */ function closestDistanceToOneAnnotation(annotation, sources) { const [source] = sources; if (!source || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start, end] = annotation.points; if (start === undefined) { return annotation; } if (end === undefined) { // No end point, treat the first point the same as in attached distance const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(start, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, start)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.movePoint)(annotation, 0, snapped); } } else { const snapped = (0,_utils__WEBPACK_IMPORTED_MODULE_3__.snapToAnnotation)(end, source); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.positionsEqual)(snapped, start)) { return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_2__.movePoint)(annotation, 0, snapped); } } return annotation; } /***/ }, /***/ 76076 /*!********************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/distance-between.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ distanceBetween: () => (/* binding */ distanceBetween) /* harmony export */ }); /* harmony import */ var _selectors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../selectors */ 27531); /** * Updates the provided Distance so the two points represent the positions * of the parent annotations' centroids. * NOTE: This is more an example - I don't believe the educational version * has this exact relative measurement. * @param annotation The Distance annotation to be updated * @param sources The two parents representing the point of the distance * @returns Updated version of the Distance */ function distanceBetween(annotation, sources) { const [start, end] = sources; if (!start || !end) { console.warn('Missing or invalid parent inputs'); return annotation; } return { ...annotation, points: [(0,_selectors__WEBPACK_IMPORTED_MODULE_0__.getCentroid)(start), (0,_selectors__WEBPACK_IMPORTED_MODULE_0__.getCentroid)(end)] }; } /***/ }, /***/ 44216 /*!*********************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/index.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ updateRelativeMeasurement: () => (/* binding */ updateRelativeMeasurement) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _angle_between_spline_axes__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./angle-between-spline-axes */ 47686); /* harmony import */ var _angle_between_splines__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./angle-between-splines */ 23077); /* harmony import */ var _attached_distance__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./attached-distance */ 24076); /* harmony import */ var _attached_point__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./attached-point */ 47041); /* harmony import */ var _attached_spline__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./attached-spline */ 78670); /* harmony import */ var _center_distance__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./center-distance */ 65743); /* harmony import */ var _chord__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./chord */ 45298); /* harmony import */ var _closest_distance_between_annotations__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./closest-distance-between-annotations */ 14057); /* harmony import */ var _closest_distance_to_one_annotation__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./closest-distance-to-one-annotation */ 38892); /* harmony import */ var _distance_between__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./distance-between */ 76076); /* harmony import */ var _projected_distance__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./projected-distance */ 54542); /* harmony import */ var _projected_distance_from_point__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./projected-distance-from-point */ 44728); const MEASUREMENT_LOOKUP = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE]: { 'angle-between-spline-axes': _angle_between_spline_axes__WEBPACK_IMPORTED_MODULE_2__.angleBetweenSplineAxes, 'angle-between-splines': _angle_between_splines__WEBPACK_IMPORTED_MODULE_3__.angleBetweenSplines }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE]: {}, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CYLINDER]: {}, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE]: { 'attached-distance': _attached_distance__WEBPACK_IMPORTED_MODULE_4__.attachedDistance, 'center-distance': _center_distance__WEBPACK_IMPORTED_MODULE_7__.centerDistance, chord: _chord__WEBPACK_IMPORTED_MODULE_8__.chord, 'closest-distance-between-annotations': _closest_distance_between_annotations__WEBPACK_IMPORTED_MODULE_9__.closestDistanceBetweenAnnotations, 'closest-distance-to-one-annotation': _closest_distance_to_one_annotation__WEBPACK_IMPORTED_MODULE_10__.closestDistanceToOneAnnotation, 'distance-between': _distance_between__WEBPACK_IMPORTED_MODULE_11__.distanceBetween, 'projected-distance': _projected_distance__WEBPACK_IMPORTED_MODULE_12__.projectedDistance, 'projected-distance-from-point': _projected_distance_from_point__WEBPACK_IMPORTED_MODULE_13__.projectedDistanceFromPoint }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.HOLLOW_CYLINDER]: {}, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.OPEN_SPLINE]: { 'attached-spline': _attached_spline__WEBPACK_IMPORTED_MODULE_6__.attachedSpline }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT]: { 'attached-point': _attached_point__WEBPACK_IMPORTED_MODULE_5__.attachedPoint, 'curvature-point': _attached_point__WEBPACK_IMPORTED_MODULE_5__.attachedPoint }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.STL]: {} }; /** * Apply the proper relative measurement updater to the provided annotation, * based on the state of its sources. * If no updater exists for the specified relationship, no changes will be made. * @param annotation The relative measurement annotation to update * @param sources The source annotations to derive the updates from * @returns A copy of the provided annotation, with updates based on the relative measurement type. */ function updateRelativeMeasurement(annotation, sources) { if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationHasRelationship)(annotation)) { return annotation; } const updater = MEASUREMENT_LOOKUP[annotation.type]?.[annotation.relationship.type]; return updater?.(annotation, sources) ?? annotation; } /***/ }, /***/ 44728 /*!*********************************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/projected-distance-from-point.ts ***! \*********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ projectedDistanceFromPoint: () => (/* binding */ projectedDistanceFromPoint) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../selectors/annotation-selectors */ 66817); /* harmony import */ var _selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../selectors/spline-selectors */ 28713); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /** * Updates the provided Distance so that the first point is always perpendicular * to the second point (which is always at the source point's position), and on the source spline's plane. */ function projectedDistanceFromPoint(annotation, sources) { const [spline, point] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsSpline)(spline) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsPoint)(point)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start, end] = annotation.points; if (start === undefined || end === undefined) { return annotation; } const newPoint = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.projectPointOnPlane)(point.position, (0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineBestFitNormal)(spline), (0,_selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(spline)); return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_4__.setPoints)(annotation, [(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vec3ToPosition)(newPoint), [...point.position]]); } /***/ }, /***/ 54542 /*!**********************************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/projected-distance.ts ***! \**********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ projectedDistance: () => (/* binding */ projectedDistance) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../selectors/annotation-selectors */ 66817); /* harmony import */ var _selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../selectors/spline-selectors */ 28713); /* harmony import */ var _annotation_updaters__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../annotation-updaters */ 77939); /** * Updates the provided Distance so that the first point is always perpendicular * to the second point, and on the source annotation's plane. */ function projectedDistance(annotation, sources) { const [source] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsSpline)(source)) { console.warn('Missing or invalid parent inputs'); return annotation; } const [start, end] = annotation.points; if (start === undefined || end === undefined) { return annotation; } const newPoint = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.projectPointOnPlane)(end, (0,_selectors_spline_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplineBestFitNormal)(source), (0,_selectors_annotation_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(source)); return (0,_annotation_updaters__WEBPACK_IMPORTED_MODULE_4__.movePoint)(annotation, 0, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vec3ToPosition)(newPoint)); } /***/ }, /***/ 87653 /*!*********************************************************************!*\ !*** ./libs/domain/src/lib/updaters/relative-measurements/utils.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ snapToAnnotation: () => (/* binding */ snapToAnnotation) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../selectors */ 27531); /* eslint-disable sonarjs/cyclomatic-complexity */ /** * Given a position and a annotation, return the position on the annotation's path * that is closest to the original position. * @param position The position to snap * @param annotation The annotation to snap onto * @returns A position on the annotation's path that is closest to the original position. */ function snapToAnnotation(position, annotation) { if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT) { return annotation.position; } if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE) { const [start, end] = annotation.points; if (start === undefined || end === undefined) { console.warn('Distance annotation missing points'); return position; } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.snapPositionToLine)(position, start, end); } if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.ANGLE) { const [start, middle, end] = annotation.points; if (start === undefined || middle === undefined || end === undefined) { console.warn('Angle annotation missing points'); return position; } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.snapPositionToAngle)(position, start, middle, end); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsSpline)(annotation)) { const path = (0,_selectors__WEBPACK_IMPORTED_MODULE_3__.getSplinePath)(annotation); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.snapPositionToSpline)(position, path); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsObject3D)(annotation)) { return (0,_selectors__WEBPACK_IMPORTED_MODULE_3__.snapPositionToObject3D)(position, (0,_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DGeometry)(annotation), (0,_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DTransformMatrix)(annotation), (0,_selectors__WEBPACK_IMPORTED_MODULE_3__.getObject3DOctree)(annotation)); } return position; } /***/ }, /***/ 74208 /*!*************************************************!*\ !*** ./libs/domain/src/lib/validators/index.ts ***! \*************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ validateProtocolForm: () => (/* reexport safe */ _protocol_form_validators__WEBPACK_IMPORTED_MODULE_0__.validateProtocolForm), /* harmony export */ validateProtocolFormField: () => (/* reexport safe */ _protocol_form_validators__WEBPACK_IMPORTED_MODULE_0__.validateProtocolFormField) /* harmony export */ }); /* harmony import */ var _protocol_form_validators__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./protocol-form-validators */ 75617); /***/ }, /***/ 75617 /*!********************************************************************!*\ !*** ./libs/domain/src/lib/validators/protocol-form-validators.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ validateProtocolForm: () => (/* binding */ validateProtocolForm), /* harmony export */ validateProtocolFormField: () => (/* binding */ validateProtocolFormField) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); function validateProtocolForm(rules, values) { const result = { errors: {}, valid: true }; for (const [key, rule] of Object.entries(rules)) { const result_ = validateProtocolFormField(rule, key, values); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isFail)(result_)) { result.valid = false; result.errors[key] = result_.error ?? 'This field is invalid.'; } } return result; } // eslint-disable-next-line sonarjs/cyclomatic-complexity,sonarjs/cognitive-complexity function validateProtocolFormField(rule, field, values) { switch (rule.type) { case 'and': { for (const rule_ of rule.rules) { const result = validateProtocolFormField(rule_, field, values); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isFail)(result)) { return result; } } return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.pass)(); } case 'equals': { const value = values[field]; return value === rule.value ? (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.pass)() : (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.fail)(rule.message ?? `Expected ${field} to equal ${rule.value}`); } case 'for-field': { return validateProtocolFormField(rule.rule, rule.field, values); } case 'if': { const condition = validateProtocolFormField(rule.condition, field, values); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isPass)(condition)) { return validateProtocolFormField(rule.rule, field, values); } else if (rule.elseRule === undefined) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.skip)(); } else { return validateProtocolFormField(rule.elseRule, field, values); } } case 'one-of': { const value = values[field]; if (Array.isArray(value) || value === undefined) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.fail)('Validation rule not supported for array type'); } return rule.values.includes(value) ? (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.pass)() : (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.fail)(rule.message ?? `Expected ${field} to be one of: ${rule.values.join(',')}`); } case 'or': { const results = rule.rules.map(rule_ => validateProtocolFormField(rule_, field, values)); if (results.some(result => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isPass)(result))) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.pass)(); } const errors = results.map(rule_ => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isFail)(rule_) ? rule_.error : undefined).filter(error => error != undefined); return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.fail)(`One of the following conditions should be true:\n${errors.join('\n')}`); } case 'required': { const value = values[field]; if (typeof value === 'string' && value.trim().length === 0 || Array.isArray(value) && value.length === 0 || value === undefined) { return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.fail)(rule.message ?? 'This field is required.'); } return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.pass)(); } } } /***/ }, /***/ 8938 /*!***********************************!*\ !*** ./libs/feature/src/index.ts ***! \***********************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationActorsService: () => (/* reexport safe */ _lib_volume_viewer_annotation_actors_annotation_actors_service__WEBPACK_IMPORTED_MODULE_15__.AnnotationActorsService), /* harmony export */ AnnotationCardComponent: () => (/* reexport safe */ _lib_annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_18__.AnnotationCardComponent), /* harmony export */ AnnotationExportBridge: () => (/* reexport safe */ _lib_dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_34__.AnnotationExportBridge), /* harmony export */ AnnotationMenuComponent: () => (/* reexport safe */ _lib_annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_25__.AnnotationMenuComponent), /* harmony export */ AnnotationMenuItemComponent: () => (/* reexport safe */ _lib_annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_26__.AnnotationMenuItemComponent), /* harmony export */ AnnotationMenuItemService: () => (/* reexport safe */ _lib_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_24__.AnnotationMenuItemService), /* harmony export */ AnnotationMenuTriggerDirective: () => (/* reexport safe */ _lib_annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_27__.AnnotationMenuTriggerDirective), /* harmony export */ AnnotationPanelComponent: () => (/* reexport safe */ _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__.AnnotationPanelComponent), /* harmony export */ COLORS_TOKEN: () => (/* reexport safe */ _lib_colors_colors_config__WEBPACK_IMPORTED_MODULE_20__.COLORS_TOKEN), /* harmony export */ CameraSliderComponent: () => (/* reexport safe */ _lib_dual_axis_slider_camera_slider_component__WEBPACK_IMPORTED_MODULE_23__.CameraSliderComponent), /* harmony export */ ChamberCardComponent: () => (/* reexport safe */ _lib_chamber_chamber_card_chamber_card_component__WEBPACK_IMPORTED_MODULE_37__.ChamberCardComponent), /* harmony export */ ChamberMenuComponent: () => (/* reexport safe */ _lib_chamber_chamber_menu_components_chamber_menu_component__WEBPACK_IMPORTED_MODULE_40__.ChamberMenuComponent), /* harmony export */ ChamberMenuItemComponent: () => (/* reexport safe */ _lib_chamber_chamber_menu_components_chamber_menu_item_component__WEBPACK_IMPORTED_MODULE_41__.ChamberMenuItemComponent), /* harmony export */ ChamberMenuItemService: () => (/* reexport safe */ _lib_chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_38__.ChamberMenuItemService), /* harmony export */ ChamberMenuTriggerDirective: () => (/* reexport safe */ _lib_chamber_chamber_menu_directives_chamber_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_42__.ChamberMenuTriggerDirective), /* harmony export */ ChamberPanelComponent: () => (/* reexport safe */ _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__.ChamberPanelComponent), /* harmony export */ ChamberService: () => (/* reexport safe */ _lib_chamber_chamber_service__WEBPACK_IMPORTED_MODULE_39__.ChamberService), /* harmony export */ ColorsService: () => (/* reexport safe */ _lib_colors_colors_service__WEBPACK_IMPORTED_MODULE_19__.ColorsService), /* harmony export */ DeviceSizingChartDialogComponent: () => (/* reexport safe */ _lib_device_sizing_chart_device_sizing_chart_dialog_component__WEBPACK_IMPORTED_MODULE_16__.DeviceSizingChartDialogComponent), /* harmony export */ DeviceSizingChartDialogService: () => (/* reexport safe */ _lib_device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_17__.DeviceSizingChartDialogService), /* harmony export */ FULL_PICKER_COLORS_TOKEN: () => (/* reexport safe */ _lib_colors_colors_config__WEBPACK_IMPORTED_MODULE_20__.FULL_PICKER_COLORS_TOKEN), /* harmony export */ ImagingLibraryPageComponent: () => (/* reexport safe */ _lib_imaging_library_imaging_library_page_component__WEBPACK_IMPORTED_MODULE_2__.ImagingLibraryPageComponent), /* harmony export */ LiveAnalysesPageComponent: () => (/* reexport safe */ _lib_imaging_library_live_analyses_page_component__WEBPACK_IMPORTED_MODULE_3__.LiveAnalysesPageComponent), /* harmony export */ LoggingService: () => (/* reexport safe */ _lib_logging_logging_service__WEBPACK_IMPORTED_MODULE_30__.LoggingService), /* harmony export */ MPR_VIEWPORT_ID_LIST: () => (/* reexport safe */ _lib_volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_14__.MPR_VIEWPORT_ID_LIST), /* harmony export */ ModalityLabelPipe: () => (/* reexport safe */ _lib_pipes_modality_label_pipe__WEBPACK_IMPORTED_MODULE_29__.ModalityLabelPipe), /* harmony export */ NON_DEGRADING_VIEWPORT_ID_LIST: () => (/* reexport safe */ _lib_volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_14__.NON_DEGRADING_VIEWPORT_ID_LIST), /* harmony export */ PICKER_COLORS_TOKEN: () => (/* reexport safe */ _lib_colors_colors_config__WEBPACK_IMPORTED_MODULE_20__.PICKER_COLORS_TOKEN), /* harmony export */ PlanarReformationPanelComponent: () => (/* reexport safe */ _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__.PlanarReformationPanelComponent), /* harmony export */ ProtocolPanelComponent: () => (/* reexport safe */ _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__.ProtocolPanelComponent), /* harmony export */ SCurveCardComponent: () => (/* reexport safe */ _lib_s_curve_card_s_curve_card_component__WEBPACK_IMPORTED_MODULE_21__.SCurveCardComponent), /* harmony export */ SCurveGraphPopoverService: () => (/* reexport safe */ _lib_volume_viewer_s_curve_graph_popover_service__WEBPACK_IMPORTED_MODULE_11__.SCurveGraphPopoverService), /* harmony export */ SCurvePanelComponent: () => (/* reexport safe */ _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__.SCurvePanelComponent), /* harmony export */ SubmenuFlipService: () => (/* reexport safe */ _lib_services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_43__.SubmenuFlipService), /* harmony export */ TAVI_PROTOCOL_ID: () => (/* reexport safe */ _lib_dicom_importer_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_35__.TAVI_PROTOCOL_ID), /* harmony export */ TaviProtocol: () => (/* reexport safe */ _lib_protocols_definitions_tavi_protocol__WEBPACK_IMPORTED_MODULE_33__.TaviProtocol), /* harmony export */ ThemePreviewPageComponent: () => (/* reexport safe */ _lib_theme_preview_theme_preview_page_component__WEBPACK_IMPORTED_MODULE_4__.ThemePreviewPageComponent), /* harmony export */ ToolMenuComponent: () => (/* reexport safe */ _lib_tool_menu_tool_menu_component__WEBPACK_IMPORTED_MODULE_22__.ToolMenuComponent), /* harmony export */ TopNavigationComponent: () => (/* reexport safe */ _lib_top_navigation_top_navigation_component__WEBPACK_IMPORTED_MODULE_1__.TopNavigationComponent), /* harmony export */ VIEWPORT_IDS: () => (/* reexport safe */ _lib_volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_14__.VIEWPORT_IDS), /* harmony export */ VOLUME_VIEWER_OPTIONS: () => (/* reexport safe */ _lib_volume_viewer_provide_volume_viewer__WEBPACK_IMPORTED_MODULE_12__.VOLUME_VIEWER_OPTIONS), /* harmony export */ VolumeViewerComponent: () => (/* reexport safe */ _lib_volume_viewer_volume_viewer_component__WEBPACK_IMPORTED_MODULE_9__.VolumeViewerComponent), /* harmony export */ VolumeViewerOrchestrator: () => (/* reexport safe */ _lib_volume_viewer_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_10__.VolumeViewerOrchestrator), /* harmony export */ WindowService: () => (/* reexport safe */ _lib_window_window_service__WEBPACK_IMPORTED_MODULE_28__.WindowService), /* harmony export */ WorkSessionDialogService: () => (/* reexport safe */ _lib_work_session_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_7__.WorkSessionDialogService), /* harmony export */ WorkSessionImportService: () => (/* reexport safe */ _lib_work_session_work_session_import_service__WEBPACK_IMPORTED_MODULE_6__.WorkSessionImportService), /* harmony export */ WorkSessionService: () => (/* reexport safe */ _lib_work_session_work_session_service__WEBPACK_IMPORTED_MODULE_5__.WorkSessionService), /* harmony export */ WorkSessionSwitchService: () => (/* reexport safe */ _lib_work_session_work_session_switch_service__WEBPACK_IMPORTED_MODULE_8__.WorkSessionSwitchService), /* harmony export */ buildProtocolBindings: () => (/* reexport safe */ _lib_dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_34__.buildProtocolBindings), /* harmony export */ deserializeAnnotationPayload: () => (/* reexport safe */ _lib_dicom_importer_services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_36__.deserializeAnnotationPayload), /* harmony export */ extractAnnotationTags: () => (/* reexport safe */ _lib_dicom_importer_services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_36__.extractAnnotationTags), /* harmony export */ getLogger: () => (/* reexport safe */ _lib_logging_utils__WEBPACK_IMPORTED_MODULE_31__.getLogger), /* harmony export */ mapViewportNameToId: () => (/* reexport safe */ _lib_volume_viewer_map_viewport_name_to_id__WEBPACK_IMPORTED_MODULE_13__.mapViewportNameToId), /* harmony export */ oauthPageRoutes: () => (/* reexport safe */ _lib_oauth_feature_pages_oauth_page_routes__WEBPACK_IMPORTED_MODULE_0__.oauthPageRoutes), /* harmony export */ provideDefaultColors: () => (/* reexport safe */ _lib_colors_colors_config__WEBPACK_IMPORTED_MODULE_20__.provideDefaultColors), /* harmony export */ provideVolumeViewer: () => (/* reexport safe */ _lib_volume_viewer_provide_volume_viewer__WEBPACK_IMPORTED_MODULE_12__.provideVolumeViewer), /* harmony export */ rebuildProtocolState: () => (/* reexport safe */ _lib_dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_34__.rebuildProtocolState) /* harmony export */ }); /* harmony import */ var _lib_oauth_feature_pages_oauth_page_routes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/oauth-feature-pages/oauth-page.routes */ 40531); /* harmony import */ var _lib_top_navigation_top_navigation_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/top-navigation/top-navigation.component */ 71202); /* harmony import */ var _lib_imaging_library_imaging_library_page_component__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/imaging-library/imaging-library-page.component */ 96472); /* harmony import */ var _lib_imaging_library_live_analyses_page_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/imaging-library/live-analyses-page.component */ 99957); /* harmony import */ var _lib_theme_preview_theme_preview_page_component__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/theme-preview/theme-preview-page.component */ 79428); /* harmony import */ var _lib_work_session_work_session_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/work-session/work-session.service */ 82757); /* harmony import */ var _lib_work_session_work_session_import_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/work-session/work-session-import.service */ 50784); /* harmony import */ var _lib_work_session_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./lib/work-session/work-session-dialog.service */ 35009); /* harmony import */ var _lib_work_session_work_session_switch_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/work-session/work-session-switch.service */ 5497); /* harmony import */ var _lib_volume_viewer_volume_viewer_component__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./lib/volume-viewer/volume-viewer.component */ 28828); /* harmony import */ var _lib_volume_viewer_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./lib/volume-viewer/volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _lib_volume_viewer_s_curve_graph_popover_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./lib/volume-viewer/s-curve-graph-popover.service */ 57669); /* harmony import */ var _lib_volume_viewer_provide_volume_viewer__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./lib/volume-viewer/provide-volume-viewer */ 21321); /* harmony import */ var _lib_volume_viewer_map_viewport_name_to_id__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./lib/volume-viewer/map-viewport-name-to-id */ 77335); /* harmony import */ var _lib_volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./lib/volume-viewer/viewport-ids */ 85309); /* harmony import */ var _lib_volume_viewer_annotation_actors_annotation_actors_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./lib/volume-viewer/annotation-actors/annotation-actors.service */ 12100); /* harmony import */ var _lib_device_sizing_chart_device_sizing_chart_dialog_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./lib/device-sizing-chart/device-sizing-chart-dialog.component */ 20619); /* harmony import */ var _lib_device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./lib/device-sizing-chart/device-sizing-chart-dialog.service */ 26755); /* harmony import */ var _lib_annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./lib/annotation-card/annotation-card.component */ 86628); /* harmony import */ var _lib_colors_colors_service__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./lib/colors/colors.service */ 39298); /* harmony import */ var _lib_colors_colors_config__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./lib/colors/colors.config */ 98063); /* harmony import */ var _lib_s_curve_card_s_curve_card_component__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./lib/s-curve-card/s-curve-card.component */ 31982); /* harmony import */ var _lib_tool_menu_tool_menu_component__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./lib/tool-menu/tool-menu.component */ 75048); /* harmony import */ var _lib_dual_axis_slider_camera_slider_component__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./lib/dual-axis-slider/camera-slider.component */ 66039); /* harmony import */ var _lib_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./lib/annotation-menu/annotation-menu-item.service */ 39860); /* harmony import */ var _lib_annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./lib/annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _lib_annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./lib/annotation-menu/components/annotation-menu-item.component */ 45731); /* harmony import */ var _lib_annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ./lib/annotation-menu/directives/annotation-menu-trigger.directive */ 12564); /* harmony import */ var _lib_window_window_service__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ./lib/window/window.service */ 26914); /* harmony import */ var _lib_pipes_modality_label_pipe__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ./lib/pipes/modality-label.pipe */ 18194); /* harmony import */ var _lib_logging_logging_service__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ./lib/logging/logging.service */ 47136); /* harmony import */ var _lib_logging_utils__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ./lib/logging/utils */ 14337); /* harmony import */ var _lib_sidebar_panels__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ./lib/sidebar-panels */ 77391); /* harmony import */ var _lib_protocols_definitions_tavi_protocol__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ./lib/protocols/definitions/tavi.protocol */ 12541); /* harmony import */ var _lib_dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ./lib/dicom-importer/services/annotation-export-bridge.service */ 68674); /* harmony import */ var _lib_dicom_importer_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./lib/dicom-importer/services/dicom-export.service */ 8027); /* harmony import */ var _lib_dicom_importer_services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./lib/dicom-importer/services/dicom-annotation-codec */ 19462); /* harmony import */ var _lib_chamber_chamber_card_chamber_card_component__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./lib/chamber/chamber-card/chamber-card.component */ 69605); /* harmony import */ var _lib_chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./lib/chamber/chamber-menu/chamber-menu-item.service */ 44189); /* harmony import */ var _lib_chamber_chamber_service__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ./lib/chamber/chamber.service */ 16592); /* harmony import */ var _lib_chamber_chamber_menu_components_chamber_menu_component__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ./lib/chamber/chamber-menu/components/chamber-menu.component */ 23204); /* harmony import */ var _lib_chamber_chamber_menu_components_chamber_menu_item_component__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ./lib/chamber/chamber-menu/components/chamber-menu-item.component */ 11612); /* harmony import */ var _lib_chamber_chamber_menu_directives_chamber_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ./lib/chamber/chamber-menu/directives/chamber-menu-trigger.directive */ 65937); /* harmony import */ var _lib_services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ./lib/services/submenu-flip/submenu-flip.service */ 9610); // Oauth router // Top Navigation // Imaging Library // Theme preview (dev-only route) // Work Session // Volume Viewer // Device Sizing Chart // Tool Menu // Orbital Camera // Annotation Menu // Pipes // Logging // Sidebar Panels // DICOM Export // Chamber Card // Services /***/ }, /***/ 86628 /*!***************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-card/annotation-card.component.ts ***! \***************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationCardComponent: () => (/* binding */ AnnotationCardComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../annotation-menu/directives/annotation-menu-trigger.directive */ 12564); /* harmony import */ var _card_theme_card_interaction__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../card-theme/card-interaction */ 35946); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../card-theme/card-theme */ 92147); const _c0 = ["nameInput"]; const _c1 = ["nameLabel"]; const _c2 = ["suggestionsPopover"]; const _c3 = ["suggestionButton"]; const _c4 = () => ({ root: "size-6 shrink-0" }); const _c5 = () => ({ root: "py-1 px-0" }); const _c6 = () => ({ color: "var(--p-accordion-header-toggle-icon-color)" }); const _c7 = a0 => ({ secondary: a0 }); const _c8 = a0 => ({ outlined: a0 }); const _forTrack0 = ($index, $item) => $item.name; const _forTrack1 = ($index, $item) => $item.icon; function AnnotationCardComponent_ng_container_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_Conditional_5_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](0, AnnotationCardComponent_Conditional_5_ng_container_0_Template, 1, 0, "ng-container", 18); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const dragHandle_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", dragHandle_r2); } } function AnnotationCardComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 23); } if (rf & 2) { const active_r3 = ctx.active; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("p-accordionheader-toggle-icon size-(--p-app-icon-size-xxxs) text-(length:--p-app-icon-size-xxxs)", !ctx_r3.cdkDrag() && "ml-2.5")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", active_r3 ? "chevron-down" : "chevron-right"); } } function AnnotationCardComponent_ng_container_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_ng_container_11_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_Conditional_13_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](0, AnnotationCardComponent_Conditional_13_ng_container_0_Template, 1, 0, "ng-container", 18); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const moreMenuBtn_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](28); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", moreMenuBtn_r5); } } function AnnotationCardComponent_ng_container_15_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_ng_container_17_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_ng_container_18_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 34); } } function AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 33); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("mousedown", function AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_Template_p_button_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.preventDefault()); })("click", function AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.clearAnnotationName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](3, AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_ng_template_3_Template, 1, 0, "ng-template", null, 12, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 3, "common.clearName"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](2, 5, "common.clearName"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](7, _c4)); } } function AnnotationCardComponent_ng_template_19_Conditional_1_For_9_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "li")(1, "button", 35, 13); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("mousedown", function AnnotationCardComponent_ng_template_19_Conditional_1_For_9_Template_button_mousedown_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.preventDefault()); })("click", function AnnotationCardComponent_ng_template_19_Conditional_1_For_9_Template_button_click_1_listener($event) { const suggestion_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8).$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); $event.stopPropagation(); $event.preventDefault(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.selectNameSuggestion(suggestion_r9)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const suggestion_r9 = ctx.$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r3.clampedSuggestions().has(suggestion_r9) ? suggestion_r9 : undefined)("tooltipPosition", ctx_r3.clampedSuggestions().has(suggestion_r9) ? "left" : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", suggestion_r9, " "); } } function AnnotationCardComponent_ng_template_19_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 25)(1, "div", 28)(2, "input", 29, 10); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_click_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("input", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_input_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.refreshNameSuggestions)($event)); })("keydown.space", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_keydown_space_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.handleSpace)($event)); })("keydown.enter", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_keydown_enter_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation()($event)); })("keyup.enter", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_keyup_enter_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.updateAnnotationName)($event)); })("keydown.escape", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_keydown_escape_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation()($event)); })("keyup.escape", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_keyup_escape_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.cancelEditAnnotationName)($event)); })("blur", function AnnotationCardComponent_ng_template_19_Conditional_1_Template_input_blur_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.updateAnnotationName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](4, AnnotationCardComponent_ng_template_19_Conditional_1_Conditional_4_Template, 5, 8, "p-button", 30); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](5, "p-popover", 31, 11)(7, "ul", 32); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](8, AnnotationCardComponent_ng_template_19_Conditional_1_For_9_Template, 4, 3, "li", null, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIdentity"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("id", `annotation-${ctx_r3.annotation().id}-name`)("formControl", ctx_r3.annotationName); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("data-test-id", `annotation-card-input-${ctx_r3.annotation().id}-name`)("maxlength", ctx_r3.nameMaxLength); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r3.annotationName.value ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("appendTo", "body")("dismissable", false); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](ctx_r3.filteredNameSuggestions()); } } function AnnotationCardComponent_ng_template_19_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "span", 26, 14); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r3.isNameClamped() ? ctx_r3.annotation().name : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", ctx_r3.annotation().name, " "); } } function AnnotationCardComponent_ng_template_19_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r10 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "button", 36); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function AnnotationCardComponent_ng_template_19_Conditional_3_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r10); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameClick($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](1, "span", 37, 14); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("min-w-0 flex-1 cursor-pointer text-left")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r3.isNameClamped() ? ctx_r3.annotation().name : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", ctx_r3.annotation().name, " "); } } function AnnotationCardComponent_ng_template_19_Conditional_4_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function AnnotationCardComponent_ng_template_19_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](0, AnnotationCardComponent_ng_template_19_Conditional_4_ng_container_0_Template, 1, 0, "ng-container", 18); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); const visibilityBtn_r11 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](26); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", visibilityBtn_r11); } } function AnnotationCardComponent_ng_template_19_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](1, AnnotationCardComponent_ng_template_19_Conditional_1_Template, 10, 7, "div", 25)(2, AnnotationCardComponent_ng_template_19_Conditional_2_Template, 3, 2, "span", 26)(3, AnnotationCardComponent_ng_template_19_Conditional_3_Template, 4, 4, "button", 27); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](4, AnnotationCardComponent_ng_template_19_Conditional_4_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r3.isEditing() ? 1 : ctx_r3.readOnly() ? 2 : 3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](!ctx_r3.isEditing() ? 4 : -1); } } function AnnotationCardComponent_ng_template_21_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](1, "lib-icon", 38); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("flex size-7 shrink-0 items-center justify-center rounded-full bg-(--p-app-surface-icon-holder)", ctx_r3.annotation().hidden && "opacity-80")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleProp"]("color", ctx_r3.accentColor()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", ctx_r3.iconName()); } } function AnnotationCardComponent_ng_template_23_div_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 41); } } function AnnotationCardComponent_ng_template_23_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 39); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](2, AnnotationCardComponent_ng_template_23_div_2_Template, 1, 0, "div", 40); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("order-first size-3 px-1.5 py-3 text-(--p-accordion-header-toggle-icon-hover-color) opacity-0", ctx_r3.readOnly() ? "pointer-events-none" : "cursor-grab transition-opacity delay-100 group-hover:opacity-100 active:cursor-grabbing")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("aria-hidden", ctx_r3.readOnly() || null)("aria-label", ctx_r3.readOnly() ? null : _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 4, "annotationCard.dragToReorder")); } } function AnnotationCardComponent_ng_template_25_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 43); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", ctx_r3.annotation().hidden ? "eye" : "eye-off"); } } function AnnotationCardComponent_ng_template_25_Template(rf, ctx) { if (rf & 1) { const _r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 42); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function AnnotationCardComponent_ng_template_25_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r12); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.annotation().hidden ? ctx_r3.show.emit() : ctx_r3.hide.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](2, AnnotationCardComponent_ng_template_25_ng_template_2_Template, 1, 1, "ng-template", null, 12, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn(ctx_r3.readOnly() && "pointer-events-none opacity-0")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](8, _c5))("dt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](12, _c8, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](10, _c7, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](9, _c6))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 6, ctx_r3.annotation().hidden ? "common.show" : "common.hide")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("aria-hidden", ctx_r3.readOnly() || null); } } function AnnotationCardComponent_ng_template_27_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 45); } } function AnnotationCardComponent_ng_template_27_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](2, AnnotationCardComponent_ng_template_27_ng_template_2_Template, 1, 0, "ng-template", null, 12, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const moreMenuTrigger_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](7, _c5))("dt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](11, _c8, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](9, _c7, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](8, _c6))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 5, "common.moreActions"))("libMenuTrigger", moreMenuTrigger_r13)("libMenuActions", ctx_r3.actions()); } } function AnnotationCardComponent_ng_template_29_Conditional_2_For_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 47)(1, "span", 49); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const name_r14 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](name_r14); } } function AnnotationCardComponent_ng_template_29_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 47)(1, "span", 48); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](4, AnnotationCardComponent_ng_template_29_Conditional_2_For_5_Template, 3, 1, "div", 47, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIdentity"]); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const relatedNames_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"]("", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](3, 1, "annotationCard.relativeTo"), ":"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](relatedNames_r15); } } function AnnotationCardComponent_ng_template_29_For_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 47)(1, "span", 48); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](4, "span", 50); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const measurement_r16 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"]("", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](3, 2, measurement_r16.name), ":"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](measurement_r16.value); } } function AnnotationCardComponent_ng_template_29_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 46); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](2, AnnotationCardComponent_ng_template_29_Conditional_2_Template, 6, 3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](3, AnnotationCardComponent_ng_template_29_For_4_Template, 6, 4, "div", 47, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); const relatedNames_r17 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"](ctx_r3.annotation().relatedNames); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](relatedNames_r17 && relatedNames_r17.length > 0 ? 2 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](ctx_r3.annotation().measurements); } } function AnnotationCardComponent_ng_template_31_For_2_Conditional_0_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 54); } if (rf & 2) { const action_r19 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", action_r19.icon)("pTooltip", action_r19.label); } } function AnnotationCardComponent_ng_template_31_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r18 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 53); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function AnnotationCardComponent_ng_template_31_For_2_Conditional_0_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r18); const action_r19 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"]().$implicit; $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](action_r19.command == null ? null : action_r19.command($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](1, AnnotationCardComponent_ng_template_31_For_2_Conditional_0_ng_template_1_Template, 1, 2, "ng-template", null, 12, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const action_r19 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ariaLabel", action_r19.label)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](3, _c5))("disabled", action_r19.disabled); } } function AnnotationCardComponent_ng_template_31_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](0, AnnotationCardComponent_ng_template_31_For_2_Conditional_0_Template, 3, 4, "p-button", 52); } if (rf & 2) { const action_r19 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](action_r19.icon ? 0 : -1); } } function AnnotationCardComponent_ng_template_31_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 51); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](1, AnnotationCardComponent_ng_template_31_For_2_Template, 1, 1, null, null, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](ctx_r3.cardActions()); } } function AnnotationCardComponent_ng_template_33_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 55); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleProp"]("background-color", ctx_r3.selected() ? ctx_r3.accentColor() : ""); } } const ANNOTATION_TYPE_ICON_MAP = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.AnnotationSourceType.CYLINDER]: 'object-3d', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.AnnotationSourceType.HOLLOW_CYLINDER]: 'object-3d', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.AnnotationSourceType.STL]: 'object-3d' }; class AnnotationCardComponent { annotation = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "annotation" }] : [])); actions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)([], ...(ngDevMode ? [{ debugName: "actions" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); selected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "selected" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); menuTrigger = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(...(ngDevMode ? [undefined, { debugName: "menuTrigger" }] : [])); cdkDrag = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "cdkDrag" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); readOnly = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "readOnly" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); show = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); hide = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); goTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); updateName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); selectedChange = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); clicked = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); cancelClick = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.CancelClickDirective, ...(ngDevMode ? [{ debugName: "cancelClick" }] : [])); cdr = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_2__.ChangeDetectorRef); nameInput = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameInput', ...(ngDevMode ? [{ debugName: "nameInput" }] : [])); nameLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameLabel', ...(ngDevMode ? [{ debugName: "nameLabel" }] : [])); suggestionsPopover = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('suggestionsPopover', ...(ngDevMode ? [{ debugName: "suggestionsPopover" }] : [])); suggestionButtons = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChildren)('suggestionButton', ...(ngDevMode ? [{ debugName: "suggestionButtons" }] : [])); isEditing = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isEditing" }] : [])); annotationName = new _angular_forms__WEBPACK_IMPORTED_MODULE_6__.FormControl(''); nameMaxLength = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.ANNOTATION_NAME_MAX_LENGTH; isNameClamped = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isNameClamped" }] : [])); structureNameSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.ANNOTATION_STRUCTURE_NAMES[this.annotation().type] ?? [], ...(ngDevMode ? [{ debugName: "structureNameSuggestions" }] : [])); filteredNameSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "filteredNameSuggestions" }] : [])); /** Suggestions whose text is actually cut off by ellipsis in the dropdown, by name. */ clampedSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(new Set(), ...(ngDevMode ? [{ debugName: "clampedSuggestions" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.afterEveryRender)(() => { const element = this.nameLabel()?.nativeElement; if (!element) return; const clamped = element.scrollHeight > element.clientHeight; if (clamped !== this.isNameClamped()) this.isNameClamped.set(clamped); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.afterEveryRender)(() => { const clamped = new Set(this.suggestionButtons().filter(({ nativeElement }) => nativeElement.scrollWidth > nativeElement.clientWidth).map(({ nativeElement }) => nativeElement.textContent?.trim() ?? '')); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.isEqualSet)(clamped, this.clampedSuggestions())) this.clampedSuggestions.set(clamped); }); } ngOnInit() { this.annotationName.setValue(this.annotation().name); } ngAfterViewInit() { this.cancelClick()?.filteredClick.subscribe(event => this.clicked.emit(event)); } mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.buildCardPt)(this.pt(), this.getCardState()), ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.buildCardDt)(_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.DARK_CARD_THEME[this.getCardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); accentColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.annotation().hidden ? 'var(--p-text-muted-color)' : this.annotation().color, ...(ngDevMode ? [{ debugName: "accentColor" }] : [])); iconName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const { type } = this.annotation(); return ANNOTATION_TYPE_ICON_MAP[type] ?? type; }, ...(ngDevMode ? [{ debugName: "iconName" }] : [])); cardActions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.actions().filter(action => action.includeInCard), ...(ngDevMode ? [{ debugName: "cardActions" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn; contextMenu(event) { // NOTE: On Mac, ctrl+click triggers the contextmenu event, // but that conflicts with our multiselect functionality. // We must re-emit this as a click now if (event.ctrlKey) { event.preventDefault(); this.clicked.emit(event); return; } const trigger = this.menuTrigger(); if (!trigger) return; trigger.model.set(this.actions()); trigger.toggle(event); } handleCardDoubleClick(event) { const wrapper = event.currentTarget; if (this.isEditing() || (0,_card_theme_card_interaction__WEBPACK_IMPORTED_MODULE_17__.isInteractiveCardDescendant)(event, wrapper)) return; this.goTo.emit(); } handleNameClick(event) { event.stopPropagation(); event.preventDefault(); this.onEditAnnotationName(); this.cdr.markForCheck(); } handleEventPropagation(callback) { return event => { event.stopPropagation(); event.preventDefault(); callback?.(); this.cdr.markForCheck(); }; } handleSpace = () => { const value = this.annotationName.value ?? ''; if (value.length >= this.nameMaxLength) return; this.annotationName.setValue(value + ' '); }; onEditAnnotationName = () => { if (this.readOnly() || this.isEditing()) return; this.annotationName.setValue(this.annotation().name); this.menuTrigger()?.hide(); this.isEditing.set(true); this.refreshNameSuggestions(); setTimeout(() => { this.nameInput()?.nativeElement.focus(); this.syncSuggestionsPopover(); }); }; cancelEditAnnotationName = () => { this.isEditing.set(false); this.suggestionsPopover()?.hide(); }; /** Clears the field's current text (without saving) so a new name can be picked from the * suggestions list with the mouse alone, no backspacing required. */ clearAnnotationName = () => { this.annotationName.setValue(''); this.refreshNameSuggestions(); this.nameInput()?.nativeElement.focus(); }; updateAnnotationName = () => { const value = this.annotationName.value ?? ''; if (value.trim().length === 0) { this.cancelEditAnnotationName(); return; } this.isEditing.set(false); this.suggestionsPopover()?.hide(); this.updateName.emit(value); }; /** Narrows the type-specific structure-name list to whatever's currently typed. */ refreshNameSuggestions = () => { const allNames = this.structureNameSuggestions(); if (allNames.length === 0) { this.filteredNameSuggestions.set([]); } else { const query = (this.annotationName.value ?? '').trim().toLowerCase(); this.filteredNameSuggestions.set(query ? allNames.filter(name => name.toLowerCase().includes(query)) : allNames); } this.syncSuggestionsPopover(); }; selectNameSuggestion(name) { this.annotationName.setValue(name.slice(0, this.nameMaxLength)); this.updateAnnotationName(); } /** Shows/hides the structure-name suggestions panel, anchored to the name input. */ syncSuggestionsPopover() { const input = this.nameInput()?.nativeElement; const popover = this.suggestionsPopover(); if (!popover || !input) return; if (this.filteredNameSuggestions().length > 0) { popover.show(undefined, input); } else { popover.hide(); } } getCardState() { if (this.selected()) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.SELECTED; if (this.annotation().hidden) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DISABLED; return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DEFAULT; } static ɵfac = function AnnotationCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdefineComponent"]({ type: AnnotationCardComponent, selectors: [["lib-annotation-card"]], viewQuery: function AnnotationCardComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵviewQuerySignal"](ctx.cancelClick, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.CancelClickDirective, 5)(ctx.nameInput, _c0, 5)(ctx.nameLabel, _c1, 5)(ctx.suggestionsPopover, _c2, 5)(ctx.suggestionButtons, _c3, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵqueryAdvance"](5); } }, inputs: { annotation: [1, "annotation"], actions: [1, "actions"], pt: [1, "pt"], selected: [1, "selected"], menuTrigger: [1, "menuTrigger"], cdkDrag: [1, "cdkDrag"], readOnly: [1, "readOnly"] }, outputs: { show: "show", hide: "hide", goTo: "goTo", updateName: "updateName", selectedChange: "selectedChange", clicked: "clicked" }, decls: 35, vars: 18, consts: [["panel", ""], ["toggleicon", ""], ["headerTitle", ""], ["cardIcon", ""], ["dragHandle", ""], ["visibilityBtn", ""], ["moreMenuBtn", ""], ["contentMeasurements", ""], ["contentActions", ""], ["accentBar", ""], ["nameInput", ""], ["suggestionsPopover", ""], ["icon", ""], ["suggestionButton", ""], ["nameLabel", ""], ["data-test-id", "annotation-card-div-wrapper", 3, "click", "dblclick", "contextmenu"], [1, "grow", 3, "pt", "dt", "value"], ["libCancelClick", "", 3, "pt"], [4, "ngTemplateOutlet"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-2", "py-1"], [1, "relative", 3, "pt"], [1, "flex", "gap-3"], ["data-propagate-click", "", 3, "icon"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], [1, "min-w-0", "flex-1"], [1, "line-clamp-2", "min-w-0", "flex-1", "wrap-anywhere", 3, "pTooltip"], ["type", "button", "data-test-id", "annotation-card-button-name-trigger", "data-propagate-click", "", 3, "class"], [1, "flex", "min-w-0", "items-center", "gap-1"], ["pInputText", "", "data-propagate-click", "", 1, "border-primary-400", "w-full", "min-w-0", "bg-transparent", "py-0.5", "text-sm", "text-inherit", 3, "click", "input", "keydown.space", "keydown.enter", "keyup.enter", "keydown.escape", "keyup.escape", "blur", "id", "formControl"], ["type", "button", "data-propagate-click", "", "data-test-id", "annotation-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "pTooltip", "ariaLabel", "pt"], ["data-propagate-click", "", 3, "appendTo", "dismissable"], ["data-propagate-click", "", "data-test-id", "annotation-card-ul-name-suggestions", 1, "max-h-48", "w-56", "overflow-auto", "text-sm"], ["type", "button", "data-propagate-click", "", "data-test-id", "annotation-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "mousedown", "click", "pTooltip", "ariaLabel", "pt"], ["icon", "times", 1, "size-3"], ["type", "button", "data-propagate-click", "", "data-test-id", "annotation-card-button-name-suggestion", 1, "hover:bg-surface-800", "block", "w-full", "overflow-hidden", "rounded", "px-2", "py-1", "text-left", "text-ellipsis", "whitespace-nowrap", "text-inherit", 3, "mousedown", "click", "pTooltip", "tooltipPosition"], ["type", "button", "data-test-id", "annotation-card-button-name-trigger", "data-propagate-click", "", 3, "click"], [1, "line-clamp-2", "wrap-anywhere", 3, "pTooltip"], [1, "size-(--p-app-icon-size-sm)", 3, "icon"], ["cdkDragHandle", "", "icon", "drag-handle"], ["class", "h-11 rounded-sm bg-(--p-app-dark-surface-base)", 4, "cdkDragPlaceholder"], [1, "h-11", "rounded-sm", "bg-(--p-app-dark-surface-base)"], ["data-test-id", "annotation-card-p-button-visibility", "data-propagate-click", "", "tooltipPosition", "left", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "pt", "dt", "pTooltip"], [1, "size-(--p-app-icon-size-xs)", 3, "icon"], ["data-test-id", "annotation-card-p-button-more-actions", "data-propagate-click", "", "tooltipPosition", "left", "severity", "secondary", "outlined", "", "size", "small", 3, "pt", "dt", "pTooltip", "libMenuTrigger", "libMenuActions"], ["icon", "ellipsis-v", 1, "size-(--p-app-icon-size-xxxs)", "text-(length:--p-app-icon-size-xxxs)"], [1, "flex", "grow", "flex-col", "gap-[3px]", "py-0", "text-[11px]"], [1, "flex", "gap-1"], [1, "text-color", "font-semibold"], [1, "ps-4", "text-(--p-accordion-content-muted-color)"], [1, "text-(--p-accordion-content-muted-color)"], [1, "-mt-2", "flex", "flex-col", "items-end"], ["data-test-id", "annotation-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "ariaLabel", "pt", "disabled"], ["data-test-id", "annotation-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "ariaLabel", "pt", "disabled"], ["tooltipPosition", "left", 1, "size-(--p-app-icon-size-xs)", 3, "icon", "pTooltip"], [1, "absolute", "top-0", "left-0", "h-full", "w-1"]], template: function AnnotationCardComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 15); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function AnnotationCardComponent_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.clicked.emit($event)); })("dblclick", function AnnotationCardComponent_Template_div_dblclick_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.handleCardDoubleClick($event)); })("contextmenu", function AnnotationCardComponent_Template_div_contextmenu_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.contextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](1, "p-accordion-panel", 16, 0)(3, "p-accordion-header", 17); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](4, AnnotationCardComponent_ng_container_4_Template, 1, 0, "ng-container", 18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](5, AnnotationCardComponent_Conditional_5_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](6, AnnotationCardComponent_ng_template_6_Template, 1, 3, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](8, "div", 19)(9, "div", 20); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](10, AnnotationCardComponent_ng_container_10_Template, 1, 0, "ng-container", 18)(11, AnnotationCardComponent_ng_container_11_Template, 1, 0, "ng-container", 18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](13, AnnotationCardComponent_Conditional_13_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](14, "p-accordion-content", 21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](15, AnnotationCardComponent_ng_container_15_Template, 1, 0, "ng-container", 18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](16, "div", 22); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](17, AnnotationCardComponent_ng_container_17_Template, 1, 0, "ng-container", 18)(18, AnnotationCardComponent_ng_container_18_Template, 1, 0, "ng-container", 18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](19, AnnotationCardComponent_ng_template_19_Template, 5, 2, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(21, AnnotationCardComponent_ng_template_21_Template, 2, 5, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(23, AnnotationCardComponent_ng_template_23_Template, 3, 6, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(25, AnnotationCardComponent_ng_template_25_Template, 4, 14, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(27, AnnotationCardComponent_ng_template_27_Template, 4, 13, "ng-template", null, 6, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(29, AnnotationCardComponent_ng_template_29_Template, 5, 2, "ng-template", null, 7, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(31, AnnotationCardComponent_ng_template_31_Template, 3, 0, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(33, AnnotationCardComponent_ng_template_33_Template, 1, 2, "ng-template", null, 9, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { const headerTitle_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](20); const cardIcon_r21 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](22); const contentMeasurements_r22 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](30); const contentActions_r23 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](32); const accentBar_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](34); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx.cn("group flex w-full overflow-hidden", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", ctx.annotation().id); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx.cdkDrag() ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", headerTitle_r20); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); const moreMenuTrigger_r25 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"](ctx.menuTrigger()); const moreActions_r26 = ctx.actions(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](!ctx.isEditing() && moreMenuTrigger_r25 && moreActions_r26.length ? 13 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().content); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", contentMeasurements_r22); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", contentActions_r23); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionContent, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionPanel, _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_16__.AnnotationMenuTriggerDirective, primeng_button__WEBPACK_IMPORTED_MODULE_9__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.CancelClickDirective, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragHandle, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragPlaceholder, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.IconComponent, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, primeng_popover__WEBPACK_IMPORTED_MODULE_11__.Popover, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.FormControlDirective, primeng_tooltip__WEBPACK_IMPORTED_MODULE_12__.Tooltip, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputText, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 39860 /*!******************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/annotation-menu-item.service.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationMenuItemService: () => (/* binding */ AnnotationMenuItemService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _chamber_chamber_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../chamber/chamber.service */ 16592); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../colors/colors.service */ 39298); /* harmony import */ var _create_s_curve_dialog_create_s_curve_dialog_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../create-s-curve-dialog/create-s-curve-dialog.component */ 24340); /* harmony import */ var _device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../device-sizing-chart/device-sizing-chart-dialog.service */ 26755); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _relative_measurements_relative_measurements_service__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../relative-measurements/relative-measurements.service */ 79408); /* harmony import */ var _s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../s-curve-relative-measurements/s-curve-relative-measurements.service */ 17464); /* harmony import */ var _volume_viewer_annotation_actors_annotation_updaters_constants__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../volume-viewer/annotation-actors/annotation-updaters/constants */ 55127); /* harmony import */ var _volume_viewer_cpr_cpr_service__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../volume-viewer/cpr/cpr.service */ 26144); /* harmony import */ var _volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../volume-viewer/viewport-ids */ 85309); /* harmony import */ var _volume_viewer_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../volume-viewer/volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _window_window_service__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../window/window.service */ 26914); /* harmony import */ var _model_geometry_service__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./model-geometry.service */ 27113); const DESTRUCTIVE_CLASSES = 'text-(--p-app-status-danger)'; const REFERENCE_LINES_ICON = 'reference-lines'; const RELATIVE_MEASUREMENT_LABEL_CLASS = 'whitespace-nowrap'; const ANNOTATION_LABEL_CLASS = 'max-w-64 overflow-hidden text-ellipsis whitespace-nowrap'; const ALIGN_VIEWS = [{ axis: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportAxisState.TOPLEFTMAIN, color: 'var(--p-app-viewport-axis-axial)', key: 'axial' }, { axis: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportAxisState.MIDDLEMAIN, color: 'var(--p-app-viewport-axis-coronal)', key: 'coronal' }, { axis: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportAxisState.BOTTOMLEFTMAIN, color: 'var(--p-app-viewport-axis-sagittal)', key: 'sagittal' }]; class AnnotationMenuItemService { annotationFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.AnnotationFacade); chamberService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_chamber_chamber_service__WEBPACK_IMPORTED_MODULE_14__.ChamberService); colorsService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_15__.ColorsService); dialogService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__.DialogService); sCurveFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.SCurveFacade); uiFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.UiFacade); interactionModeService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_18__.InteractionModeService); relativeMeasurements = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_relative_measurements_relative_measurements_service__WEBPACK_IMPORTED_MODULE_19__.RelativeMeasurementsService); sCurveRelativeMeasurements = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_20__.SCurveRelativeMeasurementsService); document = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_1__.DOCUMENT); viewer = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_volume_viewer_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_24__.VolumeViewerOrchestrator); cprService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_volume_viewer_cpr_cpr_service__WEBPACK_IMPORTED_MODULE_22__.CprService); translate = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); windowService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_window_window_service__WEBPACK_IMPORTED_MODULE_25__.WindowService); confirmationService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_4__.ConfirmationService); viewportStore = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.viewportStore); modelGeometry = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_model_geometry_service__WEBPACK_IMPORTED_MODULE_26__.ModelGeometryService); devOptions = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_6__.DevelopmentOptionsService); isDevBuild = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.IS_DEV_BUILD); deviceSizingChart = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_17__.DeviceSizingChartDialogService); selectedAnnotationIds = this.annotationFacade.selectedIds; hiddenSelectedAnnotationIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.annotationFacade.selectedAnnotations().filter(({ hidden }) => hidden).map(({ id }) => id), ...(ngDevMode ? [{ debugName: "hiddenSelectedAnnotationIds" }] : [])); visibleSelectedAnnotationIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.annotationFacade.selectedAnnotations().filter(({ hidden }) => !hidden).map(({ id }) => id), ...(ngDevMode ? [{ debugName: "visibleSelectedAnnotationIds" }] : [])); annotationIdsByVisibility = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const annotations = this.annotationFacade.annotations(); const annotationIdsVisibilities = { hiddenIds: [], visibleIds: [] }; for (const { hidden, id } of annotations) { const arrayToPush = hidden ? annotationIdsVisibilities.hiddenIds : annotationIdsVisibilities.visibleIds; arrayToPush.push(id); } return annotationIdsVisibilities; }, ...(ngDevMode ? [{ debugName: "annotationIdsByVisibility" }] : [])); selectedSCurveIds = this.sCurveFacade.selectedIds; sCurveIdsByVisibility = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const sCurves = this.sCurveFacade.sCurves(); const sCurveIdsVisibilities = { hiddenIds: [], visibleIds: [] }; for (const { hidden, id } of sCurves) { const arrayToPush = hidden ? sCurveIdsVisibilities.hiddenIds : sCurveIdsVisibilities.visibleIds; arrayToPush.push(id); } return sCurveIdsVisibilities; }, ...(ngDevMode ? [{ debugName: "sCurveIdsByVisibility" }] : [])); showAnnotation(annotationId) { this.annotationFacade.setAnnotationsVisibility([annotationId], true); } hideAnnotation(annotationId) { this.annotationFacade.setAnnotationsVisibility([annotationId], false); } goToAnnotation(annotationId) { this.viewer.goToAnnotation(annotationId); } updateAnnotationName(annotationId, newName) { const annotation = this.annotationFacade.annotationMap()[annotationId]; if (annotation) { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_12__.rename)(annotation, newName)); } } confirmDeleteSelectedAnnotations(target) { const selectedIds = this.selectedAnnotationIds(); if (selectedIds.length === 0) return; this.confirmDeletion(selectedIds, selectedIds.length > 1 ? 'selected' : 'single', target); } confirmDeleteSingleAnnotation(annotationId, target) { this.confirmDeletion([annotationId], 'single', target); } buildRenameLabels() { return { cancelLabel: this.translate.instant('common.cancel'), header: this.translate.instant('annotationMenu.renameHeader'), inputLabel: this.translate.instant('common.name'), saveLabel: this.translate.instant('common.save') }; } /** "Rename" for a type with preset names: a submenu-only row (no click action of its own, * same as every other submenu item here) listing each preset plus a trailing "Custom…" * entry that opens the popup dialog. Types with no suggestions fall back to a plain item * whose click opens the dialog directly - there'd be nothing to show in a submenu. */ renameMenuItem(suggestions, onSelectSuggestion, openDialog) { const label = this.translate.instant('common.rename'); if (!suggestions || suggestions.length === 0) { return { command: openDialog, icon: 'typography', label }; } return { icon: 'typography', items: [...suggestions.map(name => ({ command: () => onSelectSuggestion(name), label: name })), { separator: true }, { command: openDialog, label: this.translate.instant('annotationMenu.renameCustom') }], label }; } // eslint-disable-next-line sonarjs/cyclomatic-complexity menuItemsForAnnotation(annotation, pointIndex) { const renameLabels = this.buildRenameLabels(); const menuItems = [{ command: () => { this.viewer.goToAnnotation(annotation.id); }, disabled: !(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_9__.isRenderable)(annotation), icon: 'target', includeInCard: true, label: this.translate.instant('annotationMenu.goToAnnotation', { name: annotation.name }) }]; const relativeItems = this.relativeMeasurementsSubmenu(annotation); if (relativeItems.length > 0) { menuItems.push({ separator: true }, { icon: 'relative-measurements', items: relativeItems, label: this.translate.instant('annotationMenu.relativeMeasurements.label') }); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsObject3D)(annotation)) { menuItems.push({ separator: true }, ...this.object3DMenuItems(annotation)); } if (annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.AnnotationSourceType.CLOSED_SPLINE) { menuItems.push({ separator: true }, { command: () => this.deviceSizingChart.open(annotation.id), icon: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.TABLE, includeInCard: true, label: this.translate.instant('annotationMenu.deviceSizingChart') }, { command: () => { this.sCurveFacade.selectSCurves([annotation.id]); this.uiFacade.openSidebarSection(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.SidebarSection.SCURVE); }, icon: 's-curve', includeInCard: true, label: this.translate.instant('annotationMenu.optimalProjectionCurve') }); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsSpline)(annotation) && this.interactionModeService.interactionMode().type === 'select') { menuItems.push({ command: () => { this.interactionModeService.startAddingPoints(annotation.id); }, icon: 'plus', label: this.translate.instant('annotationMenu.addPointsToSpline') }); if (pointIndex !== undefined && annotation.points.length > 2) { menuItems.push({ command: () => { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_12__.removePointAt)(annotation, pointIndex)); }, icon: 'minus', label: this.translate.instant('annotationMenu.removePointFromSpline') }); } } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsSpline)(annotation)) { menuItems.push({ command: () => { this.cprService.start(annotation); this.uiFacade.openSidebarSection(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.SidebarSection.PLANAR_REFORMATION); }, icon: 'curve', label: this.translate.instant('annotationMenu.planarReformation') }); } menuItems.push({ separator: true }, { command: () => { this.annotationFacade.setAnnotationsVisibility([annotation.id], annotation.hidden); }, icon: annotation.hidden ? 'eye' : 'eye-off', label: annotation.hidden ? this.translate.instant('common.show') : this.translate.instant('common.hide') }); const selectedIdCount = this.selectedAnnotationIds().length; if (selectedIdCount > 1) { const hiddenIds = this.hiddenSelectedAnnotationIds(); const visibleIds = this.visibleSelectedAnnotationIds(); menuItems.push({ separator: true }, { command: () => { this.annotationFacade.setAnnotationsVisibility(hiddenIds, true); }, disabled: hiddenIds.length === 0, icon: 'eye', label: this.translate.instant('annotationMenu.showSelectedAnnotations', { count: selectedIdCount }) }, { command: () => { this.annotationFacade.setAnnotationsVisibility(visibleIds, false); }, disabled: visibleIds.length === 0, icon: 'eye-off', label: this.translate.instant('annotationMenu.hideSelectedAnnotations', { count: selectedIdCount }) }, { separator: true }); } menuItems.push(this.renameMenuItem(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.ANNOTATION_STRUCTURE_NAMES[annotation.type], name => this.updateAnnotationName(annotation.id, name), () => this.annotationFacade.openRenameDialog(annotation, renameLabels)), { annotation, customType: 'color-swatch', icon: 'palette' }, { items: [{ annotation, customType: 'color-swatch-full' }], label: this.translate.instant('annotationMenu.otherColor') }, { separator: true }); if (selectedIdCount > 1) { menuItems.push({ command: event => this.confirmDeleteSelectedAnnotations(event.originalEvent?.target ?? undefined), icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteSelectedAnnotations', { count: selectedIdCount }), linkClass: DESTRUCTIVE_CLASSES }); } else { menuItems.push({ command: event => this.confirmDeleteSingleAnnotation(annotation.id, event.originalEvent?.target ?? undefined), icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteAnnotation'), linkClass: DESTRUCTIVE_CLASSES }); } return menuItems; } object3DMenuItems(annotation) { const items = [{ command: () => this.viewer.openEditOrientation(annotation.id), disabled: annotation.locked, icon: 'rotation-3d', label: this.translate.instant('annotationMenu.editOrientation.label') }, { disabled: annotation.locked, icon: 'align-horizontal-center', items: this.alignWithItems(annotation), label: this.translate.instant('annotationMenu.alignWith') }, { command: () => this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_12__.toggleLock)(annotation)), icon: annotation.locked ? 'lock-open' : 'lock', label: annotation.locked ? this.translate.instant('annotationMenu.unlock') : this.translate.instant('annotationMenu.lock') }]; if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsStl)(annotation)) { items.unshift(this.modelGeometrySubmenu(annotation)); } return items; } /** * Build the "Align with …" menu items (orthogonal views and closed splines). * Shared by the context-menu submenu and the orientation dialog button. */ alignWithItems(target, onAfterAlign) { const viewItems = ALIGN_VIEWS.map(({ axis, color, key }) => ({ command: () => { this.modelGeometry.alignWithViewport(target, axis); onAfterAlign?.(); }, disabled: target.locked, icon: 'fullscreen', iconStyle: { color }, label: this.translate.instant(`annotationMenu.editOrientation.views.${key}`) })); const splineItems = this.annotationFacade.annotations().filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsClosedSpline)(annotation)).map(spline => ({ command: () => { this.modelGeometry.alignWithSpline(target, spline); onAfterAlign?.(); }, disabled: target.locked, icon: 'closed-spline', iconStyle: { color: spline.color }, label: spline.name })); return splineItems.length > 0 ? [...viewItems, { separator: true }, ...splineItems] : viewItems; } modelGeometrySubmenu(stl) { const label = key => this.translate.instant(`annotationMenu.modelGeometry.${key}`); return { disabled: stl.locked, icon: 'architecture', items: [{ command: () => this.modelGeometry.flipAxis(stl), icon: 'sync', label: label('flipAxis') }, { separator: true }, { command: () => this.modelGeometry.resetOrientation(stl), icon: 'refresh', label: label('resetOrientation') }], label: label('label') }; } menuItemsForPanelAnnotations(expandCallback) { return (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { hiddenIds, visibleIds } = this.annotationIdsByVisibility(); const ids = [...visibleIds, ...hiddenIds]; if (ids.length === 0) return []; return [{ command: () => this.annotationFacade.setAnnotationsVisibility(hiddenIds, true), disabled: hiddenIds.length === 0, icon: 'eye', label: this.translate.instant('annotationMenu.showAllAnnotationsOnScreen') }, { command: () => this.annotationFacade.setAnnotationsVisibility(visibleIds, false), disabled: visibleIds.length === 0, icon: 'eye-off', label: this.translate.instant('annotationMenu.hideAllAnnotationsOnScreen') }, { separator: true }, { command: () => expandCallback(ids), icon: 'eye', label: this.translate.instant('annotationMenu.showAllCardsDetails') }, { command: () => expandCallback([]), icon: 'eye-off', label: this.translate.instant('annotationMenu.hideAllCardsDetails') }, { separator: true }, { command: event => this.confirmDeletion(ids, 'all', event.originalEvent?.target ?? undefined), icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteAllAnnotations'), linkClass: DESTRUCTIVE_CLASSES }]; }); } /** Picks the first palette color not already used by an existing s-curve * (spline-derived or control-point) or relative measurement, so a * newly-created curve never duplicates a color already on the graph. */ nextAvailableSCurveColor() { const usedColors = new Set([...this.sCurveFacade.relativeMeasurements().map(({ color }) => color), ...this.sCurveFacade.sCurves().map(({ color }) => color)]); const available = this.colorsService.colors.find(color => !usedColors.has(color)); return available ?? this.colorsService.currentColor(); } openCreateSCurveDialog(pointCount) { const dialog = this.dialogService.open(_create_s_curve_dialog_create_s_curve_dialog_component__WEBPACK_IMPORTED_MODULE_16__.CreateSCurveDialogComponent, { closeOnEscape: true, header: this.translate.instant(pointCount === 1 ? 'annotationMenu.createOnePointSCurve' : 'annotationMenu.createTwoPointSCurve'), inputValues: { pointCount }, modal: true, width: '360px' }); dialog?.onClose.subscribe(controlPoints => { if (!controlPoints) return; const existingNames = this.sCurveFacade.sCurves().map(({ name }) => name); const sCurve = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.controlPointSCurve)({ color: this.nextAvailableSCurveColor(), controlPoints, hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.incrementName)(pointCount === 1 ? 'One-point S-curve' : 'Two-point S-curve', existingNames, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.ANNOTATION_NAME_MAX_LENGTH) }); this.sCurveFacade.addSCurve(sCurve); this.sCurveFacade.selectSCurves([sCurve.id]); }); } openEditSCurveViewsDialog(sCurve) { const pointCount = sCurve.controlPoints.length; const dialog = this.dialogService.open(_create_s_curve_dialog_create_s_curve_dialog_component__WEBPACK_IMPORTED_MODULE_16__.CreateSCurveDialogComponent, { closeOnEscape: true, header: this.translate.instant(pointCount === 1 ? 'annotationMenu.createOnePointSCurve' : 'annotationMenu.createTwoPointSCurve'), inputValues: { initialControlPoints: sCurve.controlPoints, pointCount }, modal: true, width: '360px' }); dialog?.onClose.subscribe(controlPoints => { if (!controlPoints) return; this.sCurveFacade.updateSCurve({ controlPoints, id: sCurve.id }); }); } menuItemsForPanelSCurves(expandCallback) { return (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { hiddenIds, visibleIds } = this.sCurveIdsByVisibility(); const ids = [...visibleIds, ...hiddenIds]; const items = [{ command: () => this.openCreateSCurveDialog(1), icon: 's-curve', label: this.translate.instant('annotationMenu.createOnePointSCurve') }, { command: () => this.openCreateSCurveDialog(2), icon: 's-curve', label: this.translate.instant('annotationMenu.createTwoPointSCurve') }]; if (ids.length === 0) return items; items.push({ separator: true }, { command: () => { this.sCurveFacade.setSCurveVisibility(hiddenIds, true); }, disabled: hiddenIds.length === 0, icon: 'eye', label: this.translate.instant('annotationMenu.showAllSCurvesOnGraph') }, { command: () => { this.sCurveFacade.setSCurveVisibility(visibleIds, false); }, disabled: visibleIds.length === 0, icon: 'eye-off', label: this.translate.instant('annotationMenu.hideAllSCurvesOnGraph') }, { separator: true }); if (expandCallback !== undefined) { items.push({ command: () => expandCallback(ids), icon: 'eye', label: this.translate.instant('annotationMenu.showAllCardsDetails') }, { command: () => expandCallback([]), icon: 'eye-off', label: this.translate.instant('annotationMenu.hideAllCardsDetails') }, { separator: true }); } // Spline-derived s-curves are synced from their spline annotation and // would just reappear — only control-point (from-scratch) curves are // actually deletable here. const controlPointIds = this.sCurveFacade.sCurves().filter(sCurve => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.sCurveIsControlPoint)(sCurve)).map(({ id }) => id); items.push({ command: () => this.sCurveFacade.deleteSCurves(controlPointIds), disabled: controlPointIds.length === 0, icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteAllSCurves'), linkClass: DESTRUCTIVE_CLASSES }); return items; }); } confirmDeletion(ids, mode, target) { const translationKeyByMode = { all: 'annotationMenu.confirmDeleteAll', selected: 'annotationMenu.confirmDeleteSelected', single: 'annotationMenu.confirmDeleteAnnotation' }; const translationKey = translationKeyByMode[mode]; this.confirmationService.confirm({ accept: () => this.annotationFacade.deleteAnnotations(ids), acceptButtonProps: { label: this.translate.instant(`${translationKey}.cta.accept`), severity: 'danger' }, acceptLabel: this.translate.instant(`${translationKey}.cta.accept`), defaultFocus: 'accept', header: this.translate.instant(`${translationKey}.title`), icon: 'exclamation-triangle', message: this.translate.instant(`${translationKey}.message`, { count: ids.length }), rejectButtonProps: { label: this.translate.instant('common.cancel'), outlined: true, severity: 'secondary' }, target: target ?? undefined }); } menuItemsForViewport() { const { hiddenIds, visibleIds } = this.annotationIdsByVisibility(); const { annotationFacade, viewportStore } = this; const items = [{ command: () => this.viewer.resetAngulations(), icon: 'refresh', label: this.translate.instant('viewerMenu.cta.resetAngulations') }, { command: () => this.chamberService.createNewChamber({ angulation: this.viewportStore.viewportAngulations[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportAxisState.MIDDLEMAIN](), ax: this.viewportStore.ax(), crosshairRotation: this.viewportStore.viewportCrosshairRotations[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.ViewportAxisState.MIDDLEMAIN](), intersection: this.viewportStore.intersection(), isocenter: this.viewportStore.isocenter(), isPosterior: this.viewportStore.isPosterior() }), icon: 'camera', label: this.translate.instant('viewportButton.addChamberLabel') }, { separator: true }, { command: () => this.annotationFacade.setAnnotationsVisibility(hiddenIds, true), disabled: hiddenIds.length === 0, icon: 'eye', label: this.translate.instant('annotationMenu.showAllAnnotationsOnScreen') }, { command: () => this.annotationFacade.setAnnotationsVisibility(visibleIds, false), disabled: visibleIds.length === 0, icon: 'eye-off', label: this.translate.instant('annotationMenu.hideAllAnnotationsOnScreen') }, { separator: true }]; const showCrosshairs = this.viewportStore.showCrosshairs(); if (showCrosshairs) { items.push({ command: () => { this.viewportStore.updateCrosshairVisibility(false); }, icon: REFERENCE_LINES_ICON, label: this.translate.instant('viewerMenu.cta.hideReferencePlanes') }); } else { items.push({ command: () => { this.viewportStore.updateCrosshairVisibility(true); }, icon: REFERENCE_LINES_ICON, label: this.translate.instant('viewerMenu.cta.showReferencePlanes') }); } items.push({ disabled: true, icon: 'mouse-pointer', label: this.translate.instant('viewerMenu.cta.showHideOnScreenControls') }, { command: () => this.saveScreenshots(), icon: 'screenshot', label: this.translate.instant('viewerMenu.cta.saveScreenshots') }, { command: () => this.windowService.toggleFullscreen(), icon: 'expand', label: this.windowService.isFullscreen() ? this.translate.instant('viewerMenu.cta.exitFullscreen') : this.translate.instant('viewerMenu.cta.fullscreen') }, { separator: true }, { customType: 'slider', icon: 'screen-rotation', label: this.translate.instant('viewerMenu.cta.viewRotation'), slider: { max: 180, min: -180, onReset: () => { this.viewportStore.rotateAX(0); }, onSliderChange: value => { this.viewportStore.rotateAX(this.viewportStore.isPosterior() ? -value : value); }, showReset: true, step: 1, get value() { return viewportStore.isPosterior() ? -viewportStore.ax() : viewportStore.ax(); } } }, { separator: true }, { customType: 'slider', icon: 'pencil', label: this.translate.instant('viewerMenu.cta.annotationSize'), showReset: false, slider: { max: 5, min: 0.5, onReset: () => { this.annotationFacade.setAnnotationSize(_volume_viewer_annotation_actors_annotation_updaters_constants__WEBPACK_IMPORTED_MODULE_21__.DEFAULT_ANNOTATION_RADIUS); }, onSliderChange: value => { this.annotationFacade.setAnnotationSize(value); }, showReset: true, step: 0.1, get value() { return annotationFacade.annotationSize(); } } }, { customType: 'slider', icon: REFERENCE_LINES_ICON, label: this.translate.instant('viewerMenu.cta.crosshairSize'), showReset: false, slider: { max: 10, min: 1, onReset: () => { this.viewportStore.updateCrosshairSize(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.DEFAULT_CROSSHAIR_SIZE); }, onSliderChange: value => { this.viewportStore.updateCrosshairSize(value); }, showReset: true, step: 0.1, get value() { return viewportStore.crosshairSize(); } } }, { separator: true }, { customType: 'toggle', icon: 'posterior', label: this.translate.instant('viewerMenu.cta.posterior'), toggle: { onChange: () => { this.viewer.updateIsPosterior(!this.viewer.isPosterior()); }, value: this.viewer.isPosterior() } }, { separator: true }, { items: [{ command: () => this.viewer.toggleEndoDevPanel(), label: 'Endo Preset Tuner' }, { command: () => this.viewer.toggleVascularDevPanel(), label: 'Vascular Render Tuner' }, { command: () => this.viewer.toggleRenderQualityDevPanel(), label: 'Render Quality Tuner' }, ...(this.isDevBuild ? [{ customType: 'toggle', icon: 'refresh', label: 'Clear local DICOM on startup', toggle: { onChange: value => this.devOptions.set('clearDicomCacheOnStartup', value), value: this.devOptions.clearDicomCacheOnStartup() } }] : [])], label: 'Advanced' }); return items; } menuItemsForAngulationMenu(viewportAxisState) { const items = [{ command: () => this.viewer.copyAngulations(viewportAxisState), icon: 'copy', label: this.translate.instant('viewerMenu.cta.copyAngulations') }]; return items; } menuItemsForSCurve(sCurve) { // Not marked `includeInCard` - the s-curve card already renders its own // dedicated visibility button in the header, so including it here too // would duplicate it in the card's expanded content-actions column. const items = [{ command: () => { this.sCurveFacade.setSCurveVisibility([sCurve.id], sCurve.hidden); }, icon: sCurve.hidden ? 'eye' : 'eye-off', label: sCurve.hidden ? this.translate.instant('common.show') : this.translate.instant('common.hide') }]; const otherCurves = this.sCurveFacade.sCurves().filter(other => other.id !== sCurve.id); if (otherCurves.length > 0) { items.push({ separator: true }, { icon: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.ANGLE, items: otherCurves.map(other => ({ command: () => this.sCurveRelativeMeasurements.createAngle(sCurve, other), icon: other.type === 'spline' ? _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.CLOSEDSPLINE : _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.SCURVE, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translate.instant('annotationMenu.sCurveRelativeMeasurements.angleTo') }, { icon: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.POINT, items: otherCurves.map(other => ({ command: () => this.sCurveRelativeMeasurements.createIntersection(sCurve, other), icon: other.type === 'spline' ? _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.CLOSEDSPLINE : _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.UiSvgIcon.SCURVE, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translate.instant('annotationMenu.sCurveRelativeMeasurements.intersectionWith') }); } // Spline-derived s-curves inherit the spline's name / color / etc if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.sCurveIsControlPoint)(sCurve)) { const renameLabels = this.buildRenameLabels(); items.push({ command: () => this.openEditSCurveViewsDialog(sCurve), icon: 'pencil', label: this.translate.instant('annotationMenu.editViews') }, { command: () => this.sCurveFacade.openRenameDialog(sCurve, renameLabels), icon: 'typography', label: this.translate.instant('common.rename') }, { annotation: sCurve, customType: 'color-swatch', icon: 'palette' }, { items: [{ annotation: sCurve, customType: 'color-swatch-full' }], label: this.translate.instant('annotationMenu.otherColor') }); const selectedIds = this.selectedSCurveIds(); const selectedIdCount = selectedIds.length; if (selectedIdCount > 1) { const selectedControlPointIds = this.sCurveFacade.sCurves().filter(curve => selectedIds.includes(curve.id) && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.sCurveIsControlPoint)(curve)).map(({ id }) => id); items.push({ command: () => this.sCurveFacade.deleteSCurves(selectedControlPointIds), disabled: selectedControlPointIds.length === 0, icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteSelectedSCurves', { count: selectedControlPointIds.length }), linkClass: DESTRUCTIVE_CLASSES }); } else { items.push({ command: () => this.sCurveFacade.deleteSCurves([sCurve.id]), icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteSCurve'), linkClass: DESTRUCTIVE_CLASSES }); } } return items; } menuItemsForSCurveRelativeMeasurement(measurement) { const renameLabels = this.buildRenameLabels(); return [{ command: () => this.sCurveRelativeMeasurements.goTo(measurement), disabled: !this.sCurveRelativeMeasurements.hasGoToTarget(measurement), icon: 'target', label: this.translate.instant('annotationMenu.goToAnnotation', { name: measurement.name }) }, // Not marked `includeInCard` - the measurement card already renders its own // dedicated visibility button in the header, so including it here too // would duplicate it in the card's expanded content-actions column. { command: () => { this.sCurveFacade.updateRelativeMeasurement({ hidden: !measurement.hidden, id: measurement.id }); }, icon: measurement.hidden ? 'eye' : 'eye-off', label: measurement.hidden ? this.translate.instant('common.show') : this.translate.instant('common.hide') }, { command: () => this.sCurveFacade.openRenameDialog(measurement, renameLabels), icon: 'typography', label: this.translate.instant('common.rename') }, { annotation: measurement, customType: 'color-swatch', icon: 'palette' }, { items: [{ annotation: measurement, customType: 'color-swatch-full' }], label: this.translate.instant('annotationMenu.otherColor') }, { command: () => this.sCurveFacade.deleteSCurves([measurement.id]), icon: 'trash', iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('annotationMenu.deleteSCurveRelativeMeasurement'), linkClass: DESTRUCTIVE_CLASSES }]; } saveScreenshots() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const timestamp = new Date().toISOString().replaceAll(':', '-').replaceAll('.', '-'); yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.saveScreenshots)({ document: _this.document, outputFileName: `tomoverse-screenshots-${timestamp}.zip`, selectors: ['#' + _volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_23__.VIEWPORT_IDS.AXIAL, '#' + _volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_23__.VIEWPORT_IDS.CORONAL, '#' + _volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_23__.VIEWPORT_IDS.SAGITTAL, '#' + _volume_viewer_viewport_ids__WEBPACK_IMPORTED_MODULE_23__.VIEWPORT_IDS.REFORMAT] }); })(); } // eslint-disable-next-line sonarjs/cyclomatic-complexity relativeMeasurementsSubmenu(annotation) { const otherAnnotations = this.annotationFacade.annotations().filter(other => other.id !== annotation.id); const menuItems = []; if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsClosedSpline)(annotation)) { const otherSplines = otherAnnotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsClosedSpline)(annotation)); if (otherSplines.length > 0) { menuItems.push({ icon: 'angle', items: otherSplines.map(other => ({ command: () => { this.relativeMeasurements.angleBetweenSplines(annotation, other); }, icon: other.type, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translateLabel('angleBetweenSplines') }, { icon: 'angle', items: otherSplines.map(other => ({ command: () => { this.relativeMeasurements.angleBetweenSplineAxes(annotation, other); }, icon: other.type, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translateLabel('angleBetweenSplineAxes') }); } } if (annotation.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.AnnotationSourceType.POINT) { menuItems.push({ command: () => { this.relativeMeasurements.attachedDistance(annotation); }, icon: 'distance', label: this.translateLabel('attachedDistance'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }, { command: () => { this.relativeMeasurements.attachedPoint(annotation); }, icon: 'point', label: this.translateLabel('attachedPoint'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }, { command: () => { this.relativeMeasurements.attachedSpline(annotation); }, icon: 'open-spline', label: this.translateLabel('attachedSpline'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }, { command: () => { this.relativeMeasurements.centerDistance(annotation); }, icon: 'distance', label: this.translateLabel('centerDistance'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsSpline)(annotation) || annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.AnnotationSourceType.ANGLE) { menuItems.push({ command: () => { this.relativeMeasurements.chord(annotation); }, icon: 'distance', label: this.translateLabel('chord'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } if (annotation.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_8__.AnnotationSourceType.POINT) { menuItems.push({ command: () => { this.relativeMeasurements.closestDistance(annotation); }, icon: 'distance', label: this.translateLabel('closestDistanceToOneAnnotation'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsPoint)(annotation)) { const otherSplines = otherAnnotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsSpline)(annotation)); if (otherSplines.length > 0) { menuItems.push({ icon: 'distance', items: otherSplines.map(other => ({ command: () => { this.relativeMeasurements.projectedDistanceFromPoint(other, annotation); }, icon: other.type, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translateLabel('projectedDistanceFromPoint'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsSpline)(annotation)) { menuItems.push({ command: () => { this.relativeMeasurements.curvaturePoint(annotation); }, icon: 'point', label: this.translateLabel('curvaturePoint'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }, { command: () => { this.relativeMeasurements.projectedDistance(annotation); }, icon: 'distance', label: this.translateLabel('projectedDistance'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); const otherPoints = otherAnnotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsPoint)(annotation)); if (otherPoints.length > 0) { menuItems.push({ icon: 'distance', items: otherPoints.map(other => ({ command: () => { this.relativeMeasurements.projectedDistanceFromPoint(annotation, other); }, icon: other.type, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translateLabel('projectedDistanceFromPoint'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } } // We aren't supporting Object3D with distance between currently, // this may come in a future ticket. const otherNonObject3Ds = otherAnnotations.filter(annotation => !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsObject3D)(annotation)); if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.annotationIsObject3D)(annotation) && otherNonObject3Ds.length > 0) { menuItems.push({ icon: 'distance', items: otherNonObject3Ds.map(other => ({ command: () => { this.relativeMeasurements.closestDistanceBetween(annotation, other); }, icon: other.type, iconStyle: { color: other.color }, label: other.name, labelClass: ANNOTATION_LABEL_CLASS })), label: this.translateLabel('closestDistanceBetweenAnnotations'), labelClass: RELATIVE_MEASUREMENT_LABEL_CLASS }); } return menuItems.toSorted((a, b) => (a.label ?? 'z').localeCompare(b.label ?? 'z')); } translateLabel(key) { return this.translate.instant(`annotationMenu.relativeMeasurements.${key}`); } static ɵfac = function AnnotationMenuItemService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationMenuItemService)(); }; static ɵprov = /*@__PURE__*/_angular_common__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: AnnotationMenuItemService, factory: AnnotationMenuItemService.ɵfac }); } /***/ }, /***/ 45731 /*!*******************************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/components/annotation-menu-item.component.ts ***! \*******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationMenuItemComponent: () => (/* binding */ AnnotationMenuItemComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_ripple__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/ripple */ 73271); /* harmony import */ var primeng_slider__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/slider */ 31486); /* harmony import */ var primeng_toggleswitch__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/toggleswitch */ 79945); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../colors/colors.service */ 39298); /* harmony import */ var _color_swatch_menu_item_color_swatch_menu_item_component__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./color-swatch-menu-item/color-swatch-menu-item.component */ 75971); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ root: "size-7.5 p-0" }); function AnnotationMenuItemComponent_Case_0_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](0, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("click", function AnnotationMenuItemComponent_Case_0_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](1, "lib-color-swatch-menu-item", 5); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("annotation", ctx_r1.item().annotation)("colors", ctx_r1.fullColors); } } function AnnotationMenuItemComponent_Case_1_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](0, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("click", function AnnotationMenuItemComponent_Case_1_Template_span_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](1, "lib-icon", 7)(2, "lib-color-swatch-menu-item", 8); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("icon", ctx_r1.item().icon ?? "palette")("iconStyle", ctx_r1.item().iconStyle); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("annotation", ctx_r1.item().annotation)("colors", ctx_r1.colors); } } function AnnotationMenuItemComponent_Case_2_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](0, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("click", function AnnotationMenuItemComponent_Case_2_Template_span_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](1, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](4, "p-toggleswitch", 11); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("ngModelChange", function AnnotationMenuItemComponent_Case_2_Template_p_toggleswitch_ngModelChange_4_listener($event) { let tmp_2_0; _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]((tmp_2_0 = ctx_r1.item().toggle) == null ? null : tmp_2_0.onChange == null ? null : tmp_2_0.onChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"]()(); } if (rf & 2) { let tmp_5_0; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("icon", ctx_r1.item().icon ?? "palette")("iconStyle", ctx_r1.item().iconStyle); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵclassMap"](ctx_r1.cn("p-menu-item-label grow text-sm", ctx_r1.item().labelClass)); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵtextInterpolate1"](" ", ctx_r1.item().label, " "); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("ngModel", ((tmp_5_0 = ctx_r1.item().toggle) == null ? null : tmp_5_0.value) ?? false); } } function AnnotationMenuItemComponent_Case_3_Conditional_9_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](0, "p-button", 16); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("click", function AnnotationMenuItemComponent_Case_3_Conditional_9_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r7); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); const currentItem_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵreadContextLet"](0); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](currentItem_r6.slider.onReset()); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](1, "lib-icon", 17); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵpureFunction0"](1, _c0)); } } function AnnotationMenuItemComponent_Case_3_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](1, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("click", function AnnotationMenuItemComponent_Case_3_Template_div_click_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](2, "span", 0); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](3, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](4, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementStart"](6, "div", 12)(7, "div", 13)(8, "p-slider", 14); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵlistener"]("ngModelChange", function AnnotationMenuItemComponent_Case_3_Template_p_slider_ngModelChange_8_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5); const currentItem_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵreadContextLet"](0); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](currentItem_r6.slider == null ? null : currentItem_r6.slider.onSliderChange == null ? null : currentItem_r6.slider.onSliderChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵconditionalCreate"](9, AnnotationMenuItemComponent_Case_3_Conditional_9_Template, 2, 2, "p-button", 15); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelementEnd"]()()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); const currentItem_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵstoreLet"](ctx_r1.item()); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵclassMap"](currentItem_r8.styleClass); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("icon", currentItem_r8.icon ?? "palette")("iconStyle", currentItem_r8.iconStyle); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵclassMap"](ctx_r1.cn("p-menu-item-label text-sm", currentItem_r8.labelClass)); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵtextInterpolate1"](" ", currentItem_r8.label, " "); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("min", currentItem_r8.slider.min ?? 0)("max", currentItem_r8.slider.max ?? 100)("step", currentItem_r8.slider.step ?? 1)("ngModel", currentItem_r8.slider.value); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵconditional"](currentItem_r8.slider.showReset ? 9 : -1); } } function AnnotationMenuItemComponent_Case_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵelement"](0, "lib-menu-item", 3); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵproperty"]("item", ctx_r1.item()); } } class AnnotationMenuItemComponent { item = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "item" }] : [])); colors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_9__.ColorsService).pickerColors; fullColors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_9__.ColorsService).fullPickerColors; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.cn; static ɵfac = function AnnotationMenuItemComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationMenuItemComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵdefineComponent"]({ type: AnnotationMenuItemComponent, selectors: [["lib-annotation-menu-item"]], inputs: { item: [1, "item"] }, decls: 5, vars: 1, consts: [[1, "p-menu-item-link"], [1, "p-menu-item-link", "flex"], [3, "class"], [3, "item"], [3, "click"], ["width", "narrow", 3, "annotation", "colors"], [1, "p-menu-item-link", 3, "click"], ["iconClass", "p-menu-item-icon", 1, "size-3.5", 3, "icon", "iconStyle"], [3, "annotation", "colors"], [1, "p-menu-item-link", "flex", 3, "click"], ["iconClass", "p-menu-item-icon size-3.5", 3, "icon", "iconStyle"], [3, "ngModelChange", "ngModel"], [1, "px-4", "py-2"], [1, "flex", "w-full", "items-center", "gap-2"], ["data-test-id", "components-p-slider-slider", 1, "min-w-0", "flex-1", 3, "ngModelChange", "min", "max", "step", "ngModel"], ["data-test-id", "components-p-button-reset-slider", "variant", "text", "severity", "secondary", "rounded", "", 1, "ml-1", "opacity-70", "hover:opacity-100", 3, "pt"], ["data-test-id", "components-p-button-reset-slider", "variant", "text", "severity", "secondary", "rounded", "", 1, "ml-1", "opacity-70", "hover:opacity-100", 3, "click", "pt"], ["icon", "refresh", 1, "size-(--p-app-icon-size-xxs)"]], template: function AnnotationMenuItemComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵconditionalCreate"](0, AnnotationMenuItemComponent_Case_0_Template, 2, 2, "div")(1, AnnotationMenuItemComponent_Case_1_Template, 3, 4, "span", 0)(2, AnnotationMenuItemComponent_Case_2_Template, 5, 6, "span", 1)(3, AnnotationMenuItemComponent_Case_3_Template, 10, 13, "div", 2)(4, AnnotationMenuItemComponent_Case_4_Template, 1, 1, "lib-menu-item", 3); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_11__["ɵɵconditional"]((tmp_0_0 = ctx.item().customType) === "color-swatch-full" ? 0 : tmp_0_0 === "color-swatch" ? 1 : tmp_0_0 === "toggle" ? 2 : tmp_0_0 === "slider" ? 3 : 4); } }, dependencies: [primeng_ripple__WEBPACK_IMPORTED_MODULE_4__.RippleModule, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.IconComponent, _color_swatch_menu_item_color_swatch_menu_item_component__WEBPACK_IMPORTED_MODULE_10__.ColorSwatchMenuItemComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.MenuItemComponent, primeng_toggleswitch__WEBPACK_IMPORTED_MODULE_6__.ToggleSwitchModule, primeng_toggleswitch__WEBPACK_IMPORTED_MODULE_6__.ToggleSwitch, primeng_slider__WEBPACK_IMPORTED_MODULE_5__.SliderModule, primeng_slider__WEBPACK_IMPORTED_MODULE_5__.Slider, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgModel, primeng_button__WEBPACK_IMPORTED_MODULE_3__.Button], encapsulation: 2 }); } /***/ }, /***/ 13609 /*!**************************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/components/annotation-menu.component.ts ***! \**************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationMenuComponent: () => (/* binding */ AnnotationMenuComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var _services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../services/submenu-flip/submenu-flip.service */ 9610); /* harmony import */ var _menu_tracker_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../menu-tracker.service */ 61487); /* harmony import */ var _annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./annotation-menu-item.component */ 45731); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["menu"]; function AnnotationMenuComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](0, "lib-annotation-menu-item", 3); } if (rf & 2) { const item_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("item", item_r2); } } class AnnotationMenuComponent { model = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.model)([], ...(ngDevMode ? [{ debugName: "model" }] : [])); appendTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('body', ...(ngDevMode ? [{ debugName: "appendTo" }] : [])); menu = _angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild.required('menu'); tracker = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_menu_tracker_service__WEBPACK_IMPORTED_MODULE_4__.MenuTrackerService); submenuFlipService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_3__.SubmenuFlipService); menuPt = { root: { // Prevents being able to right-click an open menu and open the native menu oncontextmenu(event) { event.preventDefault(); } }, submenu: { class: 'min-w-0' } }; show(event) { const menu = this.menu(); menu.show(event); this.tracker.trackOpenMenu(menu); this.submenuFlipService.start(); } toggle(event) { const menu = this.menu(); const wasVisible = menu.visible(); menu.toggle(event); if (wasVisible) { this.submenuFlipService.stop(); } else { this.submenuFlipService.start(); } } onMenuHide() { this.submenuFlipService.stop(); } hide() { this.menu().hide(); } ngOnDestroy() { this.submenuFlipService.stop(); } static ɵfac = function AnnotationMenuComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationMenuComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: AnnotationMenuComponent, selectors: [["lib-annotation-menu"]], viewQuery: function AnnotationMenuComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵviewQuerySignal"](ctx.menu, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵqueryAdvance"](); } }, inputs: { model: [1, "model"], appendTo: [1, "appendTo"] }, outputs: { model: "modelChange" }, features: [_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵProvidersFeature"]([{ provide: primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenu, useExisting: AnnotationMenuComponent }, _services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_3__.SubmenuFlipService])], decls: 4, vars: 3, consts: [["menu", ""], ["item", ""], ["popup", "", 3, "onHide", "pt", "model", "appendTo"], [3, "item"]], template: function AnnotationMenuComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "p-contextmenu", 2, 0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("onHide", function AnnotationMenuComponent_Template_p_contextmenu_onHide_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.onMenuHide()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplate"](2, AnnotationMenuComponent_ng_template_2_Template, 1, 1, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pt", ctx.menuPt)("model", ctx.model())("appendTo", ctx.appendTo()); } }, dependencies: [primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenu, _annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_5__.AnnotationMenuItemComponent], encapsulation: 2 }); } /***/ }, /***/ 75971 /*!********************************************************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/components/color-swatch-menu-item/color-swatch-menu-item.component.ts ***! \********************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ColorSwatchMenuItemComponent: () => (/* binding */ ColorSwatchMenuItemComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); function ColorSwatchMenuItemComponent_For_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdomElementStart"](0, "span", 1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdomListener"]("click", function ColorSwatchMenuItemComponent_For_2_Template_span_click_0_listener() { const color_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.changeColor(color_r2)); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdomElementEnd"](); } if (rf & 2) { const color_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵclassMap"]("block h-7 w-7"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵstyleProp"]("background-color", color_r2); } } function isSCurve(item) { return item.type === 'control-point' || item.type === 'spline'; } class ColorSwatchMenuItemComponent { annotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(...(ngDevMode ? [undefined, { debugName: "annotation" }] : [])); width = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('wide', ...(ngDevMode ? [{ debugName: "width" }] : [])); wide = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.width() === 'wide', ...(ngDevMode ? [{ debugName: "wide" }] : [])); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.AnnotationFacade); sCurveFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.SCurveFacade); colors = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "colors" }] : [])); changeColor(color) { const item = this.annotation(); if (!item) return; if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.sCurveIsRelativeMeasurement)(item)) { this.sCurveFacade.updateRelativeMeasurement({ color, id: item.id }); } else if (isSCurve(item)) { this.sCurveFacade.updateSCurve((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_5__.changeColor)(item, color)); } else { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_5__.changeColor)(item, color)); } } static ɵfac = function ColorSwatchMenuItemComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ColorSwatchMenuItemComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: ColorSwatchMenuItemComponent, selectors: [["lib-color-swatch-menu-item"]], inputs: { annotation: [1, "annotation"], width: [1, "width"], colors: [1, "colors"] }, decls: 3, vars: 2, consts: [[3, "class", "background-color"], [3, "click"]], template: function ColorSwatchMenuItemComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdomElementStart"](0, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵrepeaterCreate"](1, ColorSwatchMenuItemComponent_For_2_Template, 1, 4, "span", 0, _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵrepeaterTrackByIdentity"]); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdomElementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵclassMap"](`flex ${ctx.wide() ? "w-56" : "w-35"} flex-wrap overflow-clip rounded-md`); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵrepeater"](ctx.colors()); } }, encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 12564 /*!**********************************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/directives/annotation-menu-trigger.directive.ts ***! \**********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationMenuTriggerDirective: () => (/* binding */ AnnotationMenuTriggerDirective) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 14975); class AnnotationMenuTriggerDirective { libMenuTrigger = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "libMenuTrigger" }] : [])); libMenuActions = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "libMenuActions" }] : [])); onClick(event) { const menu = this.libMenuTrigger(); const actions = this.libMenuActions(); if (menu && actions.length > 0) { event.stopPropagation(); event.preventDefault(); menu.model.set(actions); menu.toggle(event); } } static ɵfac = function AnnotationMenuTriggerDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationMenuTriggerDirective)(); }; static ɵdir = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineDirective"]({ type: AnnotationMenuTriggerDirective, selectors: [["", "libMenuTrigger", ""]], hostBindings: function AnnotationMenuTriggerDirective_HostBindings(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵlistener"]("click", function AnnotationMenuTriggerDirective_click_HostBindingHandler($event) { return ctx.onClick($event); }); } }, inputs: { libMenuTrigger: [1, "libMenuTrigger"], libMenuActions: [1, "libMenuActions"] } }); } /***/ }, /***/ 61487 /*!**********************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/menu-tracker.service.ts ***! \**********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MenuTrackerService: () => (/* binding */ MenuTrackerService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); class MenuTrackerService { openMenus = []; trackOpenMenu(menu) { this.openMenus.push(menu); } closeTopMenu() { const menu = this.openMenus.pop(); if (menu) { menu.hide(); return true; } return false; } static ɵfac = function MenuTrackerService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MenuTrackerService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: MenuTrackerService, factory: MenuTrackerService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 27113 /*!************************************************************************!*\ !*** ./libs/feature/src/lib/annotation-menu/model-geometry.service.ts ***! \************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ModelGeometryService: () => (/* binding */ ModelGeometryService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); class ModelGeometryService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_2__.AnnotationFacade); geometryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_2__.Object3DGeometryFacade); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_2__.viewportStore); /** Snap an object's orientation to a viewport view, keeping its own axial spin. */ alignWithViewport(annotation, axis) { const view = this.viewportStore.viewportAngulations()[axis]; const { ax } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.angulationFromOrientation)(annotation.orientation); this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setOrientation)(annotation, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.orientationFromAngulation)({ ax, cc: view.cc, rl: view.rl }))); } /** * Snap an object onto a closed spline: orient it en-face to the spline's * best-fit plane and move it to the spline's centroid. */ alignWithSpline(annotation, spline) { const normal = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_1__.getSplineBestFitNormal)(spline); const { cc, rl } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.vectorToAngulation)([normal[0], normal[1], normal[2]]); const { ax } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.angulationFromOrientation)(annotation.orientation); this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.move)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setOrientation)(annotation, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.orientationFromAngulation)({ ax, cc, rl })), (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_1__.getSplineCentroid)(spline))); } /** Flip the mesh 180 deg about its symmetry axis. */ flipAxis(stl) { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setAxisOfSymmetryRotation)(stl, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.flipAxisOfSymmetry)(stl.axisOfSymmetryRotation))); } setAxisOfSymmetry(stl) { const object = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.angulationFromOrientation)(stl.orientation); const view = this.viewportStore.primaryViewportAngulations(); const axisOfSymmetryRotation = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.alignAxisOfSymmetryToView)(stl.axisOfSymmetryRotation, object, view); const orientation = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.orientationFromAngulation)({ ax: object.ax, cc: view.cc, rl: view.rl }); this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setOrientation)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setAxisOfSymmetryRotation)(stl, axisOfSymmetryRotation), orientation)); } /** Move the mesh's pivot to its centroid. */ setCenterOfRotationToCentroid(stl) { const geometry = this.geometryFacade.getGeometry(stl.id); if (!geometry) return; const { centroid } = geometry; this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setCenterOfRotation)(stl, [centroid[0], centroid[1], centroid[2]])); } /** Clear the mesh's orientation back to identity. */ resetOrientation(stl) { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.resetOrientation)(stl)); } /** Recompute the PCA alignment and reset orientation to identity. */ resetSymmetry(stl) { const geometry = this.geometryFacade.getGeometry(stl.id); if (!geometry) return; const { rotationMatrix } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.autoAlignAxis)(geometry.vertices, geometry.centroid); this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.resetOrientation)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_3__.setAxisOfSymmetryRotation)(stl, rotationMatrix))); } static ɵfac = function ModelGeometryService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ModelGeometryService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: ModelGeometryService, factory: ModelGeometryService.ɵfac }); } /***/ }, /***/ 35946 /*!*************************************************************!*\ !*** ./libs/feature/src/lib/card-theme/card-interaction.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ isInteractiveCardDescendant: () => (/* binding */ isInteractiveCardDescendant) /* harmony export */ }); /** * True when a double-click on a card's outer wrapper originated from an interactive descendant * (a button, input, link, or anything marked data-propagate-click) rather than the card's own * background/content. Those elements handle their own double-click semantics (e.g. double-clicking * a rename input to select its text) and shouldn't also trigger the card's goTo action. * * Deliberately excludes [role="button"]: p-accordion-header sets role="button" on its own host * element (for its unrelated expand/collapse toggle), and that host wraps virtually the entire * card header - icon, name, every action button. Matching it here would flag almost every * double-click on the card as "interactive", breaking goTo entirely rather than narrowing it. * * `wrapper` bounds the search to the card's own subtree - without it, .closest() would keep * walking past the card into ancestors it doesn't control (e.g. a parent list item, router link, * or drag-drop container marked data-propagate-click for unrelated reasons), which would * incorrectly suppress goTo for a legitimate double-click on the card's own background. */ function isInteractiveCardDescendant(event, wrapper) { const target = event.target; const match = target?.closest('button, input, a, [data-propagate-click]'); return !!match && wrapper.contains(match); } /***/ }, /***/ 92147 /*!*******************************************************!*\ !*** ./libs/feature/src/lib/card-theme/card-theme.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CARD_BUTTON_STYLE: () => (/* binding */ CARD_BUTTON_STYLE), /* harmony export */ CARD_HOVER_CLASS: () => (/* binding */ CARD_HOVER_CLASS), /* harmony export */ DARK_CARD_THEME: () => (/* binding */ DARK_CARD_THEME), /* harmony export */ buildCardDt: () => (/* binding */ buildCardDt), /* harmony export */ buildCardPt: () => (/* binding */ buildCardPt) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); const TOKEN_CARD = '{app.surface.card}'; const TOKEN_SURFACE_50 = '{surface.50}'; const TOKEN_SURFACE_300 = '{surface.300}'; const TOKEN_SURFACE_400 = '{surface.400}'; const TOKEN_SURFACE_500 = '{surface.500}'; const TOKEN_SURFACE_800 = '{surface.800}'; const CARD_HOVER_CLASS = 'group-hover:bg-(--p-app-surface-card-hover)! !transition-none'; // Header/rail button colors, shared by every card that // hosts p-button chrome inside its accordion panel. const CARD_BUTTON_STYLE = { '--p-button-outlined-secondary-border-color': 'transparent', '--p-button-outlined-secondary-color': 'var(--p-app-neutral-500)', '--p-button-text-secondary-color': 'var(--p-app-neutral-500)' }; // Shared palette for the selectable entity cards (annotation, s-curve). // The protocol cards keep their own state->token tables and use buildCardDt directly. const DARK_CARD_THEME = { default: { bg: TOKEN_CARD, bgHover: '{app.surface.card-hover}', hover: TOKEN_SURFACE_50, icon: TOKEN_SURFACE_500, mutedText: TOKEN_SURFACE_400, text: TOKEN_SURFACE_50 }, disabled: { bg: TOKEN_CARD, bgHover: TOKEN_CARD, hover: TOKEN_SURFACE_500, icon: TOKEN_SURFACE_500, mutedText: TOKEN_SURFACE_500, text: TOKEN_SURFACE_500 }, selected: { bg: TOKEN_SURFACE_800, bgHover: TOKEN_SURFACE_800, hover: TOKEN_SURFACE_50, icon: TOKEN_SURFACE_500, mutedText: TOKEN_SURFACE_300, text: TOKEN_SURFACE_50 } }; function buildCardDt(tokens) { const { bg, hover, icon, text } = tokens; const bgHover = tokens.bgHover ?? bg; const mutedText = tokens.mutedText ?? text; return { colorScheme: { dark: { content: { background: bg, color: text, mutedColor: mutedText }, header: { activeBackground: bg, activeColor: text, activeHoverBackground: bgHover, activeHoverColor: hover, background: bg, color: text, hoverBackground: bgHover, hoverColor: hover, toggleIcon: { activeColor: icon, activeHoverColor: icon, color: icon, hoverColor: icon } } }, // TODO: design. Stock Aura light placeholders, keep keys symmetric with `dark`. light: { content: { background: '{content.background}', color: '{text.color}', mutedColor: '{text.muted.color}' }, header: { activeBackground: '{content.background}', activeColor: '{text.color}', activeHoverBackground: '{content.background}', activeHoverColor: '{text.hover.color}', background: '{content.background}', color: '{text.color}', hoverBackground: '{content.background}', hoverColor: '{text.hover.color}', toggleIcon: { activeColor: '{text.muted.color}', activeHoverColor: '{text.color}', color: '{text.muted.color}', hoverColor: '{text.color}' } } } } }; } function buildCardPt(pt, state) { const hoverClass = state === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.CardState.DEFAULT ? CARD_HOVER_CLASS : ''; return { ...pt, content: { ...pt?.content, content: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.cn)('ml-5 mr-1 px-0', hoverClass, pt?.content?.content) }, header: { ...pt?.header, root: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.cn)('flex-row gap-3 rounded-none pr-1 justify-start min-h-[2.5rem]', hoverClass, pt?.header?.root), toggleicon: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.cn)('toggle-icon', pt?.header?.toggleicon) }, panel: { ...pt?.panel, root: { class: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.cn)('py-0 flex w-full border-none', hoverClass, pt?.panel?.root), style: { backgroundColor: 'var(--p-accordion-header-background)' } } }, wrapper: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.cn)(hoverClass, pt?.wrapper) }; } /***/ }, /***/ 69605 /*!*****************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-card/chamber-card.component.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberCardComponent: () => (/* binding */ ChamberCardComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _card_theme_card_interaction__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../../card-theme/card-interaction */ 35946); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../card-theme/card-theme */ 92147); /* harmony import */ var _chamber_menu_directives_chamber_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../chamber-menu/directives/chamber-menu-trigger.directive */ 65937); const _c0 = ["nameInput"]; const _c1 = ["nameLabel"]; const _c2 = ["suggestionsPopover"]; const _c3 = ["suggestionButton"]; const _c4 = () => ({ root: "size-6 shrink-0" }); const _c5 = () => ({ root: "py-1 px-0" }); const _c6 = () => ({ color: "var(--p-accordion-header-toggle-icon-color)" }); const _c7 = a0 => ({ secondary: a0 }); const _c8 = a0 => ({ outlined: a0 }); const _forTrack0 = ($index, $item) => $item.icon; function ChamberCardComponent_ng_container_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_Conditional_5_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](0, ChamberCardComponent_Conditional_5_ng_container_0_Template, 1, 0, "ng-container", 16); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const dragHandle_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](33); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", dragHandle_r2); } } function ChamberCardComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 27); } if (rf & 2) { const active_r3 = ctx.active; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("p-accordionheader-toggle-icon size-(--p-app-icon-size-xxs) text-(length:--p-app-icon-size-xxs)", !ctx_r3.cdkDrag() && "ml-2.5")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", active_r3 ? "chevron-down" : "chevron-right"); } } function ChamberCardComponent_ng_container_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_ng_container_11_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_Conditional_13_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](0, ChamberCardComponent_Conditional_13_ng_container_0_Template, 1, 0, "ng-container", 16); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const moreMenuBtn_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](39); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", moreMenuBtn_r5); } } function ChamberCardComponent_ng_container_15_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_ng_container_27_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0); } } function ChamberCardComponent_ng_template_28_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 28); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleProp"]("background-color", ctx_r3.selected() ? ctx_r3.accentColor() : ""); } } function ChamberCardComponent_ng_template_30_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](1, "lib-icon", 29); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("flex size-7 shrink-0 items-center justify-center rounded-full bg-(--p-app-surface-icon-holder)")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleProp"]("color", ctx_r3.chamber().color); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", "camera"); } } function ChamberCardComponent_ng_template_32_div_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 32); } } function ChamberCardComponent_ng_template_32_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 30); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](2, ChamberCardComponent_ng_template_32_div_2_Template, 1, 0, "div", 31); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("order-first size-3 px-1.5 py-3 text-(--p-accordion-header-toggle-icon-hover-color) opacity-0", ctx_r3.readOnly() ? "pointer-events-none" : "cursor-grab transition-opacity delay-100 group-hover:opacity-100 active:cursor-grabbing")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 3, "chamberCard.dragToReorder")); } } function ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 42); } } function ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 41); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("mousedown", function ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_Template_p_button_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.preventDefault()); })("click", function ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.clearChamberName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](3, ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_ng_template_3_Template, 1, 0, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 3, "common.clearName"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](2, 5, "common.clearName"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](7, _c4)); } } function ChamberCardComponent_ng_template_34_Conditional_1_For_9_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "li")(1, "button", 43, 11); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("mousedown", function ChamberCardComponent_ng_template_34_Conditional_1_For_9_Template_button_mousedown_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.preventDefault()); })("click", function ChamberCardComponent_ng_template_34_Conditional_1_For_9_Template_button_click_1_listener($event) { const suggestion_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8).$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); $event.stopPropagation(); $event.preventDefault(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.selectNameSuggestion(suggestion_r9)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const suggestion_r9 = ctx.$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r3.clampedSuggestions().has(suggestion_r9) ? suggestion_r9 : undefined)("tooltipPosition", ctx_r3.clampedSuggestions().has(suggestion_r9) ? "left" : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", suggestion_r9, " "); } } function ChamberCardComponent_ng_template_34_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 34)(1, "div", 36)(2, "input", 37, 8); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_click_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keydown.space", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_keydown_space_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.handleSpace)($event)); })("keydown.enter", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_keydown_enter_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation()($event)); })("keyup.enter", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_keyup_enter_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.updateChamberName)($event)); })("keydown.escape", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_keydown_escape_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation()($event)); })("keyup.escape", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_keyup_escape_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.cancelEditChamberName)($event)); })("blur", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_blur_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.updateChamberName)($event)); })("input", function ChamberCardComponent_ng_template_34_Conditional_1_Template_input_input_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleEventPropagation(ctx_r3.refreshNameSuggestions)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](4, ChamberCardComponent_ng_template_34_Conditional_1_Conditional_4_Template, 5, 8, "p-button", 38); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](5, "p-popover", 39, 9)(7, "ul", 40); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](8, ChamberCardComponent_ng_template_34_Conditional_1_For_9_Template, 4, 3, "li", null, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIdentity"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("id", `chamber-${ctx_r3.chamber().id}-name`)("formControl", ctx_r3.chamberName); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("data-test-id", `chamber-card-input-${ctx_r3.chamber().id}-name`); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r3.chamberName.value ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("appendTo", "body")("dismissable", false); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](ctx_r3.filteredNameSuggestions()); } } function ChamberCardComponent_ng_template_34_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r10 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "button", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function ChamberCardComponent_ng_template_34_Conditional_2_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r10); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameClick($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](1, "span", 45, 12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx_r3.cn("min-w-0 flex-1 cursor-pointer text-left")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r3.isNameClamped() ? ctx_r3.chamber().name : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", ctx_r3.chamber().name, " "); } } function ChamberCardComponent_ng_template_34_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 33); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](1, ChamberCardComponent_ng_template_34_Conditional_1_Template, 10, 6, "div", 34)(2, ChamberCardComponent_ng_template_34_Conditional_2_Template, 4, 4, "button", 35); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r3.isEditing() ? 1 : 2); } } function ChamberCardComponent_ng_template_36_For_2_Conditional_0_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 49); } if (rf & 2) { const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", action_r12.icon)("pTooltip", action_r12.label); } } function ChamberCardComponent_ng_template_36_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r11 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 48); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function ChamberCardComponent_ng_template_36_For_2_Conditional_0_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"]().$implicit; $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](action_r12.command == null ? null : action_r12.command($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](1, ChamberCardComponent_ng_template_36_For_2_Conditional_0_ng_template_1_Template, 1, 2, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ariaLabel", action_r12.label)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](3, _c5))("disabled", action_r12.disabled); } } function ChamberCardComponent_ng_template_36_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](0, ChamberCardComponent_ng_template_36_For_2_Conditional_0_Template, 3, 4, "p-button", 47); } if (rf & 2) { const action_r12 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](action_r12.icon ? 0 : -1); } } function ChamberCardComponent_ng_template_36_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 46); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](1, ChamberCardComponent_ng_template_36_For_2_Template, 1, 1, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](ctx_r3.cardActions()); } } function ChamberCardComponent_ng_template_38_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "lib-icon", 51); } } function ChamberCardComponent_ng_template_38_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "p-button", 50); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](2, ChamberCardComponent_ng_template_38_ng_template_2_Template, 1, 0, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const moreMenuTrigger_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](9, _c8, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](7, _c7, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](6, _c6))))("libChamberMenuTrigger", moreMenuTrigger_r13)("libMenuActions", ctx_r3.actions())("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 4, "common.moreActions")); } } class ChamberCardComponent { cdr = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_2__.ChangeDetectorRef); chamber = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "chamber" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); actions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)([], ...(ngDevMode ? [{ debugName: "actions" }] : [])); selected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(true, { ...(ngDevMode ? { debugName: "selected" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); menuTrigger = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(...(ngDevMode ? [undefined, { debugName: "menuTrigger" }] : [])); readOnly = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(true, { ...(ngDevMode ? { debugName: "readOnly" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); clicked = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); goTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); updateName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); selectedChange = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); cdkDrag = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "cdkDrag" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); filteredNameSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "filteredNameSuggestions" }] : [])); clampedSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(new Set(), ...(ngDevMode ? [{ debugName: "clampedSuggestions" }] : [])); chamberName = new _angular_forms__WEBPACK_IMPORTED_MODULE_6__.FormControl(''); nameMaxLength = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.CHAMBER_NAME_MAX_LENGTH; nameInput = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameInput', ...(ngDevMode ? [{ debugName: "nameInput" }] : [])); isNameClamped = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isNameClamped" }] : [])); nameLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameLabel', ...(ngDevMode ? [{ debugName: "nameLabel" }] : [])); suggestionsPopover = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('suggestionsPopover', ...(ngDevMode ? [{ debugName: "suggestionsPopover" }] : [])); suggestionButtons = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChildren)('suggestionButton', ...(ngDevMode ? [{ debugName: "suggestionButtons" }] : [])); isEditing = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isEditing" }] : [])); structureNameSuggestions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.CHAMBER_STRUCTURE_NAMES, ...(ngDevMode ? [{ debugName: "structureNameSuggestions" }] : [])); mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const pt = this.pt(); const hoverClass = this.getCardState() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DEFAULT ? _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_17__.CARD_HOVER_CLASS : ''; return { ...pt, content: { ...pt?.content, content: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn)('ml-5 mr-1 px-0', hoverClass, pt?.content?.content) }, header: { ...pt?.header, root: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn)('flex-row gap-3 rounded-none pr-1 justify-start min-h-[2.5rem]', hoverClass, pt?.header?.root), toggleicon: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn)('toggle-icon', pt?.header?.toggleicon) }, panel: { ...pt?.panel, root: { class: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn)('py-0 flex w-full border-none', hoverClass, pt?.panel?.root), style: { backgroundColor: 'var(--p-accordion-header-background)' } } }, wrapper: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn)(hoverClass, pt?.wrapper) }; }, ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); accentColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.chamber().hidden ? 'var(--p-text-muted-color)' : this.chamber().color, ...(ngDevMode ? [{ debugName: "accentColor" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_17__.buildCardDt)(_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_17__.DARK_CARD_THEME[this.getCardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); cardActions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.actions().filter(action => action.includeInCard), ...(ngDevMode ? [{ debugName: "cardActions" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_17__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cn; constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.afterEveryRender)(() => { const element = this.nameLabel()?.nativeElement; if (!element) return; const clamped = element.scrollHeight > element.clientHeight; if (clamped !== this.isNameClamped()) this.isNameClamped.set(clamped); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.afterEveryRender)(() => { const clamped = new Set(this.suggestionButtons().filter(({ nativeElement }) => nativeElement.scrollWidth > nativeElement.clientWidth).map(({ nativeElement }) => nativeElement.textContent?.trim() ?? '')); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.isEqualSet)(clamped, this.clampedSuggestions())) this.clampedSuggestions.set(clamped); }); } ngOnInit() { this.chamberName.setValue(this.chamber().name); } contextMenu(event) { if (this.readOnly()) return; if (event.ctrlKey) { event.preventDefault(); this.clicked.emit(event); return; } const trigger = this.menuTrigger(); if (!trigger) return; trigger.model.set(this.actions()); trigger.toggle(event); } handleCardDoubleClick(event) { const wrapper = event.currentTarget; if (this.isEditing() || (0,_card_theme_card_interaction__WEBPACK_IMPORTED_MODULE_16__.isInteractiveCardDescendant)(event, wrapper)) return; this.goTo.emit(); } handleEventPropagation(callback) { return event => { event.stopPropagation(); event.preventDefault(); callback?.(); this.cdr.markForCheck(); }; } updateChamberName = () => { const value = this.chamberName.value ?? ''; if (value.trim().length === 0) { this.isEditing.set(false); return; } this.isEditing.set(false); this.updateName.emit(value); }; cancelEditChamberName = () => { this.isEditing.set(false); }; /** Clears the field's current text (without saving) so a new name can be picked from the * suggestions list with the mouse alone, no backspacing required. */ clearChamberName = () => { this.chamberName.setValue(''); this.refreshNameSuggestions(); this.nameInput()?.nativeElement.focus(); }; handleNameClick(event) { event.stopPropagation(); event.preventDefault(); if (this.readOnly() || this.isEditing()) return; this.chamberName.setValue(this.chamber().name); this.menuTrigger()?.hide(); this.isEditing.set(true); setTimeout(() => this.nameInput()?.nativeElement.focus()); this.cdr.markForCheck(); } refreshNameSuggestions = () => { const allNames = this.structureNameSuggestions(); if (allNames.length === 0) { this.filteredNameSuggestions.set([]); } else { const query = (this.chamberName.value ?? '').trim().toLowerCase(); this.filteredNameSuggestions.set(query ? allNames.filter(name => name.toLowerCase().includes(query)) : allNames); } this.syncSuggestionsPopover(); }; selectNameSuggestion(name) { this.chamberName.setValue(name.slice(0, this.nameMaxLength)); this.updateChamberName(); } syncSuggestionsPopover() { const input = this.nameInput()?.nativeElement; const popover = this.suggestionsPopover(); if (!popover || !input) return; if (this.filteredNameSuggestions().length > 0) { popover.show(undefined, input); } else { popover.hide(); } } handleSpace = () => { const value = this.chamberName.value ?? ''; if (value.length >= this.nameMaxLength) return; this.chamberName.setValue(value + ' '); }; getCardState() { if (this.selected()) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.SELECTED; return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DEFAULT; } angleLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const angulation = this.chamber().cameraOrientation; const posterior = this.chamber().isPosterior; return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.formatAngulation)(angulation, posterior); }, ...(ngDevMode ? [{ debugName: "angleLabel" }] : [])); static ɵfac = function ChamberCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdefineComponent"]({ type: ChamberCardComponent, selectors: [["lib-chamber-card"]], viewQuery: function ChamberCardComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵviewQuerySignal"](ctx.nameInput, _c0, 5)(ctx.nameLabel, _c1, 5)(ctx.suggestionsPopover, _c2, 5)(ctx.suggestionButtons, _c3, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵqueryAdvance"](4); } }, inputs: { chamber: [1, "chamber"], pt: [1, "pt"], actions: [1, "actions"], selected: [1, "selected"], menuTrigger: [1, "menuTrigger"], readOnly: [1, "readOnly"], cdkDrag: [1, "cdkDrag"] }, outputs: { clicked: "clicked", goTo: "goTo", updateName: "updateName", selectedChange: "selectedChange" }, decls: 40, vars: 24, consts: [["panel", ""], ["toggleicon", ""], ["accentBar", ""], ["cardIcon", ""], ["dragHandle", ""], ["headerTitle", ""], ["contentActions", ""], ["moreMenuBtn", ""], ["nameInput", ""], ["suggestionsPopover", ""], ["icon", ""], ["suggestionButton", ""], ["nameLabel", ""], ["data-test-id", "chamber-card-div-wrapper", 3, "click", "dblclick", "contextmenu"], [1, "grow", 3, "pt", "dt", "value"], ["libCancelClick", "", 3, "pt"], [4, "ngTemplateOutlet"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-2", "py-1"], [1, "relative", 3, "pt"], [1, "flex", "gap-3"], [1, "flex", "grow", "flex-col", "gap-1", "py-1", "text-xs"], [1, "flex", "justify-between", "gap-1"], [1, "text-color", "ps-4"], [1, "flex", "items-center", "gap-1", "text-(--p-accordion-content-muted-color)"], [1, "min-w-5", "text-left", "whitespace-nowrap"], [1, "min-w-9.5", "text-right", "whitespace-nowrap"], ["data-propagate-click", "", 3, "icon"], [1, "absolute", "top-0", "left-0", "h-full", "w-1"], [1, "size-(--p-app-icon-size-sm)", 3, "icon"], ["cdkDragHandle", "", "icon", "drag-handle"], ["class", "h-11 rounded-sm bg-(--p-app-dark-surface-base)", 4, "cdkDragPlaceholder"], [1, "h-11", "rounded-sm", "bg-(--p-app-dark-surface-base)"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], [1, "min-w-0", "flex-1"], ["type", "button", "data-test-id", "chamber-card-button-name-trigger", "data-propagate-click", "", 3, "class"], [1, "flex", "min-w-0", "items-center", "gap-1"], ["pInputText", "", "data-propagate-click", "", 1, "border-primary-400", "w-full", "min-w-0", "bg-transparent", "py-0.5", "text-sm", "text-inherit", 3, "click", "keydown.space", "keydown.enter", "keyup.enter", "keydown.escape", "keyup.escape", "blur", "input", "id", "formControl"], ["type", "button", "data-propagate-click", "", "data-test-id", "chamber-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "pTooltip", "ariaLabel", "pt"], ["data-propagate-click", "", 3, "appendTo", "dismissable"], ["data-propagate-click", "", "data-test-id", "chamber-card-ul-name-suggestions", 1, "max-h-48", "w-56", "overflow-auto", "text-sm"], ["type", "button", "data-propagate-click", "", "data-test-id", "chamber-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "mousedown", "click", "pTooltip", "ariaLabel", "pt"], ["icon", "times", 1, "size-3"], ["type", "button", "data-propagate-click", "", "data-test-id", "chamber-card-button-name-suggestion", 1, "hover:bg-surface-800", "block", "w-full", "overflow-hidden", "rounded", "px-2", "py-1", "text-left", "text-ellipsis", "whitespace-nowrap", "text-inherit", 3, "mousedown", "click", "pTooltip", "tooltipPosition"], ["type", "button", "data-test-id", "chamber-card-button-name-trigger", "data-propagate-click", "", 3, "click"], [1, "line-clamp-2", "wrap-anywhere", 3, "pTooltip"], [1, "-mt-2", "flex", "flex-col", "items-end"], ["data-test-id", "chamber-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "ariaLabel", "pt", "disabled"], ["data-test-id", "chamber-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "ariaLabel", "pt", "disabled"], ["tooltipPosition", "left", 1, "size-(--p-app-icon-size-xs)", 3, "icon", "pTooltip"], ["data-test-id", "chamber-card-p-button-more-actions", "data-propagate-click", "", "tooltipPosition", "left", "severity", "secondary", "outlined", "", "size", "small", 3, "dt", "libChamberMenuTrigger", "libMenuActions", "pTooltip"], ["icon", "ellipsis-v", 1, "size-(--p-app-icon-size-xxxs)", "text-(length:--p-app-icon-size-xxxs)"]], template: function ChamberCardComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function ChamberCardComponent_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.clicked.emit($event)); })("dblclick", function ChamberCardComponent_Template_div_dblclick_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.handleCardDoubleClick($event)); })("contextmenu", function ChamberCardComponent_Template_div_contextmenu_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.contextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](1, "p-accordion-panel", 14, 0)(3, "p-accordion-header", 15); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](4, ChamberCardComponent_ng_container_4_Template, 1, 0, "ng-container", 16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](5, ChamberCardComponent_Conditional_5_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](6, ChamberCardComponent_ng_template_6_Template, 1, 3, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](8, "div", 17)(9, "div", 18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](10, ChamberCardComponent_ng_container_10_Template, 1, 0, "ng-container", 16)(11, ChamberCardComponent_ng_container_11_Template, 1, 0, "ng-container", 16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](13, ChamberCardComponent_Conditional_13_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](14, "p-accordion-content", 19); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](15, ChamberCardComponent_ng_container_15_Template, 1, 0, "ng-container", 16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](16, "div", 20)(17, "div", 21)(18, "div", 22)(19, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](20); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](21, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](22, "div", 24)(23, "span", 25); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](25, "span", 26); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](26); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](27, ChamberCardComponent_ng_container_27_Template, 1, 0, "ng-container", 16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](28, ChamberCardComponent_ng_template_28_Template, 1, 2, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(30, ChamberCardComponent_ng_template_30_Template, 2, 5, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(32, ChamberCardComponent_ng_template_32_Template, 3, 5, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(34, ChamberCardComponent_ng_template_34_Template, 3, 1, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(36, ChamberCardComponent_ng_template_36_Template, 3, 0, "ng-template", null, 6, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"])(38, ChamberCardComponent_ng_template_38_Template, 4, 11, "ng-template", null, 7, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { const accentBar_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](29); const cardIcon_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](31); const headerTitle_r16 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](35); const contentActions_r17 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](37); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassMap"](ctx.cn("group flex w-full overflow-hidden", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", ctx.chamber().id); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r14); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx.cdkDrag() ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r15); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", headerTitle_r16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); const moreMenuTrigger_r18 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"](ctx.menuTrigger()); const moreActions_r19 = ctx.actions(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](!ctx.isEditing() && moreMenuTrigger_r18 && moreActions_r19.length ? 13 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pt", ctx.mergedPt().content); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r14); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](21, 22, "chamberCard.angulations"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate2"](" ", ctx.angleLabel().raoLao.direction, " ", ctx.angleLabel().raoLao.formattedValue, " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate2"](" ", ctx.angleLabel().caudCran.direction, " ", ctx.angleLabel().caudCran.formattedValue, " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", contentActions_r17); } }, dependencies: [_chamber_menu_directives_chamber_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_18__.ChamberMenuTriggerDirective, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionContent, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionPanel, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.CancelClickDirective, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragHandle, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragPlaceholder, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_14__.IconComponent, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.FormControlDirective, primeng_tooltip__WEBPACK_IMPORTED_MODULE_12__.Tooltip, primeng_popover__WEBPACK_IMPORTED_MODULE_11__.Popover, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputText, primeng_button__WEBPACK_IMPORTED_MODULE_9__.Button, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 44189 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-menu/chamber-menu-item.service.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberMenuItemService: () => (/* binding */ ChamberMenuItemService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); const DESTRUCTIVE_CLASSES = 'text-(--p-app-status-danger)'; const trashIcon = 'trash'; class ChamberMenuItemService { translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateService); chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.ChamberFacade); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore); confirmationService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_2__.ConfirmationService); selectedChamberIds = this.chamberFacade.selectedIds; menuItemsForChamber(chamber) { const renameLabels = { cancelLabel: this.translate.instant('common.cancel'), header: this.translate.instant('chamberMenu.renameHeader'), inputLabel: this.translate.instant('common.name'), saveLabel: this.translate.instant('common.save') }; const menuItems = [{ command: () => this.goToChamber(chamber), disabled: false, icon: 'target', includeInCard: true, label: this.translate.instant('chamberMenu.goToChamber', { name: chamber.name }) }, { // Preset names for a mouse-only rename with no dialog/typing, plus a trailing // "Custom…" entry that opens the popup dialog - consistent with how every other // submenu here works (the top-level row only opens the submenu, never its own action). icon: 'typography', items: [..._tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.CHAMBER_STRUCTURE_NAMES.map(name => ({ command: () => this.updateChamberName(chamber.id, name), label: name })), { separator: true }, { command: () => this.chamberFacade.openRenameDialog(chamber, renameLabels), label: this.translate.instant('chamberMenu.renameCustom') }], label: this.translate.instant('common.rename') }, { chamber, customType: 'color-swatch', icon: 'palette' }, { items: [{ chamber, customType: 'color-swatch-full' }], label: this.translate.instant('chamberMenu.otherColor') }]; const selectedIdCount = this.selectedChamberIds().length; if (selectedIdCount > 1) { menuItems.push({ command: event => this.confirmDeleteSelectedChambers(event.originalEvent?.target ?? undefined), icon: trashIcon, iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('chamberMenu.deleteSelectedChambers', { count: selectedIdCount }), linkClass: DESTRUCTIVE_CLASSES }); } else { menuItems.push({ command: event => this.confirmDeleteSingleChamber(chamber.id, event.originalEvent?.target ?? undefined), icon: trashIcon, iconClass: DESTRUCTIVE_CLASSES, label: this.translate.instant('chamberMenu.deleteChamber'), linkClass: DESTRUCTIVE_CLASSES }); } return menuItems; } goToChamber(chamber) { this.viewportStore.updateAngulations(chamber.cameraOrientation); this.viewportStore.rotateAX(chamber.ax); this.viewportStore.updatePosterior(chamber.isPosterior); // Crosshair rotation is derived from the matrix/ax/isPosterior above, so it must be // restored after they're set, not before. rotateCrosshair takes a relative delta (it // decreases the absolute rotation by whatever value is passed), not an absolute target, // so the exact delta needed to land on the stored value is computed here - otherwise the // result would depend on wherever the crosshair happened to be before this ran, and // repeated "go to chamber" presses would keep rotating it further each time. // // crosshairRotation/isocenter/intersection are undefined on chambers captured before // these fields existed - there's no real value to restore, so the current view is left // alone instead of snapping to a fabricated position. if (chamber.crosshairRotation !== undefined) { const activeAxis = this.viewportStore.viewportAxisMapping()[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportAxisState.MIDDLEMAIN]; const currentCrosshairRotation = this.viewportStore.viewportCrosshairRotations[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportAxisState.MIDDLEMAIN](); this.viewportStore.rotateCrosshair(activeAxis, currentCrosshairRotation - chamber.crosshairRotation); } // Isocenter/intersection (pan + slice position) - deliberately excludes zoom, so two // chambers can share the same angle but land on different slices. if (chamber.isocenter !== undefined) { this.viewportStore.updateIsoCenter(chamber.isocenter); } if (chamber.intersection !== undefined) { this.viewportStore.updateIntersection(chamber.intersection); } this.viewportStore.nudgeAngulationsToForceResettle(); } confirmDeleteSingleChamber(chamberId, target) { this.confirmDeletion([chamberId], 'single', target); } confirmDeleteSelectedChambers(target) { const selectedIds = this.selectedChamberIds(); if (selectedIds.length === 0) return; this.confirmDeletion(selectedIds, selectedIds.length > 1 ? 'selected' : 'single', target); } updateChamberName(chamberId, newName) { const chamber = this.chamberFacade.chamberMap()[chamberId]; if (chamber) { this.chamberFacade.updateChamber({ ...chamber, name: newName }); } } confirmDeletion(ids, mode, target) { const translationKeyByMode = { all: 'chamberMenu.confirmDeleteAll', selected: 'chamberMenu.confirmDeleteSelected', single: 'chamberMenu.confirmDeleteChamber' }; const translationKey = translationKeyByMode[mode]; this.confirmationService.confirm({ accept: () => this.chamberFacade.deleteChambers(ids), acceptButtonProps: { label: this.translate.instant(`${translationKey}.cta.accept`), severity: 'danger' }, acceptLabel: this.translate.instant(`${translationKey}.cta.accept`), header: this.translate.instant(`${translationKey}.title`), icon: 'exclamation-triangle', message: this.translate.instant(`${translationKey}.message`, { count: ids.length }), rejectButtonProps: { label: this.translate.instant('common.cancel'), outlined: true, severity: 'secondary' }, target: target ?? undefined }); } } /***/ }, /***/ 11612 /*!*********************************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-menu/components/chamber-menu-item.component.ts ***! \*********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberMenuItemComponent: () => (/* binding */ ChamberMenuItemComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var primeng_ripple__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/ripple */ 73271); /* harmony import */ var primeng_slider__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/slider */ 31486); /* harmony import */ var primeng_toggleswitch__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/toggleswitch */ 79945); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../../colors/colors.service */ 39298); /* harmony import */ var _color_chamber_swatch_menu_item_color_chamber_swatch_menu_item_component__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./color-chamber-swatch-menu-item/color-chamber-swatch-menu-item.component */ 66969); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @angular/core */ 14975); function ChamberMenuItemComponent_Case_0_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "div", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("click", function ChamberMenuItemComponent_Case_0_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](1, "lib-chamber-color-swatch-menu-item", 3); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("chamber", ctx_r1.item().chamber)("colors", ctx_r1.fullColors); } } function ChamberMenuItemComponent_Case_1_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("click", function ChamberMenuItemComponent_Case_1_Template_span_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](1, "lib-icon", 5)(2, "lib-chamber-color-swatch-menu-item", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("icon", ctx_r1.item().icon ?? "palette")("iconStyle", ctx_r1.item().iconStyle); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("chamber", ctx_r1.item().chamber)("colors", ctx_r1.colors); } } function ChamberMenuItemComponent_Case_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](0, "lib-menu-item", 1); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("item", ctx_r1.item()); } } class ChamberMenuItemComponent { item = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "item" }] : [])); colors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_8__.ColorsService).pickerColors; fullColors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_8__.ColorsService).fullPickerColors; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_7__.cn; static ɵfac = function ChamberMenuItemComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberMenuItemComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdefineComponent"]({ type: ChamberMenuItemComponent, selectors: [["lib-chamber-menu-item"]], inputs: { item: [1, "item"] }, decls: 3, vars: 1, consts: [[1, "p-menu-item-link"], [3, "item"], [3, "click"], ["width", "narrow", 3, "chamber", "colors"], [1, "p-menu-item-link", 3, "click"], ["iconClass", "p-menu-item-icon", 1, "size-3.5", 3, "icon", "iconStyle"], [3, "chamber", "colors"]], template: function ChamberMenuItemComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditionalCreate"](0, ChamberMenuItemComponent_Case_0_Template, 2, 2, "div")(1, ChamberMenuItemComponent_Case_1_Template, 3, 4, "span", 0)(2, ChamberMenuItemComponent_Case_2_Template, 1, 1, "lib-menu-item", 1); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditional"]((tmp_0_0 = ctx.item().customType) === "color-swatch-full" ? 0 : tmp_0_0 === "color-swatch" ? 1 : 2); } }, dependencies: [primeng_ripple__WEBPACK_IMPORTED_MODULE_3__.RippleModule, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_6__.IconComponent, _color_chamber_swatch_menu_item_color_chamber_swatch_menu_item_component__WEBPACK_IMPORTED_MODULE_9__.ColorChamberSwatchMenuItemComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_6__.MenuItemComponent, primeng_toggleswitch__WEBPACK_IMPORTED_MODULE_5__.ToggleSwitchModule, primeng_slider__WEBPACK_IMPORTED_MODULE_4__.SliderModule, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.FormsModule], encapsulation: 2 }); } /***/ }, /***/ 23204 /*!****************************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-menu/components/chamber-menu.component.ts ***! \****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberMenuComponent: () => (/* binding */ ChamberMenuComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var _annotation_menu_menu_tracker_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../annotation-menu/menu-tracker.service */ 61487); /* harmony import */ var _services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../services/submenu-flip/submenu-flip.service */ 9610); /* harmony import */ var _chamber_menu_item_component__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./chamber-menu-item.component */ 11612); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["menu"]; function ChamberMenuComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](0, "lib-chamber-menu-item", 3); } if (rf & 2) { const item_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("item", item_r2); } } class ChamberMenuComponent { model = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.model)([], ...(ngDevMode ? [{ debugName: "model" }] : [])); appendTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('body', ...(ngDevMode ? [{ debugName: "appendTo" }] : [])); menu = _angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild.required('menu'); tracker = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_annotation_menu_menu_tracker_service__WEBPACK_IMPORTED_MODULE_3__.MenuTrackerService); submenuFlipService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_4__.SubmenuFlipService); menuPt = { root: { // Prevents being able to right-click an open menu and open the native menu oncontextmenu(event) { event.preventDefault(); } }, submenu: 'min-w-0' }; show(event) { const menu = this.menu(); menu.show(event); this.tracker.trackOpenMenu(menu); this.submenuFlipService.start(); } toggle(event) { const menu = this.menu(); const wasVisible = menu.visible(); menu.toggle(event); if (wasVisible) { this.submenuFlipService.stop(); } else { this.submenuFlipService.start(); } } onMenuHide() { this.submenuFlipService.stop(); } hide() { this.menu().hide(); } ngOnDestroy() { this.submenuFlipService.stop(); } static ɵfac = function ChamberMenuComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberMenuComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: ChamberMenuComponent, selectors: [["lib-chamber-menu"]], viewQuery: function ChamberMenuComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵviewQuerySignal"](ctx.menu, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵqueryAdvance"](); } }, inputs: { model: [1, "model"], appendTo: [1, "appendTo"] }, outputs: { model: "modelChange" }, features: [_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵProvidersFeature"]([{ provide: primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenu, useExisting: ChamberMenuComponent }, _services_submenu_flip_submenu_flip_service__WEBPACK_IMPORTED_MODULE_4__.SubmenuFlipService])], decls: 4, vars: 3, consts: [["menu", ""], ["item", ""], ["popup", "", 3, "onHide", "pt", "model", "appendTo"], [3, "item"]], template: function ChamberMenuComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "p-contextmenu", 2, 0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("onHide", function ChamberMenuComponent_Template_p_contextmenu_onHide_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.onMenuHide()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplate"](2, ChamberMenuComponent_ng_template_2_Template, 1, 1, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pt", ctx.menuPt)("model", ctx.model())("appendTo", ctx.appendTo()); } }, dependencies: [primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_2__.ContextMenu, _chamber_menu_item_component__WEBPACK_IMPORTED_MODULE_5__.ChamberMenuItemComponent], encapsulation: 2 }); } /***/ }, /***/ 66969 /*!*****************************************************************************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-menu/components/color-chamber-swatch-menu-item/color-chamber-swatch-menu-item.component.ts ***! \*****************************************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ColorChamberSwatchMenuItemComponent: () => (/* binding */ ColorChamberSwatchMenuItemComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ color: a0 }); function ColorChamberSwatchMenuItemComponent_For_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdomElementStart"](0, "button", 1); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdomListener"]("click", function ColorChamberSwatchMenuItemComponent_For_2_Template_button_click_0_listener() { const color_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.changeColor(color_r2)); }); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdomElementEnd"](); } if (rf & 2) { const color_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵclassMap"]("block h-7 w-7 cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--p-primary-color)"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵstyleProp"]("background-color", color_r2); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵattribute"]("data-test-id", "color-chamber-swatch-menu-item-button-" + color_r2)("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipeBind2"](1, 6, "chamberMenu.selectColor", _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpureFunction1"](9, _c0, color_r2))); } } class ColorChamberSwatchMenuItemComponent { chamber = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(...(ngDevMode ? [undefined, { debugName: "chamber" }] : [])); width = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('wide', ...(ngDevMode ? [{ debugName: "width" }] : [])); wide = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.width() === 'wide', ...(ngDevMode ? [{ debugName: "wide" }] : [])); chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.ChamberFacade); colors = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "colors" }] : [])); changeColor(color) { const chamber = this.chamber(); if (chamber) { this.chamberFacade.updateChamber({ ...chamber, color }); } } static ɵfac = function ColorChamberSwatchMenuItemComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ColorChamberSwatchMenuItemComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdefineComponent"]({ type: ColorChamberSwatchMenuItemComponent, selectors: [["lib-chamber-color-swatch-menu-item"]], inputs: { chamber: [1, "chamber"], width: [1, "width"], colors: [1, "colors"] }, decls: 3, vars: 2, consts: [["type", "button", 3, "class", "background-color"], ["type", "button", 3, "click"]], template: function ColorChamberSwatchMenuItemComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdomElementStart"](0, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrepeaterCreate"](1, ColorChamberSwatchMenuItemComponent_For_2_Template, 2, 11, "button", 0, _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrepeaterTrackByIdentity"]); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdomElementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵclassMap"](`flex ${ctx.wide() ? "w-56" : "w-35"} flex-wrap overflow-clip rounded-md`); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrepeater"](ctx.colors()); } }, dependencies: [_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 65937 /*!************************************************************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber-menu/directives/chamber-menu-trigger.directive.ts ***! \************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberMenuTriggerDirective: () => (/* binding */ ChamberMenuTriggerDirective) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 14975); class ChamberMenuTriggerDirective { libChamberMenuTrigger = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "libChamberMenuTrigger" }] : [])); libMenuActions = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "libMenuActions" }] : [])); onClick(event) { const menu = this.libChamberMenuTrigger(); const actions = this.libMenuActions(); if (menu && actions.length > 0) { event.stopPropagation(); event.preventDefault(); menu.model.set(actions); menu.toggle(event); } } static ɵfac = function ChamberMenuTriggerDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberMenuTriggerDirective)(); }; static ɵdir = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineDirective"]({ type: ChamberMenuTriggerDirective, selectors: [["", "libChamberMenuTrigger", ""]], hostBindings: function ChamberMenuTriggerDirective_HostBindings(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵlistener"]("click", function ChamberMenuTriggerDirective_click_HostBindingHandler($event) { return ctx.onClick($event); }); } }, inputs: { libChamberMenuTrigger: [1, "libChamberMenuTrigger"], libMenuActions: [1, "libMenuActions"] } }); } /***/ }, /***/ 16592 /*!*********************************************************!*\ !*** ./libs/feature/src/lib/chamber/chamber.service.ts ***! \*********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberService: () => (/* binding */ ChamberService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! uuid */ 69083); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../colors/colors.service */ 39298); class ChamberService { chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.ChamberFacade); colorsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_5__.ColorsService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_2__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateService); createNewChamber({ angulation, ax, crosshairRotation, intersection, isocenter, isPosterior }) { const defaultNameTemplate = this.translate.instant('chamberMenu.defaultName', { index: '__INDEX__' }); const escapedDefaultNameTemplate = defaultNameTemplate.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`); const indexPattern = String.raw`(\d+)`; const defaultNamePattern = new RegExp(`^${escapedDefaultNameTemplate.replace('__INDEX__', indexPattern)}$`); let maxIndex = 0; for (const { name } of this.chamberFacade.chambers()) { const match = defaultNamePattern.exec(name) ?? /^Chamber (\d+)$/.exec(name); if (match) { maxIndex = Math.max(maxIndex, Number(match[1])); } } const nextIndex = maxIndex + 1; const chamber = { ax, cameraOrientation: angulation, color: this.colorsService.currentColor(), crosshairRotation, hidden: false, id: (0,uuid__WEBPACK_IMPORTED_MODULE_3__["default"])(), intersection, isocenter, isPosterior: isPosterior, name: this.translate.instant('chamberMenu.defaultName', { index: nextIndex }) }; this.chamberFacade.addChamber(chamber); const createdChamber = this.chamberFacade.chambers().find(c => c.id === chamber.id); if (!createdChamber) { const errorMessage = this.translate.instant('chamberToastMessage.error', { name: chamber.name }); this.showToastMessage('error', errorMessage); return; } const successMessage = this.translate.instant('chamberToastMessage.success', { name: chamber.name }); this.showToastMessage('success', successMessage); this.colorsService.nextColor(); } showToastMessage(severity, summary) { this.messageService.add({ life: 3000, severity, summary }); } static ɵfac = function ChamberService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: ChamberService, factory: ChamberService.ɵfac }); } /***/ }, /***/ 98063 /*!******************************************************!*\ !*** ./libs/feature/src/lib/colors/colors.config.ts ***! \******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ COLORS_TOKEN: () => (/* binding */ COLORS_TOKEN), /* harmony export */ FULL_PICKER_COLORS_TOKEN: () => (/* binding */ FULL_PICKER_COLORS_TOKEN), /* harmony export */ PICKER_COLORS_TOKEN: () => (/* binding */ PICKER_COLORS_TOKEN), /* harmony export */ provideDefaultColors: () => (/* binding */ provideDefaultColors) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/ui */ 79048); // Color palettes can be overridden by providing different colors for these tokens. // The default values live in the Figma mirror (libs/ui/src/lib/theme/app-tokens.ts) // as the app.palette.* groups. const COLORS_TOKEN = new _angular_core__WEBPACK_IMPORTED_MODULE_0__.InjectionToken('Colors'); const PICKER_COLORS_TOKEN = new _angular_core__WEBPACK_IMPORTED_MODULE_0__.InjectionToken('PickerColors'); const FULL_PICKER_COLORS_TOKEN = new _angular_core__WEBPACK_IMPORTED_MODULE_0__.InjectionToken('FullPickerColors'); function provideDefaultColors() { return [ // The order that colors are chosen when creating annotations { provide: COLORS_TOKEN, useValue: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__.annotationPaletteHexColors }, // The order to display them in the color picker { provide: PICKER_COLORS_TOKEN, useValue: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__.pickerPaletteHexColors }, // The full-size color picker's colors { provide: FULL_PICKER_COLORS_TOKEN, useValue: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__.fullPickerPaletteHexColors }]; } /***/ }, /***/ 39298 /*!*******************************************************!*\ !*** ./libs/feature/src/lib/colors/colors.service.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ColorsService: () => (/* binding */ ColorsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _colors_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./colors.config */ 98063); class ColorsService { colors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_config__WEBPACK_IMPORTED_MODULE_1__.COLORS_TOKEN); pickerColors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_config__WEBPACK_IMPORTED_MODULE_1__.PICKER_COLORS_TOKEN); fullPickerColors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_config__WEBPACK_IMPORTED_MODULE_1__.FULL_PICKER_COLORS_TOKEN); colorIndex = 0; constructor() { if (this.colors.length === 0) { throw new Error('COLORS_TOKEN must provide at least one color'); } } currentColor() { return this.colors[this.colorIndex]; } nextColor() { this.colorIndex++; if (this.colorIndex >= this.colors.length) { this.colorIndex = 0; } } static ɵfac = function ColorsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ColorsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: ColorsService, factory: ColorsService.ɵfac }); } /***/ }, /***/ 7110 /*!*****************************************************************************************!*\ !*** ./libs/feature/src/lib/create-object3d-dialog/create-object3d-dialog.component.ts ***! \*****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CreateObject3DDialogComponent: () => (/* binding */ CreateObject3DDialogComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_checkbox__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/checkbox */ 10026); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_inputnumber__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/inputnumber */ 89567); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @angular/core */ 14975); function CreateObject3DDialogComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](3, "p-inputNumber", 8); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_1_Template_p_inputNumber_ngModelChange_3_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.diameter, $event) || (ctx_r1.diameter = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](4, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](7, "p-inputNumber", 9); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_1_Template_p_inputNumber_ngModelChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.height, $event) || (ctx_r1.height = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](2, 6, "createObject3d.diameter"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.diameter); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("min", 0.1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](6, 8, "createObject3d.height"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.height); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("min", 0.1); } } function CreateObject3DDialogComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](3, "p-inputNumber", 10); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_2_Template_p_inputNumber_ngModelChange_3_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.innerDiameter, $event) || (ctx_r1.innerDiameter = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](4, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](7, "p-inputNumber", 11); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_2_Template_p_inputNumber_ngModelChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.outerDiameter, $event) || (ctx_r1.outerDiameter = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](8, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](9); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](10, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](11, "p-inputNumber", 12); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_2_Template_p_inputNumber_ngModelChange_11_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.height, $event) || (ctx_r1.height = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](2, 9, "createObject3d.innerDiameter"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.innerDiameter); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("min", 0.1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](6, 11, "createObject3d.outerDiameter"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.outerDiameter); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("min", 0.1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](10, 13, "createObject3d.height"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.height); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("min", 0.1); } } function CreateObject3DDialogComponent_Conditional_3_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](0, "lib-icon", 15); } } function CreateObject3DDialogComponent_Conditional_3_ng_template_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](0, "lib-icon", 16); } } function CreateObject3DDialogComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 2)(1, "p-button", 13); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function CreateObject3DDialogComponent_Conditional_3_Template_p_button_click_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.importStl("device")); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](3, CreateObject3DDialogComponent_Conditional_3_ng_template_3_Template, 1, 0, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](5, "p-button", 14); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function CreateObject3DDialogComponent_Conditional_3_Template_p_button_click_5_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.importStl("segmentation")); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](7, CreateObject3DDialogComponent_Conditional_3_ng_template_7_Template, 1, 0, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](2, 6, "createObject3d.device"))("loading", ctx_r1.loadingMode() === "device")("disabled", ctx_r1.loadingMode() !== undefined); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](6, 8, "createObject3d.segmentation"))("loading", ctx_r1.loadingMode() === "segmentation")("disabled", ctx_r1.loadingMode() !== undefined); } } function CreateObject3DDialogComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "label", 3)(1, "p-checkbox", 17); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function CreateObject3DDialogComponent_Conditional_4_Template_p_checkbox_ngModelChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r5); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r1.disableTranslationRotation, $event) || (ctx_r1.disableTranslationRotation = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.disableTranslationRotation); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("binary", true); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](3, 3, "createObject3d.disableTranslationRotation"), " "); } } function CreateObject3DDialogComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p-button", 18); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function CreateObject3DDialogComponent_Conditional_8_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r6); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.confirm()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](1, 1, "createObject3d.create")); } } class CreateObject3DDialogComponent { dialogReference = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_8__.DynamicDialogRef); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_5__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslateService); object3DType = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "object3DType" }] : [])); diameter = 40; height = 30; innerDiameter = 40; outerDiameter = 44; /** * When enabled, the created object starts locked (interactive translation and * rotation disabled). */ disableTranslationRotation = false; /** STL import mode currently being parsed, or undefined when idle. */ loadingMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "loadingMode" }] : [])); cancel() { this.dialogReference.close(); } confirm() { this.dialogReference.close(this.buildConfig()); } buildConfig(options = {}) { const { stlData, stlImportMode } = options; return { diameter: this.diameter, height: this.height, innerDiameter: this.innerDiameter, locked: this.disableTranslationRotation, object3DType: this.object3DType(), outerDiameter: this.outerDiameter, stlData, stlImportMode }; } importStl(mode) { var _this = this; const input = document.createElement('input'); input.type = 'file'; input.accept = '.stl'; input.addEventListener('change', /*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const file = input.files?.[0]; if (!file) return; _this.loadingMode.set(mode); try { const { centroid, normals, vertices } = yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.parseSTL)(file); _this.dialogReference.close(_this.buildConfig({ stlData: { centroid, fileName: file.name, normals, vertices }, stlImportMode: mode })); } catch (error) { _this.loadingMode.set(undefined); _this.messageService.add({ detail: error.message, severity: 'error', sticky: true, summary: _this.translate.instant('createObject3d.stlParseError') }); } })); input.click(); } static ɵfac = function CreateObject3DDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CreateObject3DDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵdefineComponent"]({ type: CreateObject3DDialogComponent, selectors: [["lib-create-object3d-dialog"]], inputs: { object3DType: [1, "object3DType"] }, decls: 9, vars: 7, consts: [["icon", ""], [1, "flex", "flex-col", "gap-4", "px-4"], [1, "flex", "gap-4"], [1, "flex", "items-center", "gap-2"], [1, "flex", "justify-end", "gap-2"], ["severity", "secondary", "variant", "text", "data-test-id", "create-object3d-dialog-p-button-cancel", 3, "click", "label"], ["data-test-id", "create-object3d-dialog-p-button-confirm", 3, "label"], [1, "flex", "flex-col", "gap-1"], ["suffix", " mm", "data-test-id", "create-object3d-dialog-p-inputNumber-diameter", 3, "ngModelChange", "ngModel", "min"], ["suffix", " mm", "data-test-id", "create-object3d-dialog-p-inputNumber-height", 3, "ngModelChange", "ngModel", "min"], ["suffix", " mm", "data-test-id", "create-object3d-dialog-p-inputNumber-inner-diameter", 3, "ngModelChange", "ngModel", "min"], ["suffix", " mm", "data-test-id", "create-object3d-dialog-p-inputNumber-outer-diameter", 3, "ngModelChange", "ngModel", "min"], ["suffix", " mm", "data-test-id", "create-object3d-dialog-p-inputNumber-hollow-height", 3, "ngModelChange", "ngModel", "min"], ["fluid", "", "data-test-id", "create-object3d-dialog-p-button-device", 1, "flex-1", 3, "click", "label", "loading", "disabled"], ["fluid", "", "data-test-id", "create-object3d-dialog-p-button-segmentation", 1, "flex-1", 3, "click", "label", "loading", "disabled"], ["icon", "device", 1, "size-(--p-app-icon-size-md)"], ["icon", "segmentation", 1, "size-(--p-app-icon-size-md)"], ["data-test-id", "create-object3d-dialog-p-checkbox-disable-translation-rotation", 3, "ngModelChange", "ngModel", "binary"], ["data-test-id", "create-object3d-dialog-p-button-confirm", 3, "click", "label"]], template: function CreateObject3DDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](1, CreateObject3DDialogComponent_Conditional_1_Template, 8, 10); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](2, CreateObject3DDialogComponent_Conditional_2_Template, 12, 15); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](3, CreateObject3DDialogComponent_Conditional_3_Template, 9, 10, "div", 2)(4, CreateObject3DDialogComponent_Conditional_4_Template, 4, 5, "label", 3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](5, "div", 4)(6, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function CreateObject3DDialogComponent_Template_p_button_click_6_listener() { return ctx.cancel(); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](8, CreateObject3DDialogComponent_Conditional_8_Template, 2, 3, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.object3DType() === "cylinder" ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.object3DType() === "hollow_cylinder" ? 2 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.object3DType() === "stl_file" ? 3 : 4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](7, 5, "common.cancel")); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.object3DType() !== "stl_file" ? 8 : -1); } }, dependencies: [_angular_forms__WEBPACK_IMPORTED_MODULE_3__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgModel, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslateModule, primeng_button__WEBPACK_IMPORTED_MODULE_6__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_6__.Button, primeng_checkbox__WEBPACK_IMPORTED_MODULE_7__.CheckboxModule, primeng_checkbox__WEBPACK_IMPORTED_MODULE_7__.Checkbox, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__.IconComponent, primeng_inputnumber__WEBPACK_IMPORTED_MODULE_9__.InputNumberModule, primeng_inputnumber__WEBPACK_IMPORTED_MODULE_9__.InputNumber, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 24340 /*!***************************************************************************************!*\ !*** ./libs/feature/src/lib/create-s-curve-dialog/create-s-curve-dialog.component.ts ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CreateSCurveDialogComponent: () => (/* binding */ CreateSCurveDialogComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ index: 1 }); const _c1 = () => ({ index: 2 }); function CreateSCurveDialogComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "fieldset", 1)(1, "legend", 2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](4, "lib-viewport-setting-slider", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayListener"]("valueChange", function CreateSCurveDialogComponent_Conditional_9_Template_lib_viewport_setting_slider_valueChange_4_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayBindingSet"](ctx_r1.cc2, $event) || (ctx_r1.cc2 = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("resetClicked", function CreateSCurveDialogComponent_Conditional_9_Template_lib_viewport_setting_slider_resetClicked_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.cc2.set(0)); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](6, "lib-viewport-setting-slider", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayListener"]("valueChange", function CreateSCurveDialogComponent_Conditional_9_Template_lib_viewport_setting_slider_valueChange_6_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayBindingSet"](ctx_r1.rl2, $event) || (ctx_r1.rl2 = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("resetClicked", function CreateSCurveDialogComponent_Conditional_9_Template_lib_viewport_setting_slider_resetClicked_6_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.rl2.set(ctx_r1.defaultRl2)); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind2"](3, 11, "createSCurve.onCurveView", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction0"](18, _c1)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](5, 14, "createSCurve.cc"))("minValue", ctx_r1.angleMin)("maxValue", ctx_r1.angleMax)("showValue", true); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayProperty"]("value", ctx_r1.cc2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](7, 16, "createSCurve.rl"))("minValue", ctx_r1.angleMin)("maxValue", ctx_r1.angleMax)("showValue", true); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayProperty"]("value", ctx_r1.rl2); } } const ANGLE_MIN = -90; const ANGLE_MAX = 90; // A non-identical default second point, so the cross product used to derive // the two-point en-face angle is never a degenerate zero vector. const DEFAULT_RL2 = 45; class CreateSCurveDialogComponent { dialogReference = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DynamicDialogRef); pointCount = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "pointCount" }] : [])); // Pre-populates the sliders when reopening this dialog to edit an existing curve's views, // instead of the create flow's all-zero defaults. initialControlPoints = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(...(ngDevMode ? [undefined, { debugName: "initialControlPoints" }] : [])); angleMin = ANGLE_MIN; angleMax = ANGLE_MAX; defaultRl2 = DEFAULT_RL2; cc1 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "cc1" }] : [])); rl1 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "rl1" }] : [])); cc2 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "cc2" }] : [])); rl2 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(DEFAULT_RL2, ...(ngDevMode ? [{ debugName: "rl2" }] : [])); ngOnInit() { const [point1, point2] = this.initialControlPoints() ?? []; if (point1) { this.rl1.set(point1[0]); this.cc1.set(point1[1]); } if (point2) { this.rl2.set(point2[0]); this.cc2.set(point2[1]); } } cancel() { this.dialogReference.close(); } confirm() { const point1 = [this.rl1(), this.cc1()]; const point2 = [this.rl2(), this.cc2()]; const controlPoints = this.pointCount() === 1 ? [point1] : [point1, point2]; this.dialogReference.close(controlPoints); } static ɵfac = function CreateSCurveDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CreateSCurveDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: CreateSCurveDialogComponent, selectors: [["lib-create-s-curve-dialog"]], inputs: { pointCount: [1, "pointCount"], initialControlPoints: [1, "initialControlPoints"] }, decls: 15, vars: 26, consts: [[1, "flex", "flex-col", "gap-4", "px-4"], [1, "flex", "flex-col", "gap-2"], [1, "mb-1", "text-sm", "font-medium"], [3, "valueChange", "resetClicked", "label", "minValue", "maxValue", "showValue", "value"], [1, "flex", "justify-end", "gap-2"], ["severity", "secondary", "variant", "text", "data-test-id", "create-s-curve-dialog-p-button-cancel", 3, "click", "label"], ["data-test-id", "create-s-curve-dialog-p-button-confirm", 3, "click", "label"]], template: function CreateSCurveDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "div", 0)(1, "fieldset", 1)(2, "legend", 2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](5, "lib-viewport-setting-slider", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayListener"]("valueChange", function CreateSCurveDialogComponent_Template_lib_viewport_setting_slider_valueChange_5_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayBindingSet"](ctx.cc1, $event) || (ctx.cc1 = $event); return $event; }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("resetClicked", function CreateSCurveDialogComponent_Template_lib_viewport_setting_slider_resetClicked_5_listener() { return ctx.cc1.set(0); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](7, "lib-viewport-setting-slider", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayListener"]("valueChange", function CreateSCurveDialogComponent_Template_lib_viewport_setting_slider_valueChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayBindingSet"](ctx.rl1, $event) || (ctx.rl1 = $event); return $event; }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("resetClicked", function CreateSCurveDialogComponent_Template_lib_viewport_setting_slider_resetClicked_7_listener() { return ctx.rl1.set(0); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](9, CreateSCurveDialogComponent_Conditional_9_Template, 8, 19, "fieldset", 1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](10, "div", 4)(11, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function CreateSCurveDialogComponent_Template_p_button_click_11_listener() { return ctx.cancel(); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](13, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](14, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function CreateSCurveDialogComponent_Template_p_button_click_13_listener() { return ctx.confirm(); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind2"](4, 14, "createSCurve.onCurveView", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction0"](25, _c0)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](6, 17, "createSCurve.cc"))("minValue", ctx.angleMin)("maxValue", ctx.angleMax)("showValue", true); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayProperty"]("value", ctx.cc1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](8, 19, "createSCurve.rl"))("minValue", ctx.angleMin)("maxValue", ctx.angleMax)("showValue", true); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayProperty"]("value", ctx.rl1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx.pointCount() === 2 ? 9 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](12, 21, "common.cancel")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](14, 23, "common.create")); } }, dependencies: [_ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateModule, primeng_button__WEBPACK_IMPORTED_MODULE_3__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_3__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_5__.ViewportSettingSliderComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 20619 /*!******************************************************************************************!*\ !*** ./libs/feature/src/lib/device-sizing-chart/device-sizing-chart-dialog.component.ts ***! \******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DeviceSizingChartDialogComponent: () => (/* binding */ DeviceSizingChartDialogComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_iconfield__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/iconfield */ 60478); /* harmony import */ var primeng_inputicon__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/inputicon */ 73164); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_message__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/message */ 60134); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var primeng_tag__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/tag */ 37587); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _device_sizing_chart_calculations__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./device-sizing-chart.calculations */ 31997); /* harmony import */ var _device_sizing_chart_data__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./device-sizing-chart.data */ 25235); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = (a0, a1) => ({ matched: a0, total: a1 }); const _c1 = a0 => ({ color: a0 }); function DeviceSizingChartDialogComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "p-message", 6); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](2, 1, "deviceSizingChart.empty.noClosedSplines"), " "); } } function DeviceSizingChartDialogComponent_Conditional_2_ng_template_14_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](1, "lib-icon", 22); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](2, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const spline_r3 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("icon", ctx_r1.closedSplineIcon)("iconStyle", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](3, _c1, spline_r3.color)); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](spline_r3.name); } } function DeviceSizingChartDialogComponent_Conditional_2_ng_template_16_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](1, "lib-icon", 22); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](2, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const spline_r4 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("icon", ctx_r1.closedSplineIcon)("iconStyle", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](3, _c1, spline_r4.color)); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](spline_r4.name); } } function DeviceSizingChartDialogComponent_Conditional_2_Conditional_35_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 18)(1, "p-button", 24); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("onClick", function DeviceSizingChartDialogComponent_Conditional_2_Conditional_35_Template_p_button_onClick_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r5); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.filterText.set("")); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](2, 1, "deviceSizingChart.filter.clear")); } } function DeviceSizingChartDialogComponent_Conditional_2_ng_template_38_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "tr")(1, "th", 25); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](4, "p-sortIcon", 26); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](5, "th", 27); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](8, "p-sortIcon", 28); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](9, "th", 29); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](12, "p-sortIcon", 30); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](13, "th", 31); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](15, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](16, "th", 32); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](19, "p-sortIcon", 33); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](20, "th", 34); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](21); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](22, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](23, "p-sortIcon", 35); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](24, "th", 36); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](25); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](26, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](27, "p-sortIcon", 37); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](3, 7, "deviceSizingChart.table.columns.manufacturer"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](7, 9, "deviceSizingChart.table.columns.model"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](11, 11, "deviceSizingChart.table.columns.nominalSize"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](15, 13, "deviceSizingChart.table.columns.deployedSize"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](18, 15, "deviceSizingChart.table.columns.areaOversizing"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](22, 17, "deviceSizingChart.table.columns.perimeterOversizing"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](26, 19, "deviceSizingChart.table.columns.sizingCriteria"), " "); } } function DeviceSizingChartDialogComponent_Conditional_2_ng_template_40_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "tr")(1, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](3, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](5, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](7, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](9, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](11, "percent"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](12, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](13); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](14, "percent"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](15, "td")(16, "div", 38); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](17, "p-tag", 39); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](19, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](20, "div")(21, "span", 40); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](22); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](23, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()()()()(); } if (rf & 2) { const row_r6 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](row_r6.manufacturer); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](row_r6.model); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](row_r6.nominalSizeLabel); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](row_r6.deployedSizeLabel); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind2"](11, 12, row_r6.areaOversizing, "1.0-0")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind2"](14, 15, row_r6.perimeterOversizing, "1.0-0")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵclassMap"](row_r6.sizingMatch ? "border border-(--p-app-status-success)/40 px-3" : "border border-(--p-app-status-danger)/40 px-3"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("severity", row_r6.sizingMatch ? "success" : "danger")("value", row_r6.sizingMatch ? _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](18, 18, "deviceSizingChart.table.match") : _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](19, 20, "deviceSizingChart.table.noMatch")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate2"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](23, 22, row_r6.sizingParameterNameKey), ": ", row_r6.sizingParameterBounds, " "); } } function DeviceSizingChartDialogComponent_Conditional_2_ng_template_42_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "tr")(1, "td", 41)(2, "div", 42)(3, "div", 43); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](6, "p-button", 44); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("onClick", function DeviceSizingChartDialogComponent_Conditional_2_ng_template_42_Template_p_button_onClick_6_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.filterText.set("")); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](5, 3, "deviceSizingChart.empty.noDevices"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("outlined", true)("label", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](7, 5, "deviceSizingChart.filter.clearFilter")); } } function DeviceSizingChartDialogComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 7)(1, "label", 8)(2, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](5, "p-iconfield"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](6, "p-inputicon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](7, "input", 11); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("ngModelChange", function DeviceSizingChartDialogComponent_Conditional_2_Template_input_ngModelChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.filterText.set($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](9, "label", 8)(10, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](11); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](13, "p-select", 12); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("ngModelChange", function DeviceSizingChartDialogComponent_Conditional_2_Template_p_select_ngModelChange_13_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.selectedSpline.set($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](14, DeviceSizingChartDialogComponent_Conditional_2_ng_template_14_Template, 4, 5, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(16, DeviceSizingChartDialogComponent_Conditional_2_ng_template_16_Template, 4, 5, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](18, "div", 13)(19, "div", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](20); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](21, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](22, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](23); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](24, "div", 15); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](25, "\u00B7"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](26, "div", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](27); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](28, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](29, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](30); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](31, "div", 16)(32, "div", 17); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](33); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](34, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](35, DeviceSizingChartDialogComponent_Conditional_2_Conditional_35_Template, 3, 3, "div", 18); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](36, "div", 19)(37, "p-table", 20); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](38, DeviceSizingChartDialogComponent_Conditional_2_ng_template_38_Template, 28, 21, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(40, DeviceSizingChartDialogComponent_Conditional_2_ng_template_40_Template, 24, 24, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(42, DeviceSizingChartDialogComponent_Conditional_2_ng_template_42_Template, 8, 7, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](4, 15, "deviceSizingChart.filter.label"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngModel", ctx_r1.filterText())("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](8, 17, "deviceSizingChart.filter.placeholder")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](12, 19, "deviceSizingChart.spline.label"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngModel", ctx_r1.selectedSpline())("options", ctx_r1.closedSplines()); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](21, 21, "deviceSizingChart.measurements.area"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](ctx_r1.areaLabel()); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](28, 23, "deviceSizingChart.measurements.perimeter"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](ctx_r1.perimeterLabel()); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind2"](34, 25, "deviceSizingChart.matchCount", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction2"](28, _c0, ctx_r1.matchingDeviceCount(), ctx_r1.totalDeviceCount())), " "); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx_r1.filterText().trim() !== "" ? 35 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("value", ctx_r1.rows())("scrollable", true)("sortOrder", -1); } } class DeviceSizingChartDialogComponent { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_16__.AnnotationFacade); closedSplineIcon = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_17__.UiSvgIcon.CLOSEDSPLINE; initialSplineId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(...(ngDevMode ? [undefined, { debugName: "initialSplineId" }] : [])); filterText = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)('', ...(ngDevMode ? [{ debugName: "filterText" }] : [])); closedSplines = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.annotationFacade.annotations().filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_14__.annotationIsClosedSpline)(annotation)), ...(ngDevMode ? [{ debugName: "closedSplines" }] : [])); selectedSpline = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.linkedSignal)(() => { const splines = this.closedSplines(); return splines.find(({ id }) => id === this.initialSplineId()) ?? splines[0]; }, ...(ngDevMode ? [{ debugName: "selectedSpline" }] : [])); selectedMeasurements = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const spline = this.selectedSpline(); if (!spline) return; return { area: (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_15__.getClosedSplineArea)(spline), perimeter: (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_15__.getSplineLength)(spline) }; }, ...(ngDevMode ? [{ debugName: "selectedMeasurements" }] : [])); rows = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const measurements = this.selectedMeasurements(); if (!measurements) return []; const terms = this.filterText().trim().toLowerCase().split(/\s+/).filter(Boolean); return _device_sizing_chart_data__WEBPACK_IMPORTED_MODULE_19__.TAVR_DEVICES.filter(device => this.deviceMatchesFilter(device, terms)).map(device => ({ areaOversizing: (0,_device_sizing_chart_calculations__WEBPACK_IMPORTED_MODULE_18__.oversizingArea)(device.deployedSize.value, measurements.area), deployedSizeLabel: this.sizeLabel(device.deployedSize.value, device.deployedSize.units), device, manufacturer: device.manufacturer, model: device.model, nominalSize: device.nominalSize.value, nominalSizeLabel: this.sizeLabel(device.nominalSize.value, device.nominalSize.units), perimeterOversizing: (0,_device_sizing_chart_calculations__WEBPACK_IMPORTED_MODULE_18__.oversizingPerimeter)(device.deployedSize.value, measurements.perimeter), sizingMatch: (0,_device_sizing_chart_calculations__WEBPACK_IMPORTED_MODULE_18__.sizingMatches)(device, measurements), sizingParameterBounds: `${device.sizingParameter.lowerBound} - ${device.sizingParameter.upperBound} ${device.sizingParameter.units}`, sizingParameterNameKey: `deviceSizingChart.parameters.${device.sizingParameter.name}` })); }, ...(ngDevMode ? [{ debugName: "rows" }] : [])); matchingDeviceCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.rows().filter(({ sizingMatch }) => sizingMatch).length, ...(ngDevMode ? [{ debugName: "matchingDeviceCount" }] : [])); totalDeviceCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.rows().length, ...(ngDevMode ? [{ debugName: "totalDeviceCount" }] : [])); areaLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const area = this.selectedMeasurements()?.area; return area === undefined ? '-' : `${this.formatNumber(area)} mm²`; }, ...(ngDevMode ? [{ debugName: "areaLabel" }] : [])); perimeterLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const perimeter = this.selectedMeasurements()?.perimeter; return perimeter === undefined ? '-' : `${this.formatNumber(perimeter)} mm`; }, ...(ngDevMode ? [{ debugName: "perimeterLabel" }] : [])); deviceMatchesFilter(device, terms) { if (terms.length === 0) return true; const name = `${device.manufacturer} ${device.model}`.toLowerCase(); return terms.every(term => name.includes(term)); } sizeLabel(value, units) { return `${value} ${units}`; } formatNumber(value) { return value.toFixed(1).replace('.0', ''); } static ɵfac = function DeviceSizingChartDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DeviceSizingChartDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵdefineComponent"]({ type: DeviceSizingChartDialogComponent, selectors: [["lib-device-sizing-chart-dialog"]], inputs: { initialSplineId: [1, "initialSplineId"] }, decls: 3, vars: 1, consts: [["selectedItem", ""], ["item", ""], ["header", ""], ["body", ""], ["emptymessage", ""], [1, "flex", "h-full", "min-h-0", "flex-col", "gap-4", "p-4"], ["severity", "secondary", "variant", "simple"], [1, "grid", "gap-3", "md:grid-cols-[minmax(16rem,24rem)_minmax(16rem,24rem)_auto_minmax(6rem,16rem)]", "md:items-end"], [1, "flex", "flex-col", "gap-1"], [1, "text-muted-color", "text-sm", "uppercase"], [1, "pi", "pi-search"], ["pInputText", "", "type", "text", "data-test-id", "device-sizing-chart-input-filter", 1, "w-full", 3, "ngModelChange", "ngModel", "placeholder"], ["appendTo", "body", "optionLabel", "name", "data-test-id", "device-sizing-chart-p-select-spline", 3, "ngModelChange", "ngModel", "options"], [1, "border-surface-200", "flex", "grow", "gap-2", "px-3", "py-2", "text-sm"], [1, "text-muted-color", "font-bold", "tracking-wide", "uppercase"], [1, "text-muted-color"], [1, "flex", "items-center", "justify-end", "gap-2"], [1, "text-muted-color", "py-3", "text-sm"], [1, "col-span-full", "flex", "justify-end"], [1, "min-h-0", "flex-1"], ["scrollHeight", "flex", "sortField", "sizingMatch", 1, "h-full", 3, "value", "scrollable", "sortOrder"], [1, "flex", "min-w-0", "items-center", "gap-2"], [1, "size-4", 3, "icon", "iconStyle"], [1, "min-w-0", "truncate"], ["severity", "secondary", "text", "", "data-test-id", "device-sizing-chart-p-button-clear-filter", 3, "onClick", "label"], ["pSortableColumn", "manufacturer"], ["field", "manufacturer"], ["pSortableColumn", "model"], ["field", "model"], ["pSortableColumn", "nominalSize", 1, "whitespace-nowrap"], ["field", "nominalSize"], [1, "whitespace-nowrap"], ["pSortableColumn", "areaOversizing", 1, "whitespace-nowrap"], ["field", "areaOversizing"], ["pSortableColumn", "perimeterOversizing", 1, "whitespace-nowrap"], ["field", "perimeterOversizing"], ["pSortableColumn", "sizingMatch", 1, "whitespace-nowrap"], ["field", "sizingMatch"], [1, "px-2"], [3, "severity", "value"], [1, "text-muted-color", "text-xs"], ["colspan", "7", 1, "h-full", "py-6"], [1, "flex", "h-full", "min-h-96", "flex-col", "items-center", "justify-center", "gap-3"], [1, "text-muted-color", "text-center"], ["severity", "secondary", "size", "small", "data-test-id", "device-sizing-chart-p-button-clear-filter", 3, "onClick", "outlined", "label"]], template: function DeviceSizingChartDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 5); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](1, DeviceSizingChartDialogComponent_Conditional_1_Template, 3, 3, "p-message", 6)(2, DeviceSizingChartDialogComponent_Conditional_2_Template, 44, 31); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx.closedSplines().length === 0 ? 1 : 2); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_6__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_6__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgModel, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_17__.IconComponent, primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__.InputText, primeng_iconfield__WEBPACK_IMPORTED_MODULE_7__.IconFieldModule, primeng_iconfield__WEBPACK_IMPORTED_MODULE_7__.IconField, primeng_inputicon__WEBPACK_IMPORTED_MODULE_8__.InputIconModule, primeng_inputicon__WEBPACK_IMPORTED_MODULE_8__.InputIcon, primeng_message__WEBPACK_IMPORTED_MODULE_10__.Message, primeng_select__WEBPACK_IMPORTED_MODULE_11__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_11__.Select, primeng_table__WEBPACK_IMPORTED_MODULE_12__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_12__.Table, primeng_table__WEBPACK_IMPORTED_MODULE_12__.SortableColumn, primeng_table__WEBPACK_IMPORTED_MODULE_12__.SortIcon, primeng_tag__WEBPACK_IMPORTED_MODULE_13__.Tag, _angular_common__WEBPACK_IMPORTED_MODULE_0__.PercentPipe, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 26755 /*!****************************************************************************************!*\ !*** ./libs/feature/src/lib/device-sizing-chart/device-sizing-chart-dialog.service.ts ***! \****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DeviceSizingChartDialogService: () => (/* binding */ DeviceSizingChartDialogService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _device_sizing_chart_dialog_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./device-sizing-chart-dialog.component */ 20619); class DeviceSizingChartDialogService { dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_2__.DialogService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateService); open(initialSplineId) { this.dialogService.open(_device_sizing_chart_dialog_component__WEBPACK_IMPORTED_MODULE_3__.DeviceSizingChartDialogComponent, { breakpoints: { '640px': '96vw', '960px': '90vw' }, closable: true, closeOnEscape: true, contentStyle: { height: '80vh', overflow: 'hidden' }, header: this.translate.instant('deviceSizingChart.title'), inputValues: { initialSplineId }, modal: true, width: '90vw' }); } static ɵfac = function DeviceSizingChartDialogService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DeviceSizingChartDialogService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: DeviceSizingChartDialogService, factory: DeviceSizingChartDialogService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 31997 /*!**************************************************************************************!*\ !*** ./libs/feature/src/lib/device-sizing-chart/device-sizing-chart.calculations.ts ***! \**************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ oversizingArea: () => (/* binding */ oversizingArea), /* harmony export */ oversizingPerimeter: () => (/* binding */ oversizingPerimeter), /* harmony export */ sizingMatches: () => (/* binding */ sizingMatches) /* harmony export */ }); function oversizingArea(deployedDiameter, splineArea) { const deviceArea = Math.PI * 0.25 * deployedDiameter * deployedDiameter; return (deviceArea - splineArea) / splineArea; } function oversizingPerimeter(deployedDiameter, splinePerimeter) { const devicePerimeter = Math.PI * deployedDiameter; return (devicePerimeter - splinePerimeter) / splinePerimeter; } function sizingMatches(device, measurements) { const sizingValue = device.sizingParameter.name === 'area' ? measurements.area : measurements.perimeter; const lowerMatches = device.sizingParameter.lowerBoundExclusive ? sizingValue > device.sizingParameter.lowerBound : sizingValue >= device.sizingParameter.lowerBound; const upperMatches = device.sizingParameter.upperBoundExclusive ? sizingValue < device.sizingParameter.upperBound : sizingValue <= device.sizingParameter.upperBound; return lowerMatches && upperMatches; } /***/ }, /***/ 25235 /*!******************************************************************************!*\ !*** ./libs/feature/src/lib/device-sizing-chart/device-sizing-chart.data.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TAVR_DEVICES: () => (/* binding */ TAVR_DEVICES) /* harmony export */ }); const TAVR_DEVICES = [device('Edwards', 'Sapien 3 Ultra', 20, 'area', 273, 345, 'mm²'), device('Edwards', 'Sapien 3 Ultra', 23, 'area', 338, 430, 'mm²'), device('Edwards', 'Sapien 3 Ultra', 26, 'area', 430, 546, 'mm²'), device('Edwards', 'Sapien 3 Ultra', 29, 'area', 540, 683, 'mm²'), device('Medtronic', 'Evolut R, Pro, Fx', 23, 'perimeter', 56.6, 62.8, 'mm'), device('Medtronic', 'Evolut R, Pro, Fx', 26, 'perimeter', 62.8, 72.3, 'mm'), device('Medtronic', 'Evolut R, Pro, Fx', 29, 'perimeter', 72.3, 81.7, 'mm'), device('Medtronic', 'Evolut R, Pro, Fx', 34, 'perimeter', 81.7, 94.2, 'mm'), device('Boston Scientific', 'ACURATE neo2 S', 23, 'perimeter', 66, 72, 'mm'), device('Boston Scientific', 'ACURATE neo2 M', 25, 'perimeter', 72, 79, 'mm'), device('Boston Scientific', 'ACURATE neo2 L', 27, 'perimeter', 79, 85, 'mm'), device('Boston Scientific', 'ACURATE Prime XL', 29, 'perimeter', 83, 91, 'mm'), device('Abbott', 'Navitor', 23, 'perimeter', 60, 66, 'mm'), device('Abbott', 'Navitor', 25, 'perimeter', 66, 73, 'mm'), device('Abbott', 'Navitor', 27, 'perimeter', 72, 79, 'mm'), device('Abbott', 'Navitor', 29, 'perimeter', 79, 85, 'mm'), device('Meril', 'Myval', 20, 'area', 270, 330, 'mm²'), device('Meril', 'Myval', 21.5, 'area', 314, 380, 'mm²'), device('Meril', 'Myval', 23, 'area', 360, 440, 'mm²'), device('Meril', 'Myval', 24.5, 'area', 410, 500, 'mm²'), device('Meril', 'Myval', 26, 'area', 460, 560, 'mm²'), device('Meril', 'Myval', 27.5, 'area', 510, 630, 'mm²'), device('Meril', 'Myval', 29, 'area', 570, 700, 'mm²'), device('Meril', 'Myval', 30.5, 'area', 630, 770, 'mm²'), device('Meril', 'Myval', 32, 'area', 700, 840, 'mm²'), device('JenaValve', 'Trilogy-THV-S', 23, 'perimeter', 66, 74, 'mm'), device('JenaValve', 'Trilogy-THV-M', 25, 'perimeter', 71, 79, 'mm'), device('JenaValve', 'Trilogy-THV-L', 27, 'perimeter', 76, 85, 'mm'), device('JenaValve', 'JenaValve', 23, 'perimeter', 66, 74, 'mm'), device('JenaValve', 'JenaValve', 25, 'perimeter', 71, 79, 'mm'), device('JenaValve', 'JenaValve', 27, 'perimeter', 76, 85, 'mm'), device('MicroPort', 'VitaFlow', 21, 'perimeter', 53.4, 62.8, 'mm'), device('MicroPort', 'VitaFlow', 24, 'perimeter', 62.8, 72.3, 'mm'), device('MicroPort', 'VitaFlow', 27, 'perimeter', 72.3, 81.7, 'mm'), device('MicroPort', 'VitaFlow', 30, 'perimeter', 81.7, 91.1, 'mm'), device('Biosensors International', 'ALLEGRA', 23, 'perimeter', 59.7, 69.1, 'mm'), device('Biosensors International', 'ALLEGRA', 27, 'perimeter', 69.1, 78.5, 'mm'), device('Biosensors International', 'ALLEGRA', 31, 'perimeter', 78.5, 88, 'mm'), device('Products & Features', 'Vienna', 23, 'perimeter', 53.4, 66, 'mm'), device('Products & Features', 'Vienna', 26, 'perimeter', 66, 72.3, 'mm'), device('Products & Features', 'Vienna', 29, 'perimeter', 72.3, 81.7, 'mm'), device('Products & Features', 'Vienna', 31, 'perimeter', 81.7, 91.1, 'mm')]; function device(manufacturer, model, diameter, parameterName, lowerBound, upperBound, units) { return { deployedSize: { name: 'diameter', units: 'mm', value: diameter }, manufacturer, model, nominalSize: { name: 'diameter', units: 'mm', value: diameter }, sizingParameter: { lowerBound, name: parameterName, units, upperBound } }; } /***/ }, /***/ 18809 /*!*****************************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/dicom-importer-dialog/dicom-importer-dialog.component.ts ***! \*****************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DICOM_IMPORTER_DIALOG_OPTIONS: () => (/* binding */ DICOM_IMPORTER_DIALOG_OPTIONS), /* harmony export */ DicomImporterDialogComponent: () => (/* binding */ DicomImporterDialogComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../../logging/utils */ 14337); /* harmony import */ var _services_dicom_importer_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../services/dicom-importer.service */ 14043); /* harmony import */ var _patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../patient-library/patient-library-list.facade */ 67045); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["fileInput"]; const _c1 = a0 => ({ store: a0 }); function DicomImporterDialogComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "lib-heading-area", 8)(1, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](2, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](3, "div")(4, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](6, "div", 11)(7, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](10, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](11, "\u00B7"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](12, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](13); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](14, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementContainerStart"](15, 12); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](16, "div", 13)(17, "div", 14)(18, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](19); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](20, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](21, "div", 15); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](22, "div")(23, "div", 16)(24, "p-button", 17); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("click", function DicomImporterDialogComponent_Conditional_3_Template_p_button_click_24_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setViewMode("list")); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](25, "lib-icon", 18); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](26, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("click", function DicomImporterDialogComponent_Conditional_3_Template_p_button_click_26_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setViewMode("grid")); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](27, "lib-icon", 20); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementContainerEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵclassProp"]("blur-sm", ctx_r2.isImporting()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("showBackButton", false); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("icon", "folder-open"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", ctx_r2.importedFolderName(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate2"](" ", ctx_r2.patientCount(), " ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](9, 13, "dicomImporter.importDialog.heading.patients"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate2"](" ", ctx_r2.studyCount(), " ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](14, 15, "dicomImporter.importDialog.heading.studies"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate2"](" ", ctx_r2.seriesCount(), " ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](20, 17, "dicomImporter.importDialog.heading.series"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("severity", ctx_r2.viewMode() === "list" ? "primary" : "secondary"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("severity", ctx_r2.viewMode() === "grid" ? "primary" : "secondary"); } } function DicomImporterDialogComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("dragover", function DicomImporterDialogComponent_Conditional_5_Template_div_dragover_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.onDragOver($event)); })("dragleave", function DicomImporterDialogComponent_Conditional_5_Template_div_dragleave_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.onDragLeave($event)); })("drop", function DicomImporterDialogComponent_Conditional_5_Template_div_drop_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.onDrop($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](1, "div", 22); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](2, "lib-icon", 23); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](3, "div", 24)(4, "p", 25); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](7, "p", 26); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](10, "p-button", 27); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("click", function DicomImporterDialogComponent_Conditional_5_Template_p_button_click_10_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.importDicomFiles()); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](11); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()()(); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵclassProp"]("ring-2", ctx_r2.isDragOver())("ring-primary", ctx_r2.isDragOver())("bg-surface-500", ctx_r2.isDragOver())("opacity-50", ctx_r2.isImporting() || ctx_r2.isClearingLocalImports())("pointer-events-none", ctx_r2.isImporting() || ctx_r2.isClearingLocalImports()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](6, 14, "dicomImporter.emptyState.title"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](9, 16, "dicomImporter.emptyState.subtitle"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("disabled", ctx_r2.isImporting() || ctx_r2.isClearingLocalImports()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](12, 18, "dicomImporter.emptyState.button"), " "); } } function DicomImporterDialogComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "div", 28)(1, "lib-table", 29); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtwoWayListener"]("selectedRowDataChange", function DicomImporterDialogComponent_Conditional_6_Template_lib_table_selectedRowDataChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtwoWayBindingSet"](ctx_r2.selectedImporterRows, $event) || (ctx_r2.selectedImporterRows = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵclassProp"]("blur-sm", ctx_r2.isImporting())("pointer-events-none", ctx_r2.isImporting()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("allowRowSelection", true)("columns", ctx_r2.columns)("rowData", ctx_r2.series()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtwoWayProperty"]("selectedRowData", ctx_r2.selectedImporterRows); } } function DicomImporterDialogComponent_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](0, "p-progressBar", 30); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](1, "span", 31); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](3, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](4, "%"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("showValue", false)("value", ctx_r2.totalProgress()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate"](ctx_r2.totalProgress()); } } function DicomImporterDialogComponent_Conditional_7_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "p-button", 32); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("click", function DicomImporterDialogComponent_Conditional_7_Conditional_2_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.clearAllLocalImports()); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](1, "lib-icon", 33); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](4, "p-button", 34); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("click", function DicomImporterDialogComponent_Conditional_7_Conditional_2_Template_p_button_click_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.bulkImportToLibrary()); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelement"](5, "lib-icon", 35); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("text", true)("disabled", ctx_r2.isImporting())("loading", ctx_r2.isClearingLocalImports()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind1"](3, 7, "dicomImporter.clearAllButton"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵproperty"]("disabled", ctx_r2.selectedImporterRows().length === 0 || ctx_r2.isImporting() || ctx_r2.dicomImporterService.isImportingToLibrary())("loading", ctx_r2.dicomImporterService.isImportingToLibrary()); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpipeBind2"](7, 9, ctx_r2.selectedStoreName() ? "dicomImporter.importToStoreButton" : "dicomImporter.importToLibraryButton", _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵpureFunction1"](12, _c1, ctx_r2.selectedStoreName())), " "); } } function DicomImporterDialogComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditionalCreate"](1, DicomImporterDialogComponent_Conditional_7_Conditional_1_Template, 5, 3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditionalCreate"](2, DicomImporterDialogComponent_Conditional_7_Conditional_2_Template, 8, 14); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditional"](ctx_r2.isImporting() ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditional"](ctx_r2.series().length > 0 ? 2 : -1); } } const DICOM_IMPORTER_DIALOG_OPTIONS = { closable: true, draggable: false, height: '90vh', modal: true, pt: { root: 'p-2 px-4', title: 'text-3xl px-2' }, resizable: false, width: '80vw' }; class DicomImporterDialogComponent { fileInput; log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_10__.getLogger)(DicomImporterDialogComponent.name); dialogRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_6__.DynamicDialogRef, { optional: true }); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_4__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); isDragOver = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : [])); dicomImportService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_8__.DicomImportService); dicomImporterService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_dicom_importer_service__WEBPACK_IMPORTED_MODULE_11__["default"]); patientLibraryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_12__.PatientLibraryListFacade); selectedStoreUid = this.patientLibraryFacade.selectedStoreUid; selectedStoreName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.patientLibraryFacade.stores().find(store => store.uid === this.selectedStoreUid())?.name, ...(ngDevMode ? [{ debugName: "selectedStoreName" }] : [])); columns = [{ field: 'patientName', format: 'dicomPersonName' }, { field: 'patientID' }, { field: 'studyDate', format: 'dicomDate' }, { field: 'modality' }, { field: 'seriesDescription' }, { field: 'images' }, { field: 'studyDescription' }]; selectedImporterRows = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "selectedImporterRows" }] : [])); isClearingLocalImports = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "isClearingLocalImports" }] : [])); totalProgress = this.dicomImportService.totalProgress; // Signal-based rather than progress-based so the table stays in its loading // state until the last staged instance has been written to the local db. isImporting = this.dicomImportService.isImporting; viewMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)('list', ...(ngDevMode ? [{ debugName: "viewMode" }] : [])); clearedSeriesUids = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(new Set(), ...(ngDevMode ? [{ debugName: "clearedSeriesUids" }] : [])); series = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { return this.dicomImporterService.series().filter(row => !this.clearedSeriesUids().has(row.seriesInstanceUID)); }, ...(ngDevMode ? [{ debugName: "series" }] : [])); seriesCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.series().length, ...(ngDevMode ? [{ debugName: "seriesCount" }] : [])); studyCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => new Set(this.series().map(row => row.studyInstanceUID)).size, ...(ngDevMode ? [{ debugName: "studyCount" }] : [])); patientCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => new Set(this.series().map(row => row.patientID)).size, ...(ngDevMode ? [{ debugName: "patientCount" }] : [])); importedFolderName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "importedFolderName" }] : [])); knownSeriesUids = new Set(); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const stagedUids = new Set(this.dicomImporterService.series().map(row => row.seriesInstanceUID)); const cleared = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(this.clearedSeriesUids); if ([...cleared].some(uid => !stagedUids.has(uid))) { this.clearedSeriesUids.set(new Set([...cleared].filter(uid => stagedUids.has(uid)))); } }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const series = this.series(); const knownUids = this.knownSeriesUids; this.knownSeriesUids = new Set(series.map(row => row.seriesInstanceUID)); const selectedUids = new Set((0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(this.selectedImporterRows).map(row => row.seriesInstanceUID)); this.selectedImporterRows.set(series.filter(row => selectedUids.has(row.seriesInstanceUID) || !knownUids.has(row.seriesInstanceUID))); }); } bulkImportToLibrary() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const selectedRows = _this.selectedImporterRows(); const uploadedSeriesUids = yield _this.dicomImporterService.importToLibrary(selectedRows); if (selectedRows.length === 0 || uploadedSeriesUids.length < selectedRows.length) return; _this.dialogRef?.close(); })(); } clearAllLocalImports() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const seriesUids = _this2.series().map(row => row.seriesInstanceUID); _this2.selectedImporterRows.set([]); _this2.clearedSeriesUids.set(new Set(seriesUids)); _this2.isClearingLocalImports.set(true); try { yield _this2.dicomImporterService.deleteStagedSeries(seriesUids); } catch (error) { _this2.clearedSeriesUids.set(new Set()); _this2.log.error('Failed to clear staged series', error); _this2.messageService.add({ life: 4000, severity: 'error', summary: _this2.translate.instant('dicomImporter.clearToast.error') }); } finally { _this2.isClearingLocalImports.set(false); } })(); } importDicomFiles() { if (!this.fileInput) { this.log.warn('file input not available'); return; } this.fileInput.nativeElement.value = ''; this.fileInput.nativeElement.click(); } onFilesSelected(event) { const input = event.target; if (!input.files || input.files.length === 0) { return; } const inputFiles = input.files; this.setFolderNameFromFiles(inputFiles); this.dicomImportService.onFilesSelected(inputFiles, this.selectedStoreUid()); } onDragOver(event) { if (this.isImporting() || this.isClearingLocalImports()) return; event.preventDefault(); this.isDragOver.set(true); } onDragLeave(event) { event.preventDefault(); this.isDragOver.set(false); } setViewMode(mode) { this.viewMode.set(mode); } onDrop(event) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { event.preventDefault(); _this3.isDragOver.set(false); if (_this3.isImporting() || _this3.isClearingLocalImports()) return; const items = event.dataTransfer?.items; if (!items) return; const files = yield _this3.collectFilesFromItems(items); if (files.length === 0) return; _this3.setFolderNameFromFiles(files); const dt = new DataTransfer(); for (const f of files) dt.items.add(f); _this3.dicomImportService.onFilesSelected(dt.files, _this3.selectedStoreUid()); })(); } collectFilesFromItems(items) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const files = []; const entries = Array.from({ length: items.length }, (_, index) => items[index]?.webkitGetAsEntry()).filter(entry => entry !== null); yield Promise.all(entries.map(entry => _this4.traverseEntry(entry, files))); return files; })(); } traverseEntry(entry, files) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (entry.isFile) { const file = yield new Promise((resolve, reject) => entry.file(resolve, reject)); files.push(file); } else if (entry.isDirectory) { const reader = entry.createReader(); const children = yield _this5.readAllEntries(reader); yield Promise.all(children.map(c => _this5.traverseEntry(c, files))); } else { // unsupported entry type, skip } })(); } setFolderNameFromFiles(files) { const fileArray = files instanceof FileList ? [...files] : files; const first = fileArray[0]; const relativePath = first?.webkitRelativePath; this.importedFolderName.set(relativePath?.split('/')[0] || undefined); } readAllEntries(reader) { return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const all = []; let batch; do { batch = yield new Promise((resolve, reject) => reader.readEntries(resolve, reject)); all.push(...batch); } while (batch.length > 0); return all; })(); } static ɵfac = function DicomImporterDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomImporterDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵdefineComponent"]({ type: DicomImporterDialogComponent, selectors: [["lib-dicom-importer-dialog"]], viewQuery: function DicomImporterDialogComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵviewQuery"](_c0, 5); } if (rf & 2) { let _t; _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵqueryRefresh"](_t = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵloadQuery"]()) && (ctx.fileInput = _t.first); } }, hostAttrs: [1, "flex", "h-full", "flex-col"], decls: 8, vars: 3, consts: [["fileInput", ""], [1, "bg-surface-900", "text-color", "flex", "h-full", "flex-col", "px-4"], ["data-test-id", "dicom-importer-dialog-input-files", "type", "file", "multiple", "", "webkitdirectory", "", "mozdirectory", "", "directory", "", 2, "display", "none", 3, "change"], [3, "showBackButton", "blur-sm"], [1, "relative", "min-h-0", "flex-1"], [1, "flex", "h-full", "items-center", "justify-center", "pt-8"], [1, "h-full", "overflow-auto", "transition-[filter]", 3, "blur-sm", "pointer-events-none"], [1, "flex", "shrink-0", "items-center", "justify-end", "gap-2", "py-4"], [3, "showBackButton"], ["left", "", 1, "flex", "items-center", "gap-2"], [1, "flex", "items-center", "justify-center", 3, "icon"], ["data-test-id", "dicom-importer-dialog-div-series-summary", 1, "text-muted-color", "mb-2", "flex", "shrink-0", "items-center", "gap-1", "text-sm"], ["right", ""], [1, "flex", "items-center", "gap-4"], ["data-test-id", "dicom-importer-dialog-div-series-summary", 1, "text-muted-color", "mb-2", "flex", "shrink-0", "items-center", "gap-2", "pt-2", "text-sm"], [1, "h-8", "w-px", "bg-(--p-app-surface-tab)"], [1, "flex", "gap-1", "rounded-md", "bg-(--p-app-neutral-950)", "p-1"], ["data-test-id", "dicom-importer-dialog-p-button-view-list", "severity", "secondary", "size", "large", "variant", "text", 3, "click", "severity"], ["icon", "list"], ["data-test-id", "dicom-importer-dialog-p-button-view-grid", "severity", "secondary", "size", "large", "variant", "text", 3, "click", "severity"], ["icon", "th-large"], [1, "flex", "h-full", "items-center", "justify-center", "pt-8", 3, "dragover", "dragleave", "drop"], [1, "keep-bg", "bg-surface-600", "flex", "flex-col", "items-center", "gap-5", "rounded-2xl", "px-24", "py-10", "text-center", "transition-all"], ["icon", "file-import", 1, "text-muted-color", "text-5xl"], [1, "flex", "flex-col", "gap-1"], [1, "text-color", "text-lg", "font-semibold"], [1, "text-muted-color", "text-sm"], ["data-test-id", "dicom-importer-dialog-p-button-choose-dicom-file", 3, "click", "disabled"], [1, "h-full", "overflow-auto", "transition-[filter]"], ["translationRoot", "dicomImporter", "rowKey", "seriesInstanceUID", 3, "selectedRowDataChange", "allowRowSelection", "columns", "rowData", "selectedRowData"], ["styleClass", "h-2 w-24", 3, "showValue", "value"], [1, "display-block", "w-8", "text-right"], ["data-test-id", "dicom-importer-dialog-p-button-clear-all", "severity", "danger", "size", "small", 3, "click", "text", "disabled", "loading"], ["icon", "trash"], ["data-test-id", "dicom-importer-dialog-p-button-import-to-store", "size", "small", "rounded", "", 3, "click", "disabled", "loading"], ["icon", "upload"]], template: function DicomImporterDialogComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](0, "div", 1)(1, "input", 2, 0); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵlistener"]("change", function DicomImporterDialogComponent_Template_input_change_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.onFilesSelected($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditionalCreate"](3, DicomImporterDialogComponent_Conditional_3_Template, 28, 19, "lib-heading-area", 3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementStart"](4, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditionalCreate"](5, DicomImporterDialogComponent_Conditional_5_Template, 13, 20, "div", 5)(6, DicomImporterDialogComponent_Conditional_6_Template, 2, 8, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditionalCreate"](7, DicomImporterDialogComponent_Conditional_7_Template, 3, 2, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditional"](ctx.series().length !== 0 ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditional"](ctx.series().length === 0 ? 5 : 6); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_13__["ɵɵconditional"](ctx.series().length > 0 || ctx.isImporting() ? 7 : -1); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.TableComponent, primeng_button__WEBPACK_IMPORTED_MODULE_5__.Button, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__.ProgressBar, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.IconComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.HeadingAreaComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 26133 /*!*******************************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/export-to-store-dialog/export-to-store-dialog.component.ts ***! \*******************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ExportToStoreDialogComponent: () => (/* binding */ ExportToStoreDialogComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/progressspinner */ 7271); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../services/annotation-export-bridge.service */ 68674); /* harmony import */ var _services_dicom_export_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../services/dicom-export.service */ 8027); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ count: a0 }); function ExportToStoreDialogComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](1, "p-progressSpinner", 5); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](2, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](4, 1, "dicomImporter.exportToStoreDialog.exporting"), " "); } } function ExportToStoreDialogComponent_Conditional_2_Conditional_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 11); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](1, "p-progressSpinner", 13); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](4, 1, "dicomImporter.exportToStoreDialog.checkingStores")); } } function ExportToStoreDialogComponent_Conditional_2_Conditional_10_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-select", 14); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayListener"]("ngModelChange", function ExportToStoreDialogComponent_Conditional_2_Conditional_10_Template_p_select_ngModelChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayBindingSet"](ctx_r1.selectedStore, $event) || (ctx_r1.selectedStore = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("options", ctx_r1.stores()); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.selectedStore); } } function ExportToStoreDialogComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 7)(1, "label", 8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](4, "input", 9); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayListener"]("ngModelChange", function ExportToStoreDialogComponent_Conditional_2_Template_input_ngModelChange_4_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayBindingSet"](ctx_r1.analysisName, $event) || (ctx_r1.analysisName = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](5, "div", 7)(6, "label", 10); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](9, ExportToStoreDialogComponent_Conditional_2_Conditional_9_Template, 5, 3, "div", 11)(10, ExportToStoreDialogComponent_Conditional_2_Conditional_10_Template, 1, 2, "p-select", 12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](11, "p", 6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](13, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](3, 6, "dicomImporter.exportToStoreDialog.analysisNameLabel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtwoWayProperty"]("ngModel", ctx_r1.analysisName); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵattribute"]("maxlength", ctx_r1.analysisNameMaxLength); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](8, 8, "dicomImporter.exportToStoreDialog.storeLabel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx_r1.loadingStores() ? 9 : 10); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind2"](13, 10, "dicomImporter.exportToStoreDialog.description", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction1"](13, _c0, ctx_r1.seriesUids.length)), " "); } } /** Matches the `name` field limit in the work session schema (`workSessionSchema`). */ const ANALYSIS_NAME_MAX_LENGTH = 64; class ExportToStoreDialogComponent { ref = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_6__.DynamicDialogRef); config = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_6__.DynamicDialogConfig); exportService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_13__.DicomExportService); exportBridge = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_12__.AnnotationExportBridge); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.DicomStoreListService); workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.WorkSessionDatabaseService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_4__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); state = this.exportService.state; stores = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "stores" }] : [])); loadingStores = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(true, ...(ngDevMode ? [{ debugName: "loadingStores" }] : [])); analysisNameMaxLength = ANALYSIS_NAME_MAX_LENGTH; selectedStore; /** Defaults to the current analysis name; editing it renames the analysis for this export only. */ analysisName = ''; get seriesUids() { return this.config.data?.seriesUids ?? []; } get storeUid() { return this.config.data?.storeUid ?? ''; } get studyUid() { return this.config.data?.studyUid ?? ''; } get workSessionUid() { return this.config.data?.workSessionUid ?? ''; } get existingOtSeriesUid() { return this.config.data?.existingOtSeriesUid; } ngOnInit() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this.analysisName = _this.exportBridge.workSessionName(); try { const stores = yield _this.storeList.getReachableStores(); _this.stores.set(stores); const defaultUid = _this.config.data?.defaultStoreUid; _this.selectedStore = defaultUid && stores.find(s => s.uid === defaultUid) || stores[0]; if (stores.length === 0) { yield _this.warnIfConfiguredStoresUnreachable(); } } finally { _this.loadingStores.set(false); } })(); } /** * Distinguishes "no DICOM stores configured" from "stores are configured but none * responded to a ping" — the latter warrants a toast since it usually means bad * credentials or an unreachable store instance. */ warnIfConfiguredStoresUnreachable() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const enabled = yield _this2.storeList.getEnabledStores(); if (enabled.length === 0) return; _this2.messageService.add({ detail: _this2.translate.instant('dicomImporter.storesUnreachable.detail'), life: 8000, severity: 'error', summary: _this2.translate.instant('dicomImporter.storesUnreachable.summary') }); })(); } onExport() { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const originalName = _this3.exportBridge.workSessionName(); const trimmedName = _this3.analysisName.trim(); const workSessionName = trimmedName || originalName; // The OT series identity is a deterministic function of (work session, name), so // repeat exports under the same name always land on the same series regardless of // whether the name change happened this call or a previous one — unless we're // updating a specific, already-known OT series, whose identity must stay put. const workSessionUID = _this3.existingOtSeriesUid ? _this3.workSessionUid : yield _this3.exportService.deriveRenamedWorkSessionUid(_this3.workSessionUid, workSessionName); yield _this3.exportService.exportSeriesToStore({ activePhaseInstanceUIDs: _this3.exportBridge.sourceInstanceUIDs(), annotations: _this3.exportBridge.annotations(), author: _this3.exportBridge.author, authorUserId: _this3.exportBridge.authorUserId, destinationStoreUid: _this3.selectedStore?.uid, existingOtSeriesUid: _this3.existingOtSeriesUid, phaseLabel: _this3.exportBridge.activePhaseLabel(), previewPixels: _this3.exportBridge.capturePreview?.(), protocolBindings: _this3.exportBridge.protocolBindings(), protocolFormValues: _this3.exportBridge.protocolFormValues(), renderSettings2D: _this3.exportBridge.renderSettings2D(), renderSettings3D: _this3.exportBridge.renderSettings3D(), seriesUids: _this3.seriesUids, sourceStudyUid: _this3.studyUid, storeUid: _this3.storeUid, workSessionName, workSessionUID }); // Only rename the local record once the store export has actually succeeded, // so a failed export doesn't leave the local name out of sync with the store. if (_this3.workSessionUid) { yield _this3.renameLocalWorkSessionIfPresent(_this3.workSessionUid, workSessionName); } _this3.ref.close({ messageKey: 'dicomImporter.exportToast.success', severity: 'success' }); } catch (error) { _this3.ref.close({ detail: error.message, messageKey: 'dicomImporter.exportToast.error', severity: 'error' }); } })(); } onCancel() { this.ref.close(); } /** Keeps the local analysis record's name in sync when it's already been saved to RxDB. */ renameLocalWorkSessionIfPresent(uid, name) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const existing = yield _this4.workSessionDb.get(uid); if (!existing || existing.name === name) return; const updated = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_10__.workSessionSchema.parse({ ...existing, name }); yield _this4.workSessionDb.save(updated, { incrementVersion: true }); })(); } static ɵfac = function ExportToStoreDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ExportToStoreDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵdefineComponent"]({ type: ExportToStoreDialogComponent, selectors: [["lib-export-to-store-dialog"]], features: [_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵProvidersFeature"]([_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_13__.DicomExportService])], decls: 10, vars: 9, consts: [[1, "flex", "flex-col", "gap-6", "p-4"], [1, "flex", "flex-col", "items-center", "gap-3", "py-4"], [1, "flex", "justify-end", "gap-2"], ["data-test-id", "export-to-store-dialog-p-button-cancel", "severity", "secondary", "outlined", "", 3, "click", "disabled"], ["data-test-id", "export-to-store-dialog-p-button-export", 3, "click", "disabled"], ["strokeWidth", "4", 1, "size-12"], [1, "text-muted-color", "text-sm"], [1, "flex", "flex-col", "gap-2"], ["for", "export-to-store-dialog-analysis-name", 1, "text-muted-color", "text-sm", "font-medium"], ["id", "export-to-store-dialog-analysis-name", "data-test-id", "export-to-store-dialog-input-analysis-name", "pInputText", "", 1, "w-full", 3, "ngModelChange", "ngModel"], [1, "text-muted-color", "text-sm", "font-medium"], [1, "text-muted-color", "flex", "w-full", "items-center", "justify-center", "gap-2", "text-sm"], ["data-test-id", "export-to-store-dialog-p-select-store", "optionLabel", "name", 1, "w-full", 3, "options", "ngModel"], ["strokeWidth", "4", 1, "size-4"], ["data-test-id", "export-to-store-dialog-p-select-store", "optionLabel", "name", 1, "w-full", 3, "ngModelChange", "options", "ngModel"]], template: function ExportToStoreDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](1, ExportToStoreDialogComponent_Conditional_1_Template, 5, 3, "div", 1)(2, ExportToStoreDialogComponent_Conditional_2_Template, 14, 15); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "div", 2)(4, "p-button", 3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("click", function ExportToStoreDialogComponent_Template_p_button_click_4_listener() { return ctx.onCancel(); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](7, "p-button", 4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("click", function ExportToStoreDialogComponent_Template_p_button_click_7_listener() { return ctx.onExport(); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx.state() === "exporting" ? 1 : 2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("disabled", ctx.state() === "exporting"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](6, 5, "dicomImporter.exportToStoreDialog.cancel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("disabled", !ctx.selectedStore || ctx.stores().length === 0 || ctx.state() === "exporting" || ctx.loadingStores()); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](9, 7, "dicomImporter.exportToStoreDialog.export"), " "); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_5__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_5__.Button, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateModule, primeng_select__WEBPACK_IMPORTED_MODULE_9__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_9__.Select, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgModel, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__.ProgressSpinnerModule, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__.ProgressSpinner, primeng_inputtext__WEBPACK_IMPORTED_MODULE_7__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_7__.InputText, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 89442 /*!*****************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/instance-picker.component.ts ***! \*****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ InstancePickerComponent: () => (/* binding */ InstancePickerComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../review-status-icon/review-status-icon.component */ 92729); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/api */ 62751); const _c0 = ["popover"]; const _c1 = () => ({ background: "{surface.800}", borderColor: "{primary.500}", color: "{surface.50}" }); const _c2 = a0 => ({ root: a0 }); const _c3 = () => ({ borderColor: "{surface.700}" }); const _c4 = () => ({ background: "{surface.800}", borderColor: "{surface.700}", color: "{surface.50}" }); const _c5 = () => ({ background: "{surface.800}", color: "{surface.50}", hoverBackground: "{surface.700}" }); const _c6 = (a0, a1, a2) => ({ bodyCell: a0, headerCell: a1, row: a2 }); function InstancePickerComponent_ng_template_3_Conditional_12_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](0, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](2, 1, "patientDetails.instancePicker.phase")); } } function InstancePickerComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](0, "tr")(1, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](2, "#"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](3, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](6, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](9, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditionalCreate"](12, InstancePickerComponent_ng_template_3_Conditional_12_Template, 3, 3, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](13, "th", 5); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](14); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](15, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](16, "th", 5); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelement"](19, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](5, 6, "patientDetails.instancePicker.date")); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](8, 8, "patientDetails.instancePicker.time")); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](11, 10, "patientDetails.instancePicker.annotator")); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditional"](ctx_r0.hasPhaseLabels() ? 12 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](15, 12, "patientDetails.instancePicker.reviewed")); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](18, 14, "patientDetails.instancePicker.local")); } } function InstancePickerComponent_ng_template_4_Conditional_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](0, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵnextContext"](); const item_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](item_r3.phaseLabel || "\u2014"); } } function InstancePickerComponent_ng_template_4_Conditional_14_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](0, "span", 7); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelement"](1, "lib-icon", 9); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](2, 1, "patientDetails.cachedLocally")); } } function InstancePickerComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](1, "tr")(2, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](4, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](6, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](8, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](9); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditionalCreate"](10, InstancePickerComponent_ng_template_4_Conditional_10_Template, 2, 1, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](11, "td", 5); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelement"](12, "lib-review-status-icon", 6); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](13, "td", 5); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditionalCreate"](14, InstancePickerComponent_ng_template_4_Conditional_14_Template, 3, 3, "span", 7); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](15, "td")(16, "p-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵlistener"]("click", function InstancePickerComponent_ng_template_4_Template_p_button_click_16_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵrestoreView"](_r2); const item_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵreadContextLet"](0); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵnextContext"](); ctx_r0.hide(); return _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵresetView"](item_r3.open()); }); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"]()()(); } if (rf & 2) { const rawItem_r4 = ctx.$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵnextContext"](); const item_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵstoreLet"](ctx_r0.asItem(rawItem_r4)); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](item_r5.index); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](item_r5.date); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](item_r5.time); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate"](item_r5.annotator); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditional"](ctx_r0.hasPhaseLabels() ? 10 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵproperty"]("status", item_r5.reviewStatus); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵconditional"](item_r5.isLocal ? 14 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpipeBind1"](18, 9, "patientDetails.open"), " "); } } class InstancePickerComponent { popover; items = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)([], ...(ngDevMode ? [{ debugName: "items" }] : [])); hasPhaseLabels = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.items().some(item => item.phaseLabel), ...(ngDevMode ? [{ debugName: "hasPhaseLabels" }] : [])); onDocumentPointerDown(event) { const target = event.target; if (!target.closest('.instance-picker-popover') && !target.closest('lib-instance-picker')) { this.popover?.hide(); } } /** * Takes the element rather than the originating event: a menu command runs long after * its event was dispatched, by which point `currentTarget` is null. */ toggleAt(anchor) { this.popover?.toggle(new MouseEvent('click'), anchor); } hide() { this.popover?.hide(); document.querySelector('.instance-picker-popover')?.remove(); } asItem(value) { return value; } static ɵfac = function InstancePickerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || InstancePickerComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵdefineComponent"]({ type: InstancePickerComponent, selectors: [["lib-instance-picker"]], viewQuery: function InstancePickerComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵviewQuery"](_c0, 5); } if (rf & 2) { let _t; _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵqueryRefresh"](_t = _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵloadQuery"]()) && (ctx.popover = _t.first); } }, hostBindings: function InstancePickerComponent_HostBindings(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵlistener"]("pointerdown", function InstancePickerComponent_pointerdown_HostBindingHandler($event) { return ctx.onDocumentPointerDown($event); }, _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵresolveDocument"]); } }, inputs: { items: [1, "items"] }, decls: 5, vars: 13, consts: [["popover", ""], ["data-test-id", "patient-library-p-popover-instance-picker", 3, "dt"], ["styleClass", "text-sm", 3, "value", "dt"], ["pTemplate", "header"], ["pTemplate", "body"], [1, "text-center"], [3, "status"], [1, "text-muted-color", "inline-flex", "cursor-default"], ["data-test-id", "patient-library-p-button-open-instance", "outlined", "", "size", "small", 3, "click"], ["icon", "check-circle"]], template: function InstancePickerComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementStart"](0, "p-popover", 1, 0)(2, "p-table", 2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵtemplate"](3, InstancePickerComponent_ng_template_3_Template, 20, 16, "ng-template", 3)(4, InstancePickerComponent_ng_template_4_Template, 19, 11, "ng-template", 4); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction1"](4, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction0"](3, _c1))); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵproperty"]("value", ctx.items())("dt", _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction3"](9, _c6, _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction0"](6, _c3), _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction0"](7, _c4), _angular_core__WEBPACK_IMPORTED_MODULE_9__["ɵɵpureFunction0"](8, _c5))); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_3__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_3__.Button, primeng_api__WEBPACK_IMPORTED_MODULE_10__.PrimeTemplate, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_6__.IconComponent, primeng_popover__WEBPACK_IMPORTED_MODULE_4__.PopoverModule, primeng_popover__WEBPACK_IMPORTED_MODULE_4__.Popover, _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_7__.ReviewStatusIconComponent, primeng_table__WEBPACK_IMPORTED_MODULE_5__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_5__.Table, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 71086 /*!*************************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/patient-library-details.component.ts ***! \*************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatientLibraryDetailsComponent: () => (/* binding */ PatientLibraryDetailsComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var primeng_progressspinner__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/progressspinner */ 7271); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _phase_selection_dialog_phase_selection_dialog_service__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../../../phase-selection-dialog/phase-selection-dialog.service */ 3124); /* harmony import */ var _services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../../services/dicom-annotation-codec */ 19462); /* harmony import */ var _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../review-status-icon/review-status-icon.component */ 92729); /* harmony import */ var _instance_picker_component__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ./instance-picker.component */ 89442); /* harmony import */ var _patient_library_details_facade__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ./patient-library-details.facade */ 21723); /* harmony import */ var _patient_library_list_facade__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ./patient-library-list.facade */ 67045); /* harmony import */ var _series_bulk_actions_component__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ./series-bulk-actions.component */ 36088); /* harmony import */ var _series_sort_store__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ./series-sort.store */ 14900); const _c0 = a0 => ({ count: a0 }); const _c1 = () => ({ "min-width": "60rem", "table-layout": "fixed" }); const _c2 = a0 => ({ $implicit: a0 }); function PatientLibraryDetailsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", ctx_r1.error(), " "); } } function PatientLibraryDetailsComponent_For_6_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 33); } } function PatientLibraryDetailsComponent_For_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainer"](0, 32); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](1, PatientLibraryDetailsComponent_For_6_Conditional_1_Template, 1, 0, "div", 33); } if (rf & 2) { const template_r3 = ctx.$implicit; const ɵ$index_13_r4 = ctx.$index; const ɵ$count_13_r5 = ctx.$count; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const studySummaryTemplate_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](30); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ngTemplateOutlet", studySummaryTemplate_r6)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](3, _c2, template_r3)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](!(ɵ$index_13_r4 === ɵ$count_13_r5 - 1) ? 1 : -1); } } function PatientLibraryDetailsComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](0, "div", 13); } } function PatientLibraryDetailsComponent_ng_template_29_For_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "span", 39); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const title_r8 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](2, 1, title_r8)); } } function PatientLibraryDetailsComponent_ng_template_29_For_12_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "span", 39); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { const value_r9 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](value_r9); } } function PatientLibraryDetailsComponent_ng_template_29_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 34); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](1, "lib-icon", 35); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](2, "div")(3, "div")(4, "h3", 36); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](6, "div", 37)(7, "div", 38); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](8, PatientLibraryDetailsComponent_ng_template_29_For_9_Template, 3, 3, "span", 39, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIndex"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](10, "div", 40); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](11, PatientLibraryDetailsComponent_ng_template_29_For_12_Template, 2, 1, "span", 39, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIndex"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()()(); } if (rf & 2) { const data_r10 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("icon", data_r10.icon); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", data_r10.mainTitle, " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](data_r10.content.titles); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](data_r10.content.values); } } function PatientLibraryDetailsComponent_ng_template_33_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "tr")(1, "th", 41); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](2, "p-tableHeaderCheckbox"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](3, "th", 42)(4, "span", 43)(5, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](8, "p-sortIcon", 45); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](9, "th", 46)(10, "span", 43)(11, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](13, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](14, "p-sortIcon", 47); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](15, "th", 48)(16, "span", 43)(17, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](18); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](19, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](20, "p-sortIcon", 49); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](21, "th", 50)(22, "span", 43)(23, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](25, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](26, "p-sortIcon", 51); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](27, "th", 52)(28, "span", 53)(29, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](30); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](31, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](32, "p-sortIcon", 54); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](33, "th", 55)(34, "span", 53)(35, "span", 44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](36); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](37, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](38, "p-sortIcon", 56); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](39, "th", 57); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](40, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](41, "lib-icon", 58); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](42, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](43, "th", 59); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](44); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](45, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](7, 9, "patientDetails.table.modality")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](13, 11, "patientDetails.table.seriesNumber")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](19, 13, "patientDetails.table.description")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](25, 15, "patientDetails.table.seriesDate")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](31, 17, "patientDetails.table.images")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](37, 19, "patientDetails.table.approvalStatus")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](40, 21, "patientDetails.table.localCache")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](42, 23, "patientDetails.table.localCache")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](45, 25, "patientDetails.table.actions"), " "); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 73); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const total_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate2"](" ", total_r14 - series_r12.cache.cachedCount, "/", total_r14, " "); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 74); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](1, "p-progressBar", 75); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](2, "span", 76); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](4, "span", 77); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](5, "/"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](6, "span", 78); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const total_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("showValue", false)("value", total_r14 ? (total_r14 - series_r12.cache.cachedCount) / total_r14 * 100 : 0)("color", "var(--p-app-status-danger)"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](total_r14 - series_r12.cache.cachedCount); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](total_r14); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](1, PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Conditional_1_Template, 2, 2, "div", 73)(2, PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Conditional_2_Template, 8, 5, "div", 74); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const isOt_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](26); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"](ctx_r1.deletingSeriesTotalFiles()[series_r12.seriesInstanceUID] ?? series_r12.cache.totalCount); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](isOt_r15 ? 1 : 2); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_28_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 65)(1, "span", 79); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](3, "lib-icon", 80); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](2, 2, "patientDetails.cachedLocally")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](4, 4, "patientDetails.cachedLocally")); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_29_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 66); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](1, "p-progressBar", 81); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](2, "span", 76); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](4, "span", 77); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](5, "/"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](6, "span", 78); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("showValue", false)("value", series_r12.cache.percent); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", series_r12.cache.cachedCount, " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", series_r12.cache.totalCount, " "); } } function PatientLibraryDetailsComponent_ng_template_34_Conditional_30_Template(rf, ctx) { if (rf & 1) { const _r16 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 65)(1, "span", 82); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](3, "p-button", 83); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_ng_template_34_Conditional_30_Template_p_button_click_3_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.onDownloadSeries(series_r12)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](5, "lib-icon", 84); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r1.canAttempt(series_r12) ? _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](2, 3, "patientDetails.cacheLocally") : ctx_r1.getValidationTooltip(series_r12)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ariaLabel", ctx_r1.canAttempt(series_r12) ? _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](4, 5, "patientDetails.cacheLocally") : ctx_r1.getValidationTooltip(series_r12))("disabled", !ctx_r1.canAttempt(series_r12) || !series_r12.seriesInstanceUID || ctx_r1.downloadState()[series_r12.seriesInstanceUID] || ctx_r1.deleteState()[series_r12.seriesInstanceUID]); } } function PatientLibraryDetailsComponent_ng_template_34_Template(rf, ctx) { if (rf & 1) { const _r11 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](1, "tr", 60); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_ng_template_34_Template_tr_click_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.onRowClick(series_r12, $event)); })("dblclick", function PatientLibraryDetailsComponent_ng_template_34_Template_tr_dblclick_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.onRowDoubleClick(series_r12, $event)); })("contextmenu", function PatientLibraryDetailsComponent_ng_template_34_Template_tr_contextmenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const seriesMenuContext_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](41); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.seriesMenu.openAtPointer(seriesMenuContext_r13, $event, series_r12)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](2, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](3, "p-tableCheckbox", 61); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](4, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](6, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](7, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](9, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](10, "td", 62, 4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](13, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](14, "td", 62, 5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](16, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](18, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](19, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](20, "td", 63); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](22, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](23, "td", 63); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](24, "lib-review-status-icon", 64); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](25, "td", 63); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdeclareLet"](26); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](27, PatientLibraryDetailsComponent_ng_template_34_Conditional_27_Template, 3, 2)(28, PatientLibraryDetailsComponent_ng_template_34_Conditional_28_Template, 5, 6, "div", 65)(29, PatientLibraryDetailsComponent_ng_template_34_Conditional_29_Template, 8, 4, "div", 66)(30, PatientLibraryDetailsComponent_ng_template_34_Conditional_30_Template, 6, 7, "div", 65); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](31, "td")(32, "div", 67)(33, "span", 68)(34, "p-button", 69); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](35, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_ng_template_34_Template_p_button_click_34_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.openInVolumeViewer(series_r12, $event.currentTarget)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](36, "lib-icon", 70); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](37, "p-button", 71); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](38, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_ng_template_34_Template_p_button_click_37_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const series_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const seriesMenuPopup_r17 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](37); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r1.seriesMenu.openFromButton(seriesMenuPopup_r17, $event, series_r12)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](39, "lib-icon", 72); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); } if (rf & 2) { const rawSeries_r18 = ctx.$implicit; const descriptionTip_r19 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](11); const seriesDateTip_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](15); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); const series_r21 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"](ctx_r1.asSeries(rawSeries_r18)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵclassProp"]("p-datatable-row-selected", ctx_r1.isSelected(series_r21)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pSelectableRow", series_r21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵattribute"]("data-series-uid", series_r21.seriesInstanceUID); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("value", series_r21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](6, 20, series_r21.modality)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](9, 22, series_r21.seriesNumber)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", descriptionTip_r19.truncated() ? series_r21.seriesDescription ?? undefined : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](13, 24, series_r21.seriesDescription), " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", seriesDateTip_r20.truncated() ? _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind3"](16, 26, series_r21.seriesDate, !!series_r21.seriesTime, series_r21.seriesTime) : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](19, 34, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind3"](18, 30, series_r21.seriesDate, !!series_r21.seriesTime, series_r21.seriesTime)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](22, 36, series_r21.totalInstanceCount)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("status", series_r21.reviewStatus); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵstoreLet"]((series_r21.modality == null ? null : series_r21.modality.toUpperCase()) === "OT"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r1.deleteState()[series_r21.seriesInstanceUID] ? 27 : series_r21.cache.percent === 100 ? 28 : series_r21.cache.totalCount > 0 && (series_r21.cache.cachedCount > 0 || ctx_r1.downloadState()[series_r21.seriesInstanceUID]) ? 29 : 30); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("pTooltip", ctx_r1.getValidationTooltip(series_r21))("tooltipDisabled", ctx_r1.canAttempt(series_r21)); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("disabled", !ctx_r1.canAttempt(series_r21) || !series_r21.seriesInstanceUID || !!ctx_r1.downloadState()[series_r21.seriesInstanceUID] || !!ctx_r1.deleteState()[series_r21.seriesInstanceUID] || ctx_r1.isOpening())("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](35, 39, "patientDetails.menu.view")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](38, 41, "patientDetails.table.actions")); } } function PatientLibraryDetailsComponent_ng_template_35_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 1, "patientDetails.loading"), " "); } } function PatientLibraryDetailsComponent_ng_template_35_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](1, 1, "patientDetails.noSeries"), " "); } } function PatientLibraryDetailsComponent_ng_template_35_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "tr")(1, "td", 85); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](2, PatientLibraryDetailsComponent_ng_template_35_Conditional_2_Template, 2, 3)(3, PatientLibraryDetailsComponent_ng_template_35_Conditional_3_Template, 2, 3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx_r1.loading() ? 2 : 3); } } const VIEWER_ROUTE = '/volume-viewer'; function readMetaTag(meta, tag) { return String(meta?.[tag]?.Value?.[0] ?? '').trim(); } /** Read a DICOM PN value, which may be a plain string or a `{ Alphabetic }` object. */ function readPersonName(value) { if (typeof value === 'string') return value.trim(); return ''; } class PatientLibraryDetailsComponent { router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_8__.Router); vm = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_patient_library_details_facade__WEBPACK_IMPORTED_MODULE_29__.PatientLibraryDetailsFacade); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_9__.TranslateService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_10__.MessageService); dialogRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_13__.DynamicDialogRef, { optional: true }); phaseSelectionDialog = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_phase_selection_dialog_phase_selection_dialog_service__WEBPACK_IMPORTED_MODULE_25__.PhaseSelectionDialogService); database = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.DicomDatabaseService); datePipe = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_1__.DatePipe); seriesSort = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_series_sort_store__WEBPACK_IMPORTED_MODULE_32__.SeriesSortStore); listFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_30__.PatientLibraryListFacade); destroyRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef); dicomPersonNamePipe = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.DicomPersonNamePipe); dicomDatePipe = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.DicomDatePipe); host = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_4__.ElementRef); studyUid = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "studyUid" }] : [])); storeUid = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "storeUid" }] : [])); cacheAllOnOpen = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, ...(ngDevMode ? [{ debugName: "cacheAllOnOpen" }] : [])); // The study-level instance total from the study list's already-fetched row, when this store's // vendor provides one. Forwarded into the facade (see setContext below), which prefers it over // peekStudyInstanceCount - both the preference and the resulting instanceCount live there, in // summary(), so this component doesn't need to duplicate that logic. numberOfInstancesHint = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(undefined, ...(ngDevMode ? [{ debugName: "numberOfInstancesHint" }] : [])); viewMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)('list', ...(ngDevMode ? [{ debugName: "viewMode" }] : [])); back = new _angular_core__WEBPACK_IMPORTED_MODULE_3__.EventEmitter(); loading = this.vm.loading; error = this.vm.error; seriesList = this.vm.seriesList; hasAnnotatedSeries = this.vm.hasAnnotatedSeries; deleteState = this.vm.deleteState; downloadState = this.vm.downloadState; loadSeries = (force = false) => this.vm.loadSeries(force); deleteSeries = seriesUid => this.vm.deleteSeries(seriesUid); summary = this.vm.summary; sortField = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.seriesSort.sortSpec()?.field, ...(ngDevMode ? [{ debugName: "sortField" }] : [])); sortOrder = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.seriesSort.sortSpec()?.direction ?? _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.PRIMENG_DEFAULT_SORT_ORDER, ...(ngDevMode ? [{ debugName: "sortOrder" }] : [])); instancePicker; statusFilter = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(undefined, ...(ngDevMode ? [{ debugName: "statusFilter" }] : [])); langChange = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_6__.toSignal)(this.translate.onLangChange); statusFilterOptions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { this.langChange(); return ['approved', 'rejected', 'unapproved'].map(value => ({ label: this.translate.instant(`reviewStatus.${value}`), value })); }, ...(ngDevMode ? [{ debugName: "statusFilterOptions" }] : [])); displayedSeries = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const status = this.statusFilter(); const list = this.seriesList(); // Copy so PrimeNG's in-place column sort doesn't mutate the facade's signal array. return status ? list.filter(series => series.reviewStatus === status) : [...list]; }, ...(ngDevMode ? [{ debugName: "displayedSeries" }] : [])); studySummary = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(undefined, ...(ngDevMode ? [{ debugName: "studySummary" }] : [])); seriesMenu = new _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.RowMenuController((series, anchor) => this.buildSeriesMenuItems(series, anchor)); activeInstanceItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "activeInstanceItems" }] : [])); deletingSeriesTotalFiles = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)({}, ...(ngDevMode ? [{ debugName: "deletingSeriesTotalFiles" }] : [])); // Phase/instance-picker resolution before navigation can take a noticeable moment - this // blocks re-entry into openInVolumeViewer for that whole span so a slow click doesn't get // mistaken for a missed one and re-triggered. isOpening = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isOpening" }] : [])); selectedSeries = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "selectedSeries" }] : [])); anchorSeriesUid; cacheAllRequestedUids = new Set(); _studySummaryRequestId = 0; // p-table's own internal row-rendering *ngFor runs over [value] directly, using [rowTrackBy] - // which defaults to raw object identity. seriesList() hands it a brand-new object for the row // being cached on every progress tick, so without this, Angular's default trackBy sees "a // different row" on every tick and destroys+recreates that row's entire embedded view, // checkbox included - a fresh p-tableCheckbox starts unchecked until its own ngOnInit reruns, // which is the actual checked-state flip (TVC bug: "Entry-selecting checkbox flickers while // application pre-caches image data"), not just a repaint. trackBySeriesUid = (_index, item) => item.seriesInstanceUID ?? item; // Narrows seriesList()[0] down to just the fields the summary effect below actually cares // about, with an equality check over them - seriesList() gets a new array (and new item // objects) every time any series' peeked totalInstanceCount arrives, which happens once per // series as the table's counts fill in. Without this, the summary effect below re-read that // unrelated churn as "the first series changed", re-running its network peek and clobbering // the already-resolved patientBirthDate/studyTime with the synchronous fallback on every // single instance-count update - the heading flashing back to '-' and re-filling repeatedly. firstSeriesSummarySource = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const first = this.seriesList()[0]; if (!first?.seriesInstanceUID) return; return { patientID: first.patientID, patientName: first.patientName, seriesInstanceUID: first.seriesInstanceUID, studyDate: first.studyDate, studyDescription: first.studyDescription }; }, { ...(ngDevMode ? { debugName: "firstSeriesSummarySource" } : {}), equal: (a, b) => a?.seriesInstanceUID === b?.seriesInstanceUID && a?.patientID === b?.patientID && a?.patientName === b?.patientName && a?.studyDate === b?.studyDate && a?.studyDescription === b?.studyDescription }); constructor() { this.listFacade.detailsToolbar.set({ loading: this.loading, reload: () => this.loadSeries(true) }); this.destroyRef.onDestroy(() => this.listFacade.detailsToolbar.set(undefined)); // Native OS busy cursor for the open-scan span: opening can take a moment before the // volume viewer's own progress bar takes over, and the button being disabled isn't visible // if the mouse isn't over it. Toggled on
(not scoped to this component's DOM) with // `!important` on every descendant so it overrides elements that set their own cursor // (buttons, links). Cleared on destroy - this component is torn down when navigation to the // viewer completes, which is exactly the point its own loading state should take over. (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { document.body.classList.toggle('app-cursor-wait', this.isOpening()); }); this.destroyRef.onDestroy(() => document.body.classList.remove('app-cursor-wait')); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.vm.setContext(this.studyUid(), this.storeUid(), this.numberOfInstancesHint()); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { const first = this.firstSeriesSummarySource(); const requestId = ++this._studySummaryRequestId; if (!first?.seriesInstanceUID) { // No series (yet, or this study genuinely has none) - clear rather than leave a // previous study's summary on screen. this.studySummary.set(undefined); return; } const studyUid = this.studyUid(); const storeUid = this.storeUid(); // Immediate fallback from fields the series-list item already carries, so the heading // doesn't show '-' for data that was never actually behind the peek below. this.studySummary.set({ patientBirthDate: undefined, patientID: first.patientID ?? undefined, patientName: first.patientName ?? undefined, studyDate: first.studyDate ?? undefined, studyDescription: first.studyDescription ?? undefined, studyTime: undefined }); // Fills in the richer fields (patientBirthDate, studyTime) the series-list item doesn't // carry. peekSeriesCommonMetadata prefers whatever's already cached locally, and only // reaches the network on a cold cache - without ever persisting the response, so peeking // at this info for the heading can't grow local storage or resurrect an evicted series' // metadata rows. this.database.peekSeriesCommonMetadata(studyUid, first.seriesInstanceUID, storeUid).then(meta => { if (requestId !== this._studySummaryRequestId) return; this.studySummary.set({ patientBirthDate: meta?.patientBirthDate, patientID: meta?.patientID ?? first.patientID ?? undefined, patientName: meta?.patientName ?? first.patientName ?? undefined, studyDate: meta?.studyDate ?? first.studyDate ?? undefined, studyDescription: meta?.studyDescription ?? first.studyDescription ?? undefined, studyTime: this.formatDicomTime(meta?.studyTime) }); }).catch(() => { // Non-fatal: leave the synchronous fallback set above in place rather than clearing // it - the richer fields just stay unavailable for this series. }); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { const list = this.seriesList(); const selectedUids = new Set((0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(this.selectedSeries).map(s => s.seriesInstanceUID)); if (selectedUids.size === 0) return; this.selectedSeries.set(list.filter(s => s.seriesInstanceUID && selectedUids.has(s.seriesInstanceUID))); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { if (!this.cacheAllOnOpen()) return; const list = this.seriesList(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => this.cacheSeriesOnce(list)); }); } // Renders both cards immediately with per-field '-' placeholders rather than waiting for // studySummary to fully resolve and flashing the whole heading in at once - each field fills // in on its own once the underlying peek (or richer local metadata) provides it. headingTemplate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const s = this.studySummary(); const dateOfBirth = this.dicomDatePipe.transform(s?.patientBirthDate) ?? '-'; const patientId = s?.patientID ?? '-'; const studyDate = this.dicomDatePipe.transform(s?.studyDate) ?? '-'; const studyTime = s?.studyTime ?? '-'; return [{ content: { titles: ['patientDetails.heading.dateOfBirth', 'patientDetails.heading.patientId'], values: [dateOfBirth, patientId] }, icon: 'user', mainTitle: this.dicomPersonNamePipe.transform(s?.patientName) ?? '-' }, { content: { titles: ['patientDetails.heading.studyDate', 'patientDetails.heading.studyTime'], values: [studyDate, studyTime] }, icon: 'folder', mainTitle: s?.studyDescription ?? '-' }]; }, ...(ngDevMode ? [{ debugName: "headingTemplate" }] : [])); formatDicomDate(raw) { const d = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.parseDicomDate)(raw); return d ? this.datePipe.transform(d, 'MMM d, y') ?? raw : raw; } formatDicomTime(raw) { if (!raw || raw.length < 6) return raw; return `${raw.slice(0, 2)}:${raw.slice(2, 4)}:${raw.slice(4, 6)}`; } openInVolumeViewer(series, anchor) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this.isOpening()) return; const seriesUid = series.seriesInstanceUID; if (!seriesUid || !_this.canAttempt(series) || _this.downloadState()[seriesUid] || _this.deleteState()[seriesUid]) { return; } const isOt = _this.isOtModality(series); _this.isOpening.set(true); try { if (isOt) { yield _this.openOtSeriesInViewer(series, seriesUid, anchor); return; } const selectedPhaseIds = yield _this.phaseSelectionDialog.selectForSeries(_this.studyUid(), seriesUid, _this.storeUid()); if (selectedPhaseIds === undefined) return; _this.vm.downloadSeries(seriesUid); _this.dialogRef?.close(); yield _this.router.navigate([VIEWER_ROUTE, _this.storeUid(), _this.studyUid(), seriesUid, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.WORK_SESSION_NEW_KEY], { queryParams: { ...(selectedPhaseIds.length > 0 ? { phases: selectedPhaseIds.join(',') } : {}) } }); } finally { _this.isOpening.set(false); } })(); } openOtSeriesInViewer(series, seriesUid, anchor) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (anchor && (yield _this2.tryShowInstancePicker(series, seriesUid, anchor))) return; const { otSeriesUid, targetSeriesUid } = yield _this2.resolveViewerTarget(series, seriesUid); if (otSeriesUid) { _this2.vm.downloadSeries(targetSeriesUid); } _this2.dialogRef?.close(); yield _this2.router.navigate([VIEWER_ROUTE, _this2.storeUid(), _this2.studyUid(), targetSeriesUid, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.WORK_SESSION_NEW_KEY], { queryParams: { ...(otSeriesUid ? { otSeriesUid } : {}) } }); })(); } tryShowInstancePicker(series, seriesUid, anchor) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const studyUid = _this3.studyUid(); if (!studyUid) return false; const instances = yield _this3.database.getSeriesInstancesMetadata(studyUid, seriesUid, _this3.storeUid()); if (instances.length <= 1) return false; _this3.activeInstanceItems.set(instances.map((inst, index) => _this3.buildInstanceItem(series, inst, index, !!inst.getAttachment('pixelData')))); _this3.instancePicker?.toggleAt(anchor); return true; })(); } openOtInstance(series, inst) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this4.isOpening()) return; _this4.isOpening.set(true); try { const seriesUid = series.seriesInstanceUID ?? ''; // Same definitive check as resolveWorkSessionInstance - a "referenced series" tag alone // isn't proof this specific instance is a genuine Tomoverse work session. const meta = inst.toJSON().metadata; if (!meta) return; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_21__.isTvctWorkSessionInstance)(meta)) { _this4.vm.error.set(_this4.translate.instant('patientDetails.instancePicker.notWorkSession')); return; } const sourceSeriesUid = yield _this4.resolveSourceFromInstance(inst); if (!sourceSeriesUid) return; _this4.vm.downloadSeries(sourceSeriesUid); _this4.dialogRef?.close(); yield _this4.router.navigate([VIEWER_ROUTE, _this4.storeUid(), _this4.studyUid(), sourceSeriesUid, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.WORK_SESSION_NEW_KEY], { queryParams: { otInstanceUid: inst.sopInstanceUID, otSeriesUid: seriesUid } }); } finally { _this4.isOpening.set(false); } })(); } resolveViewerTarget(series, seriesUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const notOt = { otSeriesUid: undefined, targetSeriesUid: seriesUid, workSessionName: undefined, workSessionUid: undefined }; if (!_this5.isOtModality(series)) return notOt; const studyUid = _this5.studyUid(); if (!studyUid) return notOt; const workSession = yield _this5.resolveWorkSessionInstance(studyUid, seriesUid); if (!workSession) return notOt; const sourceSeriesUid = yield _this5.resolveSourceFromInstance(workSession.firstInstance); if (!sourceSeriesUid) return notOt; const workSessionUid = readMetaTag(workSession.meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.TvctWorkSessionUid) || undefined; const workSessionName = readMetaTag(workSession.meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.SeriesDescription) || undefined; return { otSeriesUid: seriesUid, targetSeriesUid: sourceSeriesUid, workSessionName, workSessionUid }; })(); } /** * Fetches (and caches) the series' instances, returning its first instance and metadata only * if a definitive, instance-level check confirms this is a genuine Tomoverse work session - a * "referenced series" tag alone isn't proof, since any secondary-capture OT file could have one. */ resolveWorkSessionInstance(studyUid, seriesUid) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const instances = yield _this6.database.getSeriesInstancesMetadata(studyUid, seriesUid, _this6.storeUid()); const [firstInstance] = instances; if (!firstInstance) return undefined; const meta = firstInstance.toJSON().metadata; if (!meta || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_21__.isTvctWorkSessionInstance)(meta)) return undefined; return { firstInstance, meta }; })(); } resolveSourceFromInstance(inst) { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const meta = inst.toJSON().metadata; let sourceSeriesUid = String(meta?.[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.ReferencedSeriesSequence]?.Value?.[0]?.[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.SeriesInstanceUID]?.Value?.[0] ?? '').trim(); if (!sourceSeriesUid) { try { const binary = yield _this7.database.getBinary(inst.sopInstanceUID, _this7.storeUid()); sourceSeriesUid = (0,_services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_26__.extractAnnotationTags)(binary)?.sourceSeriesUid ?? ''; } catch { // binary unavailable — fall through } } if (!sourceSeriesUid) return ''; const studyUid = _this7.studyUid(); if (!studyUid || !(yield _this7.seriesExistsInStore(studyUid, sourceSeriesUid))) { _this7.messageService.add({ life: 4000, severity: 'warn', summary: _this7.translate.instant('patientDetails.sourceSeriesMissing') }); return ''; } return sourceSeriesUid; })(); } // An OT file's embedded/tagged source series reference can point at a series the store no // longer has (e.g. the original CT was never uploaded to this store, or was deleted) - without // this check, navigating ahead anyway only surfaces a raw 404 once the viewer tries to load it. seriesExistsInStore(studyUid, seriesUid) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const instances = yield _this8.database.getSeriesInstancesMetadata(studyUid, seriesUid, _this8.storeUid()); return instances.length > 0; } catch { return false; } })(); } buildInstanceItem(series, inst, index, isLocal) { const meta = inst.toJSON().metadata; const rawDate = readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.InstanceCreationDate); const rawTime = readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.InstanceCreationTime); const annotator = readPersonName(meta?.[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.TvctAuthorName]?.Value?.[0]); const phaseLabel = readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.TvctPhaseLabel) || undefined; // Private mirror fallback in case the store dropped the non-indexed standard tag. const approvalStatus = readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.ApprovalStatus) || readMetaTag(meta, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_22__.DicomTagId.TvctReviewStatus); return { annotator: annotator || '—', date: (this.formatDicomDate(rawDate) ?? rawDate) || '—', index: index + 1, isLocal, open: () => { this.openOtInstance(series, inst); }, phaseLabel, reviewStatus: (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.approvalToReviewStatus)(approvalStatus), time: rawTime ? this.formatDicomTime(rawTime) ?? rawTime : '—' }; } onRowDoubleClick(series, event) { this.openInVolumeViewer(series, event.currentTarget); } // A plain click must leave selection alone, which rules out pSelectableRow: its plain-click // branch always selects, even under metaKeySelection. onRowClick(series, event) { // The checkbox and action buttons answer their own clicks; without this a ctrl-click on the // checkbox toggles twice. if (event.target.closest('p-tablecheckbox, .p-checkbox, button, a')) return; const seriesUid = series.seriesInstanceUID; if (event.shiftKey && this.anchorSeriesUid) { this.selectRangeTo(seriesUid); return; } if (!event.ctrlKey && !event.metaKey) return; this.anchorSeriesUid = seriesUid; this.selectedSeries.update(selected => selected.some(s => s.seriesInstanceUID === seriesUid) ? selected.filter(s => s.seriesInstanceUID !== seriesUid) : [...selected, series]); } // Row order comes from the DOM because sorting reorders the screen, not seriesList(). selectRangeTo(seriesUid) { const anchor = this.anchorSeriesUid; if (!seriesUid || !anchor) return; const order = [...this.host.nativeElement.querySelectorAll('[data-series-uid]')].map(row => row.dataset['seriesUid']).filter(uid => !!uid); const from = order.indexOf(anchor); const to = order.indexOf(seriesUid); if (from === -1 || to === -1) return; const inRange = new Set(order.slice(Math.min(from, to), Math.max(from, to) + 1)); this.selectedSeries.set(this.seriesList().filter(s => s.seriesInstanceUID && inRange.has(s.seriesInstanceUID))); } clearSelection() { this.selectedSeries.set([]); // Without this a later shift-click would extend from the cleared selection's anchor. this.anchorSeriesUid = undefined; } isSelected(series) { return this.selectedSeries().some(s => s.seriesInstanceUID === series.seriesInstanceUID); } onSort(event) { const field = event.field; this.seriesSort.setSort(field ? { direction: event.order ?? 1, field } : undefined); } canOpen(series) { const seriesUid = series.seriesInstanceUID; return Boolean(seriesUid && this.isSupported(series) && !this.downloadState()[seriesUid] && !this.deleteState()[seriesUid]); } canCache(series) { return this.canOpen(series) && !(0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.isSeriesFullyCached)(series.cache); } canDelete(series) { const seriesUid = series.seriesInstanceUID; return Boolean(seriesUid && (series.cache.totalCount > 0 || series.cache.cachedCount > 0) && !this.downloadState()[seriesUid] && !this.deleteState()[seriesUid]); } cacheableSelected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.selectedSeries().filter(s => s.seriesInstanceUID && !(0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.isSeriesFullyCached)(s.cache) && this.canAttempt(s) && !this.downloadState()[s.seriesInstanceUID] && !this.deleteState()[s.seriesInstanceUID]), ...(ngDevMode ? [{ debugName: "cacheableSelected" }] : [])); deletableSelected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => this.selectedSeries().filter(s => this.canDelete(s)), ...(ngDevMode ? [{ debugName: "deletableSelected" }] : [])); viewBlockedReason = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const selected = this.selectedSeries(); if (selected.length > 1) { return this.translate.instant('patientDetails.bulkActions.viewOneOnly'); } const [series] = selected; if (!series || this.canOpen(series) || this.isOtModality(series)) return ''; return this.getValidationTooltip(series); }, ...(ngDevMode ? [{ debugName: "viewBlockedReason" }] : [])); onBulkView() { if (this.viewBlockedReason()) return; const [series] = this.selectedSeries(); if (series) this.openInVolumeViewer(series); } onBulkDownload() { const uids = this.cacheableSelected().map(s => s.seriesInstanceUID).filter(uid => !!uid); if (uids.length === 0) return; this.vm.downloadSeriesBatch(uids, uids.length === 1 ? undefined : this.translate.instant('patientDetails.caching.selectedSeries', { count: uids.length })); this.clearSelection(); } cacheSeriesOnce(list) { const uids = []; for (const s of list) { const seriesUid = s.seriesInstanceUID; if (!seriesUid || this.cacheAllRequestedUids.has(seriesUid) || !this.canCache(s)) continue; this.cacheAllRequestedUids.add(seriesUid); uids.push(seriesUid); } if (uids.length === 0) return; this.vm.downloadSeriesBatch(uids, uids.length === 1 ? undefined : this.translate.instant('patientDetails.caching.selectedSeries', { count: uids.length })); } bulkMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_5__.computed)(() => { const blocked = this.viewBlockedReason(); return [{ command: () => this.onBulkView(), disabled: !!blocked, icon: 'pi pi-eye', label: blocked || this.translate.instant('patientDetails.bulkActions.view') }, { separator: true }, { command: () => this.onBulkDownload(), disabled: this.cacheableSelected().length === 0, icon: 'pi pi-cloud-download', label: this.translate.instant('patientDetails.menu.cache') }, { separator: true }, { command: () => this.selectedSeries.set([...this.seriesList()]), disabled: this.selectedSeries().length === this.seriesList().length, icon: 'pi pi-check-square', label: this.translate.instant('patientDetails.menu.selectAll') }, { command: () => this.clearSelection(), disabled: this.selectedSeries().length === 0, icon: 'pi pi-stop', label: this.translate.instant('patientDetails.menu.deselectAll') }, { separator: true }, (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.dangerMenuItem)({ command: () => this.onBulkDeleteLocalStorage(), disabled: this.deletableSelected().length === 0, icon: 'pi pi-ban', label: this.translate.instant('patientDetails.menu.delete') })]; }, ...(ngDevMode ? [{ debugName: "bulkMenuItems" }] : [])); onBulkDeleteLocalStorage() { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // Sequential, not fired concurrently: deleteSeriesCache races against itself across series // when run in parallel (each removes its own instance documents from the same RxDB // collection), which was silently dropping every deletion after the first. for (const s of _this9.deletableSelected()) { yield _this9.deleteSeriesWithProgress(s); } })(); } /** deleteSeriesCache removes each instance document outright rather than just clearing its * attachment, so the live `series.cache.totalCount` this row is bound to shrinks along with * `cachedCount` as the delete progresses - showing a stuck "0/N" ticking down to "0/0" * instead of "N/N" ticking down to "0/N". Snapshotting the starting total here (read via * `deletingSeriesTotalFiles` in the template) keeps the denominator fixed for the duration. */ deleteSeriesWithProgress(series) { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const seriesUid = series.seriesInstanceUID; if (!seriesUid) return; _this0.deletingSeriesTotalFiles.update(state => ({ ...state, [seriesUid]: series.cache.totalCount })); try { yield _this0.deleteSeries(seriesUid); } finally { _this0.deletingSeriesTotalFiles.update(state => { const next = { ...state }; delete next[seriesUid]; return next; }); } })(); } onBack() { this.back.emit(); } onDownloadSeries(series) { const seriesUid = series.seriesInstanceUID; if (!seriesUid || !this.canAttempt(series)) { return; } this.vm.downloadSeries(seriesUid); } buildSeriesMenuItems(series, anchor) { return [{ command: () => this.openInVolumeViewer(series, anchor), disabled: !this.canOpen(series), icon: 'pi pi-box', label: this.translate.instant('patientDetails.menu.view') }, { separator: true }, { command: () => this.onDownloadSeries(series), disabled: !this.canCache(series), icon: 'pi pi-cloud-download', label: this.translate.instant('patientDetails.menu.cache') }, { separator: true }, { command: () => this.selectedSeries.set([...this.seriesList()]), disabled: this.selectedSeries().length === this.seriesList().length, icon: 'pi pi-check-square', label: this.translate.instant('patientDetails.menu.selectAll') }, { command: () => this.clearSelection(), disabled: this.selectedSeries().length === 0, icon: 'pi pi-stop', label: this.translate.instant('patientDetails.menu.deselectAll') }, { separator: true }, (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.dangerMenuItem)({ command: () => this.deleteSeriesWithProgress(series), disabled: !this.canDelete(series), icon: 'pi pi-ban', label: this.translate.instant('patientDetails.menu.delete') }), (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.dangerMenuItem)({ disabled: true, icon: 'pi pi-trash', label: this.translate.instant('patientDetails.menu.deleteFromStore') })]; } asSeries(value) { return value; } isSupported(series) { return this.getValidationErrors(series).length === 0; } /** * Whether an action (open/download) should be attempted at all. isSupported() reflects * validationErrors computed from whatever's already cached locally, which is empty - and * therefore wrongly flags a modality mismatch - for any OT series never fetched before. OT * series defer their real validity check to the on-demand fetch (resolveWorkSessionInstance), * so they're always attemptable here regardless of that possibly-stale snapshot. */ canAttempt(series) { return this.isSupported(series) || this.isOtModality(series); } isOtModality(series) { return String(series.modality ?? '').trim().toUpperCase() === 'OT'; } getValidationTooltip(series) { return this.getValidationErrors(series).join('\n'); } setViewMode(mode) { this.viewMode.set(mode); } getValidationErrors(series) { return series.validationErrors ?? []; } static ɵfac = function PatientLibraryDetailsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PatientLibraryDetailsComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵdefineComponent"]({ type: PatientLibraryDetailsComponent, selectors: [["lib-patient-library-details"]], viewQuery: function PatientLibraryDetailsComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵviewQuery"](_instance_picker_component__WEBPACK_IMPORTED_MODULE_28__.InstancePickerComponent, 5); } if (rf & 2) { let _t; _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵqueryRefresh"](_t = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵloadQuery"]()) && (ctx.instancePicker = _t.first); } }, hostAttrs: [1, "block", "h-full"], inputs: { studyUid: [1, "studyUid"], storeUid: [1, "storeUid"], cacheAllOnOpen: [1, "cacheAllOnOpen"], numberOfInstancesHint: [1, "numberOfInstancesHint"] }, outputs: { back: "back" }, features: [_angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵProvidersFeature"]([_angular_common__WEBPACK_IMPORTED_MODULE_1__.DatePipe, _patient_library_details_facade__WEBPACK_IMPORTED_MODULE_29__.PatientLibraryDetailsFacade, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.DicomPersonNamePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.DicomDatePipe])], decls: 43, vars: 40, consts: [["studySummaryTemplate", ""], ["seriesMenuPopup", ""], ["bulkMenu", ""], ["seriesMenuContext", ""], ["descriptionTip", "libEllipsisTip"], ["seriesDateTip", "libEllipsisTip"], [1, "flex", "h-full", "min-h-0", "flex-col"], [1, "border-destructive/30", "bg-destructive/10", "text-destructive", "mx-4", "mb-4", "shrink-0", "rounded-md", "border", "px-3", "py-2"], [1, "mx-4", 3, "back", "backAriaLabel"], ["left", ""], ["right", ""], [1, "flex", "items-center", "gap-4"], [3, "view", "cache", "clear", "more", "selectedCount", "cacheableCount", "viewBlockedReason"], [1, "h-8", "w-px", "bg-(--p-app-surface-tab)"], ["data-test-id", "patient-library-p-select-status-filter", "optionLabel", "label", "optionValue", "value", "size", "small", "appendTo", "body", 1, "overflow-hidden", 3, "ngModelChange", "options", "ngModel", "showClear", "placeholder"], ["data-test-id", "patient-library-div-series-summary", 1, "text-muted-color", "mb-2", "flex", "shrink-0", "items-center", "gap-2", "pt-2", "text-sm"], [1, "hidden", "h-8", "w-px", "bg-(--p-app-surface-tab)"], [1, "hidden"], [1, "flex", "gap-1", "rounded-md", "bg-(--p-app-neutral-950)", "p-1"], ["data-test-id", "patient-library-p-button-view-list", "severity", "secondary", "size", "large", "variant", "text", 3, "click", "severity"], ["icon", "list"], ["data-test-id", "patient-library-p-button-view-grid", "severity", "secondary", "size", "large", "variant", "text", 3, "click", "severity"], ["icon", "th-large"], [1, "min-h-0", "flex-1"], ["dataKey", "seriesInstanceUID", "scrollable", "", "scrollHeight", "flex", "selectionMode", "multiple", 1, "library-table", 3, "selectionChange", "onSort", "value", "loading", "rowTrackBy", "tableStyle", "selection", "sortField", "sortOrder"], ["pTemplate", "header"], ["pTemplate", "body"], ["pTemplate", "emptymessage"], ["data-test-id", "patient-library-p-menu-series", "popup", "", "appendTo", "body", 3, "model"], ["data-test-id", "patient-library-p-menu-bulk", "popup", "", "appendTo", "body", 3, "model"], ["data-test-id", "patient-library-p-contextmenu-series", "appendTo", "body", 3, "model"], [3, "items"], [3, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "mr-2", "ml-2", "h-12", "w-px", "bg-(--p-app-surface-tab)"], [1, "flex", "items-center", "gap-3"], [1, "flex", "size-10", "items-center", "justify-center", "rounded-full", "bg-(--p-app-neutral-800)", "[&_svg]:size-5", 3, "icon"], [1, "text-color", "pb-1", "text-base", "font-semibold"], [1, "flex", "gap-3"], [1, "text-muted-color", "flex", "flex-col", "text-xs"], [1, "pb-0.5"], [1, "flex", "flex-col", "text-xs", "text-(--p-app-neutral-300)"], [1, "w-[4.125rem]"], ["pSortableColumn", "modality", 1, "w-[6.875rem]", "overflow-hidden"], [1, "flex", "min-w-0", "items-center", "gap-1"], [1, "truncate"], ["field", "modality"], ["pSortableColumn", "seriesNumber", 1, "w-[9.6875rem]", "overflow-hidden"], ["field", "seriesNumber"], ["pSortableColumn", "seriesDescription", 1, "overflow-hidden"], ["field", "seriesDescription"], ["pSortableColumn", "seriesDate", 1, "w-[11.5625rem]", "overflow-hidden"], ["field", "seriesDate"], ["pSortableColumn", "totalInstanceCount", 1, "w-[6.25rem]", "overflow-hidden", "text-center"], [1, "flex", "min-w-0", "items-center", "justify-center", "gap-1"], ["field", "totalInstanceCount"], ["pSortableColumn", "reviewStatusRank", 1, "w-[8.4375rem]", "overflow-hidden", "text-center"], ["field", "reviewStatusRank"], ["tooltipPosition", "top", 1, "w-[3.125rem]", "text-center", "whitespace-nowrap", 3, "pTooltip"], ["icon", "cloud-download", 1, "text-muted-color"], [1, "w-[8.4375rem]", "text-center", "whitespace-nowrap"], [3, "click", "dblclick", "contextmenu", "pSelectableRow"], [3, "value"], ["libEllipsisTip", "", "tooltipPosition", "top", 3, "pTooltip"], [1, "text-center"], [3, "status"], [1, "flex", "items-center", "justify-center", "gap-2"], [1, "text-muted-color", "flex", "items-center", "text-xs"], [1, "flex", "items-center", "justify-end", "gap-2"], ["tooltipPosition", "top", 1, "inline-flex", 3, "pTooltip", "tooltipDisabled"], ["data-test-id", "patient-library-p-button-open-series", "rounded", "", "text", "", "size", "small", "styleClass", "h-[30px] w-[30px] p-0", 3, "click", "disabled", "ariaLabel"], ["icon", "eye", 1, "size-(--p-app-icon-size-xs)"], ["data-test-id", "patient-library-p-button-series-menu", "severity", "secondary", "text", "", "size", "small", 3, "click", "ariaLabel"], ["icon", "ellipsis-v"], [1, "flex", "justify-center", "text-xs", "text-(--p-app-status-danger)"], [1, "flex", "items-center", "text-xs", "text-(--p-app-status-danger)"], [1, "mr-2", "h-2", "w-24", 3, "showValue", "value", "color"], [1, "w-10", "text-right"], [1, "w-2"], [1, "w-5"], ["tooltipPosition", "top", 1, "text-muted-color", "inline-flex", "cursor-default", 3, "pTooltip"], ["icon", "check-circle"], [1, "mr-2", "h-2", "w-24", 3, "showValue", "value"], ["tooltipPosition", "top", 1, "inline-flex", 3, "pTooltip"], ["data-test-id", "patient-library-p-button-download-series", "severity", "secondary", "rounded", "", "text", "", "size", "small", "styleClass", "h-[30px] w-[30px] p-0", 3, "click", "ariaLabel", "disabled"], ["icon", "cloud-download", 1, "size-(--p-app-icon-size-xs)"], ["colspan", "9", 1, "text-center"]], template: function PatientLibraryDetailsComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](0, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](1, PatientLibraryDetailsComponent_Conditional_1_Template, 2, 1, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](2, "lib-heading-area", 8); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("back", function PatientLibraryDetailsComponent_Template_lib_heading_area_back_2_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.onBack()); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainerStart"](4, 9); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterCreate"](5, PatientLibraryDetailsComponent_For_6_Template, 2, 5, null, null, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeaterTrackByIndex"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainerEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainerStart"](7, 10); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](8, "div", 11)(9, "lib-series-bulk-actions", 12); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("view", function PatientLibraryDetailsComponent_Template_lib_series_bulk_actions_view_9_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.onBulkView()); })("cache", function PatientLibraryDetailsComponent_Template_lib_series_bulk_actions_cache_9_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.onBulkDownload()); })("clear", function PatientLibraryDetailsComponent_Template_lib_series_bulk_actions_clear_9_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.clearSelection()); })("more", function PatientLibraryDetailsComponent_Template_lib_series_bulk_actions_more_9_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); const bulkMenu_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵreference"](39); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](bulkMenu_r7.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditionalCreate"](10, PatientLibraryDetailsComponent_Conditional_10_Template, 1, 0, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](11, "p-select", 14); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("ngModelChange", function PatientLibraryDetailsComponent_Template_p_select_ngModelChange_11_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.statusFilter.set($event ?? undefined)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](13, "div", 15)(14, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](15); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](16, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](17, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](18, "\u00B7"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](19, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtext"](20); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipe"](21, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](22, "div", 16); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](23, "div", 17)(24, "div", 18)(25, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_Template_p_button_click_25_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.setViewMode("list")); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](26, "lib-icon", 20); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](27, "p-button", 21); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("click", function PatientLibraryDetailsComponent_Template_p_button_click_27_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.setViewMode("grid")); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](28, "lib-icon", 22); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementContainerEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](29, PatientLibraryDetailsComponent_ng_template_29_Template, 13, 2, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementStart"](31, "div", 23)(32, "p-table", 24); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵlistener"]("selectionChange", function PatientLibraryDetailsComponent_Template_p_table_selectionChange_32_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.selectedSeries.set($event ?? [])); })("onSort", function PatientLibraryDetailsComponent_Template_p_table_onSort_32_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.onSort($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtemplate"](33, PatientLibraryDetailsComponent_ng_template_33_Template, 46, 27, "ng-template", 25)(34, PatientLibraryDetailsComponent_ng_template_34_Template, 40, 43, "ng-template", 26)(35, PatientLibraryDetailsComponent_ng_template_35_Template, 4, 1, "ng-template", 27); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵelement"](36, "p-menu", 28, 1)(38, "p-menu", 29, 2)(40, "p-contextmenu", 30, 3)(42, "lib-instance-picker", 31); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx.error() ? 1 : -1); const headingTemplateData_r22 = ctx.headingTemplate(); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("backAriaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](3, 25, "patientDetails.back")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵrepeater"](headingTemplateData_r22); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("selectedCount", ctx.selectedSeries().length)("cacheableCount", ctx.cacheableSelected().length)("viewBlockedReason", ctx.viewBlockedReason()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵconditional"](ctx.selectedSeries().length > 0 ? 10 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("options", ctx.statusFilterOptions())("ngModel", ctx.statusFilter())("showClear", true)("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind1"](12, 27, "reviewStatus.all")); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind2"](16, 29, "patientDetails.counts.series", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](35, _c0, ctx.summary().seriesCount)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpipeBind2"](21, 32, "patientDetails.counts.instances", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction1"](37, _c0, ctx.summary().instanceCount ?? "-")), " "); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("severity", ctx.viewMode() === "list" ? "primary" : "secondary"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("severity", ctx.viewMode() === "grid" ? "primary" : "secondary"); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("value", ctx.displayedSeries())("loading", ctx.loading())("rowTrackBy", ctx.trackBySeriesUid)("tableStyle", _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵpureFunction0"](39, _c1))("selection", ctx.selectedSeries())("sortField", ctx.sortField())("sortOrder", ctx.sortOrder()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("model", ctx.seriesMenu.items()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("model", ctx.bulkMenuItems()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("model", ctx.seriesMenu.items()); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_4__["ɵɵproperty"]("items", ctx.activeInstanceItems()); } }, dependencies: [primeng_table__WEBPACK_IMPORTED_MODULE_18__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_18__.Table, primeng_api__WEBPACK_IMPORTED_MODULE_10__.PrimeTemplate, primeng_table__WEBPACK_IMPORTED_MODULE_18__.SortableColumn, primeng_table__WEBPACK_IMPORTED_MODULE_18__.SelectableRow, primeng_table__WEBPACK_IMPORTED_MODULE_18__.SortIcon, primeng_table__WEBPACK_IMPORTED_MODULE_18__.TableCheckbox, primeng_table__WEBPACK_IMPORTED_MODULE_18__.TableHeaderCheckbox, primeng_button__WEBPACK_IMPORTED_MODULE_11__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_11__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_7__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_7__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_7__.NgModel, _instance_picker_component__WEBPACK_IMPORTED_MODULE_28__.InstancePickerComponent, _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_27__.ReviewStatusIconComponent, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_12__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_12__.ContextMenu, _series_bulk_actions_component__WEBPACK_IMPORTED_MODULE_31__.SeriesBulkActionsComponent, primeng_menu__WEBPACK_IMPORTED_MODULE_14__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_14__.Menu, primeng_progressbar__WEBPACK_IMPORTED_MODULE_15__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_15__.ProgressBar, primeng_select__WEBPACK_IMPORTED_MODULE_17__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_17__.Select, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_9__.TranslateModule, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.IconComponent, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_16__.ProgressSpinnerModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__.Tooltip, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.EllipsisTipDirective, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_23__.HeadingAreaComponent, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_9__.TranslatePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.DicomDatePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_24__.OrDashPipe], encapsulation: 2 }); } /***/ }, /***/ 21723 /*!**********************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/patient-library-details.facade.ts ***! \**********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatientLibraryDetailsFacade: () => (/* binding */ PatientLibraryDetailsFacade) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../services/dicom-annotation-codec */ 19462); /* harmony import */ var _series_cache_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./series-cache.service */ 60240); /* harmony import */ var _series_cacheability__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./series-cacheability */ 54759); const FETCH_SOURCE_DESCRIPTIONS_FAILED_LOG = '[patient-library-debug] fetchSourceDescriptions failed'; function groupSeriesByUid(seriesList) { const groupsByUid = new Map(); const groups = []; for (const series of seriesList) { const seriesUid = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.normalizeSeriesUid)(series.seriesInstanceUID); if (!seriesUid) { groups.push({ series, seriesUids: [] }); continue; } const group = groupsByUid.get(seriesUid); if (group) { addSeriesUidAliases(group.seriesUids, series.seriesInstanceUID, seriesUid); continue; } const nextGroup = { series: { ...series, seriesInstanceUID: seriesUid }, seriesUids: [] }; addSeriesUidAliases(nextGroup.seriesUids, series.seriesInstanceUID, seriesUid); groupsByUid.set(seriesUid, nextGroup); groups.push(nextGroup); } return groups; } function addSeriesUidAliases(seriesUids, rawUid, normalizedUid) { const raw = String(rawUid ?? ''); for (const uid of [normalizedUid, raw]) { if (uid && !seriesUids.includes(uid)) seriesUids.push(uid); } } class PatientLibraryDetailsFacade { database = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.DicomDatabaseService); seriesCache = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_series_cache_service__WEBPACK_IMPORTED_MODULE_12__.SeriesCacheService); studyUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "studyUid" }] : [])); storeUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "storeUid" }] : [])); // Study-level instance total the caller already knows (e.g. from a study-search row), when // available. Preferred over peekStudyInstanceCount below, which exists specifically for when // this isn't available - so the peek is skipped entirely rather than run and discarded. numberOfInstancesHint = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "numberOfInstancesHint" }] : [])); seriesList$ = (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.combineLatest)([(0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toObservable)(this.studyUid), (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toObservable)(this.storeUid)]).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_8__.switchMap)(([studyUid, storeUid]) => { if (!studyUid || !storeUid) return (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.of)([]); return this.database.streamSeriesForStudy(studyUid, storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_8__.switchMap)(seriesList => { const seriesGroups = groupSeriesByUid(seriesList); if (seriesGroups.length === 0) return (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.of)([]); const streams = seriesGroups.map(({ series, seriesUids }) => { const { modality, seriesInstanceUID: seriesUid } = series; const seriesModalityErrors = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.validateCtModality)(modality); if (!seriesUid || seriesUids.length === 0) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.of)({ ...series, cache: { cachedCount: 0, percent: 0, totalCount: 0 }, isAnnotated: false, reviewStatus: 'none', reviewStatusRank: (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.reviewStatusRank)('none'), validationErrors: seriesModalityErrors }); } this.refreshOtInstanceMetadata(modality, seriesUids, studyUid, storeUid); return (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.combineLatest)(seriesUids.map(uid => this.database.streamSeriesInstances(uid, storeUid))).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_7__.map)(documentGroups => this.buildSeriesListItem(series, documentGroups.flat()))); }); return (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.combineLatest)(streams); })); })); // True instance total across every series in the study, peeked (never cached locally) once // per study/store - see peekStudyInstanceCount. Undefined until that resolves; summary() // falls back to the series-list-derived (locally-cached-only) count until then. peekedInstanceCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "peekedInstanceCount" }] : [])); _peekRequestId = 0; // Per-series instance totals for the same study/store, keyed by seriesInstanceUID - see // peekSeriesInstanceCounts. Populates the series table's true "Images" count regardless of // what's cached locally. Unlike peekedInstanceCount above, this always runs: the study-level // hint (when present) only ever covers the study's aggregate total, never a per-series // breakdown, so there's nothing cheaper to fall back to here. peekedSeriesInstanceCounts = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(new Map(), ...(ngDevMode ? [{ debugName: "peekedSeriesInstanceCounts" }] : [])); _seriesInstanceCountsPeekRequestId = 0; constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const studyUid = this.studyUid(); if (!studyUid) return; this.loadSeries(); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const studyUid = this.studyUid(); const storeUid = this.storeUid(); this.peekedInstanceCount.set(undefined); // Invalidates any in-flight peek too (via the requestId bump below) - a hint arriving // while a peek is still pending shouldn't let that peek's result overwrite it later. if (!studyUid || !storeUid || this.numberOfInstancesHint() !== undefined) { ++this._peekRequestId; return; } const requestId = ++this._peekRequestId; this.database.peekStudyInstanceCount(studyUid, storeUid).then(count => { if (requestId !== this._peekRequestId) return; this.peekedInstanceCount.set(count); }).catch(() => { // Non-fatal: leave instanceCount undefined (shown as '-') rather than surfacing an // unhandled rejection - only if this request is still the current one, so a failed // stale request can't clobber a newer request's already-resolved count. if (requestId !== this._peekRequestId) return; this.peekedInstanceCount.set(undefined); }); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const studyUid = this.studyUid(); const storeUid = this.storeUid(); this.peekedSeriesInstanceCounts.set(new Map()); if (!studyUid || !storeUid) { ++this._seriesInstanceCountsPeekRequestId; return; } const requestId = ++this._seriesInstanceCountsPeekRequestId; this.database.peekSeriesInstanceCounts(studyUid, storeUid, (seriesUid, count) => { // Series resolve out of order and one at a time - apply each as it lands rather than // waiting for the whole study to finish, so the table fills in progressively instead // of jumping from all-dashes to fully populated at once. if (requestId !== this._seriesInstanceCountsPeekRequestId) return; this.peekedSeriesInstanceCounts.update(counts => new Map(counts).set(seriesUid, count)); }).catch(() => { // Non-fatal: whatever already landed via onSeriesCount stays - only the series that // hadn't resolved yet stay at '-' rather than surfacing an unhandled rejection. }); }); } loadingData = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "loadingData" }] : [])); confirmedEmpty = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "confirmedEmpty" }] : [])); error = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "error" }] : [])); baseSeriesList = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)(this.seriesList$, { initialValue: [] }); seriesList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const list = this.baseSeriesList(); const counts = this.peekedSeriesInstanceCounts(); return list.map(series => ({ ...series, totalInstanceCount: series.seriesInstanceUID ? counts.get(series.seriesInstanceUID) : undefined })); }, ...(ngDevMode ? [{ debugName: "seriesList" }] : [])); loading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.baseSeriesList().length === 0 && (this.loadingData() || !this.confirmedEmpty()), ...(ngDevMode ? [{ debugName: "loading" }] : [])); hasAnnotatedSeries = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.baseSeriesList().some(s => s.isAnnotated), ...(ngDevMode ? [{ debugName: "hasAnnotatedSeries" }] : [])); sourceDescriptions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(new Map(), ...(ngDevMode ? [{ debugName: "sourceDescriptions" }] : [])); downloadState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const storeUid = this.storeUid(); return Object.fromEntries(this.seriesCache.activeTargets().filter(target => target.storeUid === storeUid).map(target => [target.seriesUid, true])); }, ...(ngDevMode ? [{ debugName: "downloadState" }] : [])); deleteState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)({}, ...(ngDevMode ? [{ debugName: "deleteState" }] : [])); // instanceCount prefers numberOfInstancesHint (free, when the caller already has it), then // falls back to peekStudyInstanceCount's result - undefined until whichever applies resolves. // The series-list-derived count is deliberately never used as a placeholder here: it only // reflects locally-cached instances (0 for an untouched series), which is misleading rather // than genuinely "not known yet". summary = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => ({ instanceCount: this.numberOfInstancesHint() ?? this.peekedInstanceCount(), seriesCount: this.baseSeriesList().length }), ...(ngDevMode ? [{ debugName: "summary" }] : [])); _requestId = 0; /** Series whose instance metadata has already been refreshed this visit. */ otMetadataRefreshes = new Set(); /** * Review status lives in instance tags, and the local instance docs can be * missing (series never opened) or stale (a review recorded since — possibly * by another account). OT series hold only a handful of instances, so refresh * them from the store on every visit; CT series stay lazy. */ refreshOtInstanceMetadata(modality, seriesUids, studyUid, storeUid) { if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.normalizeModality)(modality) !== 'OT') return; for (const seriesUid of seriesUids) { const key = `${storeUid}:${seriesUid}`; if (this.otMetadataRefreshes.has(key)) continue; this.otMetadataRefreshes.add(key); this.database.refreshSeriesInstancesMetadata(studyUid, seriesUid, storeUid).catch(() => { // Non-fatal: the status column shows what the local cache has. }); } } buildSeriesListItem(series, documents) { const totalCount = documents.length; let cachedCount = 0; for (const document of documents) { if (document.getAttachment('pixelData')) { cachedCount += 1; } } const percent = totalCount ? Math.round(cachedCount / totalCount * 100) : 0; const reviewStatus = (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.resolveSeriesReviewStatus)(documents); return { ...series, cache: { cachedCount, percent, totalCount }, isAnnotated: (0,_series_cacheability__WEBPACK_IMPORTED_MODULE_13__.hasWorkSessionInstance)(documents), reviewStatus, reviewStatusRank: (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.reviewStatusRank)(reviewStatus), validationErrors: (0,_series_cacheability__WEBPACK_IMPORTED_MODULE_13__.resolveSeriesValidationErrors)(series.modality, documents) }; } setContext(studyUid, storeUid, numberOfInstancesHint) { this.storeUid.set(storeUid); this.studyUid.set(studyUid); this.numberOfInstancesHint.set(numberOfInstancesHint); } loadSeries() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (force = false) { const studyUid = _this.studyUid(); const storeUid = _this.storeUid(); if (!studyUid || !storeUid) return; const requestId = ++_this._requestId; _this.error.set(undefined); _this.loadingData.set(true); _this.confirmedEmpty.set(false); _this.sourceDescriptions.set(new Map()); try { if (force) { // Explicit reload: hard resync, also picking up server-side deletions. resyncSeriesForStudy // fetches before clearing, so a failed refetch leaves the existing series list in place // instead of wiping it with nothing to replace it. const remoteSeries = yield _this.database.resyncSeriesForStudy(studyUid, storeUid); if (requestId !== _this._requestId) return; _this.confirmedEmpty.set(remoteSeries.length === 0); _this.fetchSourceDescriptions(studyUid, storeUid).catch(error => { // Non-fatal: source descriptions are a supplementary label - a failure here // shouldn't surface as an error over an otherwise-successful series load. console.debug(FETCH_SOURCE_DESCRIPTIONS_FAILED_LOG, error); }); } else { yield _this.loadSeriesCacheFirst(requestId, studyUid, storeUid); } } catch (error) { if (requestId !== _this._requestId) return; _this.error.set(error.message ?? String(error)); _this.confirmedEmpty.set(true); } finally { if (requestId === _this._requestId) { _this.loadingData.set(false); } } }).apply(this, arguments); } /** Cache-first load: instant if already cached locally, revalidated in the background. */ loadSeriesCacheFirst(requestId, studyUid, storeUid) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const cachedSeries = yield _this2.database.getSeriesForStudy(studyUid, storeUid); if (requestId !== _this2._requestId) return; _this2.confirmedEmpty.set(cachedSeries.length === 0); if (cachedSeries.length > 0) { // Data is already visible via the reactive stream. Revalidate in the // background so server-side changes (e.g. a newly exported OT series) // eventually surface, without blocking or clearing what's on screen. _this2.loadingData.set(false); _this2.revalidateSeriesInBackground(requestId, studyUid, storeUid); } else { _this2.fetchSourceDescriptions(studyUid, storeUid).catch(error => { // Non-fatal: source descriptions are a supplementary label - a failure here // shouldn't surface as an error over an otherwise-successful series load. console.debug(FETCH_SOURCE_DESCRIPTIONS_FAILED_LOG, error); }); } })(); } revalidateSeriesInBackground(requestId, studyUid, storeUid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { yield _this3.database.refreshSeriesForStudy(studyUid, storeUid, () => requestId === _this3._requestId); if (requestId !== _this3._requestId) return; _this3.fetchSourceDescriptions(studyUid, storeUid).catch(error => { // Non-fatal: source descriptions are a supplementary label - a failure here // shouldn't surface as an error over an otherwise-successful series load. console.debug(FETCH_SOURCE_DESCRIPTIONS_FAILED_LOG, error); }); } catch { // Non-fatal: keep showing the already-cached series list. } })(); } fetchSourceDescriptions(studyUid, storeUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const series = yield _this4.database.getSeriesForStudy(studyUid, storeUid); const otSeries = series.filter(s => String(s.modality ?? '').trim().toUpperCase() === 'OT' && s.seriesInstanceUID); if (otSeries.length === 0) return; const descriptions = new Map(); for (const s of otSeries) { const seriesUid = s.seriesInstanceUID ?? ''; try { // Local-only: reads whatever's already cached instead of fetching the series just to // compute this label - callers that need the data itself still fetch it explicitly. const instances = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.firstValueFrom)(_this4.database.streamSeriesInstances(seriesUid, storeUid)); if (instances.length === 0) continue; const typed = instances; const meta = typed[0]?.toJSON().metadata; if (String(meta?.['00080070']?.Value?.[0] ?? '').trim() !== 'Tomoverse Imaging') continue; const desc = yield _this4.findSourceDescription(typed, storeUid); if (desc) descriptions.set(seriesUid, desc); } catch { // Non-fatal: binary may not be available yet } } _this4.sourceDescriptions.set(descriptions); })(); } findSourceDescription(instances, storeUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { for (const inst of instances) { const binary = yield _this5.database.getCachedBinary(inst.sopInstanceUID, storeUid); if (!binary) continue; const desc = (0,_services_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_11__.extractAnnotationTags)(binary)?.sourceSeriesDescription ?? ''; if (desc) return desc; } return ''; })(); } isDownloading(seriesUid) { return Boolean(this.downloadState()[seriesUid]); } isDeleting(seriesUid) { return Boolean(this.deleteState()[seriesUid]); } downloadSeries(seriesUid) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this6.downloadSeriesBatch([seriesUid]); })(); } downloadSeriesBatch(seriesUids, detail) { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const studyUid = _this7.studyUid(); const storeUid = _this7.storeUid(); const targets = seriesUids.filter(Boolean); const [first] = targets; if (!studyUid || !storeUid || !first) return; try { yield _this7.seriesCache.cache(targets.map(seriesUid => ({ seriesUid, storeUid, studyUid })), detail ?? _this7.seriesLabel(first)); // Binaries just became available - recompute source descriptions now instead of waiting // for an unrelated series reload to happen to pick them up. _this7.fetchSourceDescriptions(studyUid, storeUid).catch(error => { // Non-fatal: source descriptions are a supplementary label - a failure here // shouldn't surface as an error over an otherwise-successful download. console.debug(FETCH_SOURCE_DESCRIPTIONS_FAILED_LOG, error); }); } catch (error) { _this7.error.set(error.message ?? String(error)); } })(); } seriesLabel(seriesUid) { const series = this.baseSeriesList().find(item => item.seriesInstanceUID === seriesUid); const description = series?.seriesDescription?.trim() || (series?.seriesNumber === undefined ? seriesUid : `#${series.seriesNumber}`); const patient = series?.patientName?.trim(); return patient ? `${patient} · ${description}` : description; } deleteSeries(seriesUid) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const storeUid = _this8.storeUid(); if (!seriesUid || !storeUid) return; _this8.setDeleteState(seriesUid, true); try { yield _this8.database.deleteSeriesCache(seriesUid, storeUid); } catch (error) { _this8.error.set(error.message ?? String(error)); } finally { _this8.setDeleteState(seriesUid, false); } })(); } setDeleteState(seriesUid, isDeleting) { this.deleteState.update(state => ({ ...state, [seriesUid]: isDeleting })); } static ɵfac = function PatientLibraryDetailsFacade_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PatientLibraryDetailsFacade)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: PatientLibraryDetailsFacade, factory: PatientLibraryDetailsFacade.ɵfac }); } /***/ }, /***/ 33784 /*!**********************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/patient-library-list.component.ts ***! \**********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatientLibraryListComponent: () => (/* binding */ PatientLibraryListComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 57168); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_datepicker__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/datepicker */ 83203); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_multiselect__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/multiselect */ 58612); /* harmony import */ var primeng_paginator__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/paginator */ 69130); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../review-status-icon/review-status-icon.component */ 92729); /* harmony import */ var _patient_library_list_facade__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./patient-library-list.facade */ 67045); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ cap: a0 }); const _c1 = () => ({ "table-layout": "fixed" }); const _c2 = a0 => ({ count: a0 }); function PatientLibraryListComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", ctx_r0.error(), " "); } } function PatientLibraryListComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind2"](2, 1, "patientList.truncated", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction1"](4, _c0, ctx_r0.total())), " "); } } function PatientLibraryListComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](2, 1, "patientList.noStores"), " "); } } function PatientLibraryListComponent_Conditional_4_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "tr")(1, "th", 20)(2, "span", 21)(3, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](6, "p-sortIcon", 23); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](7, "th", 24)(8, "span", 21)(9, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](12, "p-sortIcon", 25); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](13, "th", 26)(14, "span", 21)(15, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](16); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](17, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](18, "p-sortIcon", 27); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](19, "th", 28)(20, "span", 21)(21, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](23, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](24, "p-sortIcon", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](25, "th", 30); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](26); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](27, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](28, "th", 31)(29, "span", 21)(30, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](31); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](32, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](33, "p-sortIcon", 32); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](34, "th", 33)(35, "span", 34)(36, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](38, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](39, "p-sortIcon", 35); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](40, "th", 36)(41, "span", 34)(42, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](43); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](44, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](45, "p-sortIcon", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](46, "th", 38); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](47); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](48, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](49, "th", 39)(50, "span", 34)(51, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](52); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](53, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](54, "p-sortIcon", 40); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](55, "th", 41); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](56); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](57, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](58, "tr", 42)(59, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](60, "input", 43); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](61, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](62, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](63, "input", 44); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](64, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](65, "th")(66, "div", 45); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](67, "p-datepicker", 46); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](68, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](69, "p-datepicker", 47); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](70, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](71, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](72, "input", 48); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](73, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](74, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](75, "p-multiselect", 49); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](76, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](77, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](78, "input", 50); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](79, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](80, "th")(81, "th")(82, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](83, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](84, "p-select", 51); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](85, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](86, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](5, 26, "patientList.table.patientName")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](11, 28, "patientList.table.mrn")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](17, 30, "patientList.table.studyDate")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](23, 32, "patientList.table.description")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](27, 34, "patientList.table.modalities"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](32, 36, "patientList.table.institution")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](38, 38, "patientList.table.series")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](44, 40, "patientList.table.sessions")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](48, 42, "patientList.table.annotated"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](53, 44, "patientList.table.reviewed")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](57, 46, "patientList.table.actions"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formGroup", ctx_r0.filterForm); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](61, 48, "patientList.filters.patientName")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](64, 50, "patientList.filters.mrn")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("showIcon", true)("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](68, 52, "patientList.filters.dateFrom")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("showIcon", true)("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](70, 54, "patientList.filters.dateTo")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](73, 56, "patientList.filters.description")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("options", ctx_r0.modalityOptions)("showToggleAll", false)("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](76, 58, "patientList.filters.modality")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](79, 60, "patientList.filters.institution")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("options", ctx_r0.statusFilterOptions())("showClear", true)("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](85, 62, "reviewStatus.all")); } } function PatientLibraryListComponent_Conditional_4_ng_template_3_Conditional_37_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "span", 56); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](1, "lib-icon", 63); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } } function PatientLibraryListComponent_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](1, "tr", 52); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("contextmenu", function PatientLibraryListComponent_Conditional_4_ng_template_3_Template_tr_contextmenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const study_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreadContextLet"](0); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); const studyMenuContext_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](9); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.studyMenu.openAtPointer(studyMenuContext_r5, $event, study_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](2, "td", 53, 5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](4, "dicomPersonName"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](6, "dicomPersonName"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](7, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](8, "td", 53, 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](11, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](12, "td", 53, 7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](14, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](15); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](16, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](17, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](18, "td", 53, 8); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](20); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](21, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](22, "td", 54, 9); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](25, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](26, "td", 53, 10); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](28); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](29, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](30, "td", 55); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](31); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](32, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](33, "td", 55); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](34); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](35, "orDash"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](36, "td", 55); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](37, PatientLibraryListComponent_Conditional_4_ng_template_3_Conditional_37_Template, 2, 0, "span", 56); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](38, "td", 55); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](39, "lib-review-status-icon", 57); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](40, "td")(41, "div", 58)(42, "p-button", 59); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](43, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function PatientLibraryListComponent_Conditional_4_ng_template_3_Template_p_button_click_42_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const study_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreadContextLet"](0); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); const studyMenuPopup_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](7); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.studyMenu.openFromButton(studyMenuPopup_r6, $event, study_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](44, "lib-icon", 60); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](45, "p-button", 61); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](46, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](47, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function PatientLibraryListComponent_Conditional_4_ng_template_3_Template_p_button_click_45_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const study_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreadContextLet"](0); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.selectStudy(study_r4.studyInstanceUID)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](48, "lib-icon", 62); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()()(); } if (rf & 2) { const rawStudy_r7 = ctx.$implicit; const patientNameTip_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](3); const patientIdTip_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](9); const studyDateTip_r10 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](13); const descriptionTip_r11 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](19); const modalitiesTip_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](23); const institutionTip_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](27); const study_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵstoreLet"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2).asStudy(rawStudy_r7)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pSelectableRow", study_r14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", patientNameTip_r8.truncated() ? _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](4, 21, study_r14.patientName) : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](7, 25, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](6, 23, study_r14.patientName)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", patientIdTip_r9.truncated() ? study_r14.patientID : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](11, 27, study_r14.patientID), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", studyDateTip_r10.truncated() ? _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind3"](14, 29, study_r14.studyDate, !!study_r14.studyTime, study_r14.studyTime) : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](17, 37, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind3"](16, 33, study_r14.studyDate, !!study_r14.studyTime, study_r14.studyTime)), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", descriptionTip_r11.truncated() ? study_r14.studyDescription : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](21, 39, study_r14.studyDescription), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", modalitiesTip_r12.truncated() ? study_r14.modalities.join(", ") : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](25, 41, study_r14.modalities.join(", ")), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", institutionTip_r13.truncated() ? study_r14.institutionName : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](29, 43, study_r14.institutionName), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](32, 45, study_r14.numberOfSeries)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](35, 47, study_r14.workSessionCount)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](study_r14.isAnnotated ? 37 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("status", study_r14.reviewStatus ?? "none"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](43, 49, "patientList.table.actions")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](46, 51, "patientList.open"))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](47, 53, "patientList.open")); } } function PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](1, 1, "patientList.loading"), " "); } } function PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](1, 1, "patientList.noMatches"), " "); } } function PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](1, 1, "patientList.noData"), " "); } } function PatientLibraryListComponent_Conditional_4_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "tr")(1, "td", 55); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](2, PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_2_Template, 2, 3)(3, PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_3_Template, 2, 3)(4, PatientLibraryListComponent_Conditional_4_ng_template_5_Conditional_4_Template, 2, 3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵattribute"]("colspan", 11); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx_r0.loading() ? 2 : ctx_r0.hasActiveFilters() ? 3 : 4); } } function PatientLibraryListComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "p-table", 19); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("onLazyLoad", function PatientLibraryListComponent_Conditional_4_Template_p_table_onLazyLoad_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.onLazyLoad($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayListener"]("selectionChange", function PatientLibraryListComponent_Conditional_4_Template_p_table_selectionChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayBindingSet"](ctx_r0.rowClickedStudyUid, $event) || (ctx_r0.rowClickedStudyUid = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("onRowSelect", function PatientLibraryListComponent_Conditional_4_Template_p_table_onRowSelect_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.onRowSelect($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplate"](1, PatientLibraryListComponent_Conditional_4_ng_template_1_Template, 87, 64, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplateRefExtractor"])(3, PatientLibraryListComponent_Conditional_4_ng_template_3_Template, 49, 55, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplateRefExtractor"])(5, PatientLibraryListComponent_Conditional_4_ng_template_5_Template, 5, 2, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("value", ctx_r0.rows())("loading", ctx_r0.loading())("lazy", true)("sortField", ctx_r0.sortField())("sortOrder", ctx_r0.sortOrder())("paginator", false)("tableStyle", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction0"](9, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayProperty"]("selection", ctx_r0.rowClickedStudyUid); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("metaKeySelection", true); } } function PatientLibraryListComponent_Conditional_5_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1, "\u00B7"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind2"](4, 1, "patientList.counts.series", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction1"](4, _c2, ctx_r0.summary().seriesCount))); } } function PatientLibraryListComponent_Conditional_5_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1, "\u00B7"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind2"](4, 1, "patientList.counts.instances", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction1"](4, _c2, ctx_r0.summary().instanceCount)), " "); } } function PatientLibraryListComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { const _r15 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 16)(1, "div", 64)(2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](5, PatientLibraryListComponent_Conditional_5_Conditional_5_Template, 5, 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](6, PatientLibraryListComponent_Conditional_5_Conditional_6_Template, 5, 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](7, "span", 65); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](10, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](11, "p-select", 66); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("ngModelChange", function PatientLibraryListComponent_Conditional_5_Template_p_select_ngModelChange_11_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r15); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.onRowsPerPageChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](12, "span", 65); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](13); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](14, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](15, "p-paginator", 67); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("onPageChange", function PatientLibraryListComponent_Conditional_5_Template_p_paginator_onPageChange_15_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r15); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.onPageChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind2"](4, 16, "patientList.counts.studies", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction1"](23, _c2, ctx_r0.summary().studyCount))); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx_r0.summary().seriesCount !== undefined ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx_r0.summary().instanceCount !== undefined ? 6 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](9, 19, "patientList.pagination.rowsPerPage")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("options", ctx_r0.pageSizeOptions)("ngModel", ctx_r0.pageSize()); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate4"](" ", ctx_r0.firstRecord(), "-", ctx_r0.lastRecord(), " ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](14, 21, "patientList.pagination.of"), " ", ctx_r0.total(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("showCurrentPageReport", false)("showPageLinks", false)("showFirstLastIcon", false)("first", ctx_r0.first())("rows", ctx_r0.pageSize())("totalRecords", ctx_r0.total()); } } const FILTER_DEBOUNCE_MS = 250; class PatientLibraryListComponent { vm = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_21__.PatientLibraryListFacade); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__.TranslateService); studySelected = new _angular_core__WEBPACK_IMPORTED_MODULE_1__.EventEmitter(); studyMenu = new _tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__.RowMenuController(study => this.buildStudyMenuItems(study)); rowClickedStudyUid = undefined; lastClickedStudyUid = undefined; lastClickAtMs = 0; doubleClickThresholdMs = 300; loading = this.vm.loading; error = this.vm.error; rows = this.vm.rows; total = this.vm.total; truncated = this.vm.truncated; summary = this.vm.summary; pageSize = this.vm.pageSize; first = this.vm.first; hasActiveFilters = this.vm.hasActiveFilters; stores = this.vm.stores; loadingStores = this.vm.loadingStores; selectedStoreUid = this.vm.selectedStoreUid; pageSizeOptions = [12, 25, 50]; modalityOptions = [..._tomoverse_dtos__WEBPACK_IMPORTED_MODULE_17__.MODALITY_OPTIONS]; langChange = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)(this.translate.onLangChange); statusFilterOptions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this.langChange(); return ['approved', 'rejected', 'unapproved'].map(value => ({ label: this.translate.instant(`reviewStatus.${value}`), value })); }, ...(ngDevMode ? [{ debugName: "statusFilterOptions" }] : [])); firstRecord = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.total() === 0 ? 0 : this.first() + 1, ...(ngDevMode ? [{ debugName: "firstRecord" }] : [])); lastRecord = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => Math.min(this.first() + this.pageSize(), this.total()), ...(ngDevMode ? [{ debugName: "lastRecord" }] : [])); sortField = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.vm.sortSpec()?.field, ...(ngDevMode ? [{ debugName: "sortField" }] : [])); sortOrder = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.vm.sortSpec()?.direction ?? _tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__.PRIMENG_DEFAULT_SORT_ORDER, ...(ngDevMode ? [{ debugName: "sortOrder" }] : [])); filterForm = new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormGroup({ description: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl('', { nonNullable: true }), institution: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl('', { nonNullable: true }), modalities: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl([], { nonNullable: true }), mrn: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl('', { nonNullable: true }), patientName: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl('', { nonNullable: true }), reviewStatus: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl(undefined, { nonNullable: true }), studyDateFrom: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl(undefined, { nonNullable: true }), studyDateTo: new _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControl(undefined, { nonNullable: true }) }); constructor() { this.hydrateFormFromCriteria(); this.filterForm.valueChanges.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.debounceTime)(FILTER_DEBOUNCE_MS), (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.takeUntilDestroyed)()).subscribe(() => this.vm.setCriteria(this.buildCriteria())); this.vm.clearFiltersRequests.pipe((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.takeUntilDestroyed)()).subscribe(() => this.clearFilters()); } hydrateFormFromCriteria() { const { description, institution, modalities, patientID, patientName, reviewStatus, studyDateFrom, studyDateTo } = this.vm.criteria(); this.filterForm.reset({ description: description ?? '', institution: institution ?? '', modalities: modalities ?? [], mrn: patientID ?? '', patientName: patientName ?? '', reviewStatus, studyDateFrom: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.parseDicomDate)(studyDateFrom), studyDateTo: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.parseDicomDate)(studyDateTo) }, { emitEvent: false }); } onLazyLoad(event) { const field = typeof event.sortField === 'string' ? event.sortField : undefined; const sort = field ? { direction: event.sortOrder ?? 1, field } : undefined; const current = this.vm.sortSpec(); if (sort?.field === current?.field && sort?.direction === current?.direction) return; this.vm.applySort(sort); } onPageChange(event) { this.vm.setPage(event.first ?? 0, event.rows ?? this.pageSize()); } onRowsPerPageChange(rows) { this.vm.setPage(0, rows); } buildCriteria() { const { description, institution, modalities, mrn, patientName, reviewStatus, studyDateFrom, studyDateTo } = this.filterForm.getRawValue(); const criteria = {}; if (modalities.length > 0) criteria.modalities = modalities; if (reviewStatus) criteria.reviewStatus = reviewStatus; const textFields = [['description', description], ['institution', institution], ['patientID', mrn], ['patientName', patientName]]; for (const [key, raw] of textFields) { const term = raw.trim(); if (term) criteria[key] = term; } if (studyDateFrom) criteria.studyDateFrom = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.toDicomDate)(studyDateFrom); if (studyDateTo) criteria.studyDateTo = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.toDicomDate)(studyDateTo); return criteria; } clearFilters() { this.filterForm.reset({ description: '', institution: '', modalities: [], mrn: '', patientName: '', reviewStatus: undefined, studyDateFrom: undefined, studyDateTo: undefined }); } reloadStudies() { this.vm.reloadStudies(); } onRowSelect(event) { const study = Array.isArray(event?.data) ? event.data[0] : event?.data; const { studyInstanceUID } = study || {}; const now = Date.now(); const isDoubleClick = studyInstanceUID !== undefined && studyInstanceUID === this.lastClickedStudyUid && now - this.lastClickAtMs <= this.doubleClickThresholdMs; if (isDoubleClick) { this.lastClickedStudyUid = undefined; this.lastClickAtMs = 0; this.selectStudy(studyInstanceUID, false, study?.numberOfInstances); return; } this.lastClickedStudyUid = studyInstanceUID; this.lastClickAtMs = now; } asStudy(value) { return value; } selectStudy(studyUID, cacheAll = false, numberOfInstances) { const storeUid = this.selectedStoreUid(); if (studyUID && storeUid) { this.studySelected.emit({ cacheAll, numberOfInstances, storeUid, studyUid: studyUID }); } } /** * The viewer opens CT, plus OT when the series is a tvCT analysis - plain OT is not * viewable, and `isAnnotated` is the only per-study signal for that. Instance-level * validation can still reject a CT series, so this rules studies out but never in. */ hasCacheableModality(study) { return (study.modalities ?? []).some(modality => { const viewable = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.isViewableModality)(modality); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.normalizeModality)(modality) === 'OT' ? viewable && study.isAnnotated : viewable; }); } /** * Caching happens in the series view, so the user can watch per-series progress. Only * go there when there is something to fetch: the modalities on the row rule out studies * the viewer cannot open at all, and the local database rules out ones already cached. */ cacheStudy(study) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const studyUid = study.studyInstanceUID; const storeUid = _this.selectedStoreUid(); if (!studyUid || !storeUid) return; if (yield _this.vm.hasCacheableSeries(studyUid, storeUid)) { _this.selectStudy(studyUid, true, study.numberOfInstances); return; } _this.vm.notifyNothingToCache(); })(); } buildStudyMenuItems(study) { const studyUid = study.studyInstanceUID; return [{ command: () => this.selectStudy(studyUid, false, study.numberOfInstances), disabled: !studyUid, icon: 'pi pi-folder-open', label: this.translate.instant('patientList.menu.openStudy') }, { separator: true }, { command: () => this.cacheStudy(study), disabled: !studyUid || !this.hasCacheableModality(study), icon: 'pi pi-cloud-download', label: this.translate.instant('patientList.menu.cache') }, { separator: true }, (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__.dangerMenuItem)({ disabled: true, icon: 'pi pi-trash', label: this.translate.instant('patientList.menu.deleteStudy') })]; } static ɵfac = function PatientLibraryListComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PatientLibraryListComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵdefineComponent"]({ type: PatientLibraryListComponent, selectors: [["lib-patient-library-list"]], hostAttrs: [1, "flex", "h-full", "flex-col"], outputs: { studySelected: "studySelected" }, decls: 10, vars: 7, consts: [["studyMenuPopup", ""], ["studyMenuContext", ""], ["header", ""], ["body", ""], ["emptymessage", ""], ["patientNameTip", "libEllipsisTip"], ["patientIdTip", "libEllipsisTip"], ["studyDateTip", "libEllipsisTip"], ["descriptionTip", "libEllipsisTip"], ["modalitiesTip", "libEllipsisTip"], ["institutionTip", "libEllipsisTip"], [1, "flex", "min-h-0", "flex-1", "flex-col"], [1, "border-destructive/30", "bg-destructive/10", "text-destructive", "mx-4", "mb-4", "shrink-0", "rounded-md", "border", "px-3", "py-2"], ["data-test-id", "patient-library-div-truncated", 1, "border-primary-500/40", "bg-primary-500/10", "text-primary-400", "mx-4", "mb-4", "shrink-0", "rounded-md", "border", "px-3", "py-2", "text-sm"], [1, "text-muted-color", "bw", "mx-4", "mb-4", "shrink-0", "rounded-md", "border", "px-3", "py-2"], ["dataKey", "studyInstanceUID", "selectionMode", "single", "scrollable", "", "scrollHeight", "flex", 1, "library-table", "min-h-0", "flex-1", 3, "value", "loading", "lazy", "sortField", "sortOrder", "paginator", "tableStyle", "selection", "metaKeySelection"], [1, "library-footer", "text-muted-color", "border-surface-800", "flex", "shrink-0", "items-center", "justify-end", "gap-3", "border-t", "px-8", "py-2", "text-sm"], ["data-test-id", "patient-library-p-menu-study", "popup", "", "appendTo", "body", 3, "model"], ["data-test-id", "patient-library-p-contextmenu-study", "appendTo", "body", 3, "model"], ["dataKey", "studyInstanceUID", "selectionMode", "single", "scrollable", "", "scrollHeight", "flex", 1, "library-table", "min-h-0", "flex-1", 3, "onLazyLoad", "selectionChange", "onRowSelect", "value", "loading", "lazy", "sortField", "sortOrder", "paginator", "tableStyle", "selection", "metaKeySelection"], ["pSortableColumn", "patientName", 1, "w-[10.3125rem]", "overflow-hidden"], [1, "flex", "min-w-0", "items-center", "gap-1"], [1, "truncate"], ["field", "patientName"], ["pSortableColumn", "patientID", 1, "w-[7.5rem]", "overflow-hidden"], ["field", "patientID"], ["pSortableColumn", "studyDate", 1, "w-[18.125rem]", "overflow-hidden"], ["field", "studyDate"], ["pSortableColumn", "studyDescription", 1, "w-[13.75rem]", "overflow-hidden"], ["field", "studyDescription"], [1, "w-[9.0625rem]", "overflow-hidden", "text-center", "whitespace-nowrap"], ["pSortableColumn", "institutionName", 1, "w-[8.75rem]", "overflow-hidden"], ["field", "institutionName"], ["pSortableColumn", "numberOfSeries", 1, "w-[5.9375rem]", "overflow-hidden", "text-center"], [1, "flex", "min-w-0", "items-center", "justify-center", "gap-1"], ["field", "numberOfSeries"], ["pSortableColumn", "workSessionCount", 1, "w-[6.875rem]", "overflow-hidden", "text-center"], ["field", "workSessionCount"], [1, "w-[6.875rem]", "overflow-hidden", "text-center", "whitespace-nowrap"], ["pSortableColumn", "reviewStatusRank", 1, "w-[6.25rem]", "overflow-hidden", "text-center"], ["field", "reviewStatusRank"], [1, "w-[7.8125rem]", "overflow-hidden", "text-right", "whitespace-nowrap"], [3, "formGroup"], ["pInputText", "", "pSize", "small", "type", "text", "formControlName", "patientName", "data-test-id", "patient-library-input-filter-patient-name", 1, "w-full", 3, "placeholder"], ["pInputText", "", "pSize", "small", "type", "text", "formControlName", "mrn", "data-test-id", "patient-library-input-filter-mrn", 1, "w-full", 3, "placeholder"], [1, "flex", "items-center", "gap-1"], ["formControlName", "studyDateFrom", "dateFormat", "dd.mm.yy", "size", "small", "appendTo", "body", "iconDisplay", "input", "styleClass", "w-full", "data-test-id", "patient-library-p-datepicker-filter-date-from", 3, "showIcon", "placeholder"], ["formControlName", "studyDateTo", "dateFormat", "dd.mm.yy", "size", "small", "appendTo", "body", "iconDisplay", "input", "styleClass", "w-full", "data-test-id", "patient-library-p-datepicker-filter-date-to", 3, "showIcon", "placeholder"], ["pInputText", "", "pSize", "small", "type", "text", "formControlName", "description", "data-test-id", "patient-library-input-filter-description", 1, "w-full", 3, "placeholder"], ["formControlName", "modalities", "size", "small", "appendTo", "body", "styleClass", "w-full", "data-test-id", "patient-library-p-multiselect-filter-study-modality", 3, "options", "showToggleAll", "placeholder"], ["pInputText", "", "pSize", "small", "type", "text", "formControlName", "institution", "data-test-id", "patient-library-input-filter-institution", 1, "w-full", 3, "placeholder"], ["formControlName", "reviewStatus", "optionLabel", "label", "optionValue", "value", "size", "small", "appendTo", "body", "styleClass", "w-full", "data-test-id", "patient-library-p-select-filter-review-status", 3, "options", "showClear", "placeholder"], [3, "contextmenu", "pSelectableRow"], ["libEllipsisTip", "", "tooltipPosition", "top", 3, "pTooltip"], ["libEllipsisTip", "", "tooltipPosition", "top", 1, "text-center", 3, "pTooltip"], [1, "text-center"], [1, "text-(--p-app-status-success)"], [3, "status"], [1, "flex", "items-center", "justify-end", "gap-2"], ["data-test-id", "patient-library-p-button-study-menu", "severity", "secondary", "text", "", "size", "small", 3, "click", "ariaLabel"], ["icon", "ellipsis-v"], ["data-test-id", "patient-library-p-button-open-study", "severity", "secondary", "rounded", "", "text", "", "size", "small", "styleClass", "h-[30px] w-[30px] p-0", "tooltipPosition", "top", 3, "click", "ariaLabel", "pTooltip"], ["icon", "arrow-right", 1, "size-(--p-app-icon-size-xs)"], ["icon", "check"], ["data-test-id", "patient-library-div-summary", 1, "mr-auto", "flex", "items-center", "gap-2"], [1, "shrink-0"], ["data-test-id", "patient-library-p-select-page-size", "size", "small", "appendTo", "body", 1, "overflow-hidden", 3, "ngModelChange", "options", "ngModel"], ["data-test-id", "patient-library-p-paginator-nav", 1, "gap-3", "bg-transparent", "p-0", 3, "onPageChange", "showCurrentPageReport", "showPageLinks", "showFirstLastIcon", "first", "rows", "totalRecords"]], template: function PatientLibraryListComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 11); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](1, PatientLibraryListComponent_Conditional_1_Template, 2, 1, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](2, PatientLibraryListComponent_Conditional_2_Template, 3, 6, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](3, PatientLibraryListComponent_Conditional_3_Template, 3, 3, "div", 14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](4, PatientLibraryListComponent_Conditional_4_Template, 7, 10, "p-table", 15); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](5, PatientLibraryListComponent_Conditional_5_Template, 16, 25, "div", 16); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](6, "p-menu", 17, 0)(8, "p-contextmenu", 18, 1); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx.error() ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx.truncated() ? 2 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](!ctx.loading() && !ctx.loadingStores() && ctx.stores().length === 0 ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx.stores().length !== 0 ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](!ctx.loading() && ctx.stores().length !== 0 ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("model", ctx.studyMenu.items()); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("model", ctx.studyMenu.items()); } }, dependencies: [primeng_table__WEBPACK_IMPORTED_MODULE_15__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_15__.Table, primeng_table__WEBPACK_IMPORTED_MODULE_15__.SortableColumn, primeng_table__WEBPACK_IMPORTED_MODULE_15__.SelectableRow, primeng_table__WEBPACK_IMPORTED_MODULE_15__.SortIcon, primeng_button__WEBPACK_IMPORTED_MODULE_7__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_7__.Button, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_8__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_8__.ContextMenu, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__.TranslateModule, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgControlStatusGroup, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgModel, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormGroupDirective, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormControlName, primeng_datepicker__WEBPACK_IMPORTED_MODULE_9__.DatePickerModule, primeng_datepicker__WEBPACK_IMPORTED_MODULE_9__.DatePicker, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputText, primeng_menu__WEBPACK_IMPORTED_MODULE_11__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_11__.Menu, primeng_multiselect__WEBPACK_IMPORTED_MODULE_12__.MultiSelectModule, primeng_multiselect__WEBPACK_IMPORTED_MODULE_12__.MultiSelect, primeng_select__WEBPACK_IMPORTED_MODULE_14__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_14__.Select, primeng_paginator__WEBPACK_IMPORTED_MODULE_13__.PaginatorModule, primeng_paginator__WEBPACK_IMPORTED_MODULE_13__.Paginator, primeng_tooltip__WEBPACK_IMPORTED_MODULE_16__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_16__.Tooltip, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__.EllipsisTipDirective, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_18__.IconComponent, _review_status_icon_review_status_icon_component__WEBPACK_IMPORTED_MODULE_20__.ReviewStatusIconComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__.TranslatePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.DicomDatePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.DicomPersonNamePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_19__.OrDashPipe], encapsulation: 2 }); } /***/ }, /***/ 67045 /*!*******************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/patient-library-list.facade.ts ***! \*******************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatientLibraryListFacade: () => (/* binding */ PatientLibraryListFacade) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 33242); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 90015); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 45541); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _series_cacheability__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./series-cacheability */ 54759); const EMPTY_PAGE = { aggregates: {}, rows: [], total: 0, truncated: false }; function statusMapsEqual(a, b) { if (a.size !== b.size) return false; for (const [studyUid, status] of a) { if (b.get(studyUid) !== status) return false; } return true; } class PatientLibraryListFacade { provider = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_12__.StudySearchProvider); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_12__.DicomStoreListService); preferences = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_12__.PreferencesService); database = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_12__.DicomDatabaseService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_11__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__.TranslateService); loading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "loading" }] : [])); error = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "error" }] : [])); page = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(EMPTY_PAGE, ...(ngDevMode ? [{ debugName: "page" }] : [])); criteria = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)({}, ...(ngDevMode ? [{ debugName: "criteria" }] : [])); sortSpec = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "sortSpec" }] : [])); first = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "first" }] : [])); pageSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(12, ...(ngDevMode ? [{ debugName: "pageSize" }] : [])); stores = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "stores" }] : [])); selectedStoreUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "selectedStoreUid" }] : [])); loadingStores = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "loadingStores" }] : [])); storeStats = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "storeStats" }] : [])); /** Review status per studyUid, from locally cached OT instance metadata (fills in as studies are visited). */ reviewStatuses = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(new Map(), ...(ngDevMode ? [{ debugName: "reviewStatuses" }] : [])); rows = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.page().rows, ...(ngDevMode ? [{ debugName: "rows" }] : [])); total = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.page().total, ...(ngDevMode ? [{ debugName: "total" }] : [])); truncated = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.page().truncated, ...(ngDevMode ? [{ debugName: "truncated" }] : [])); summary = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { aggregates, total } = this.page(); return { instanceCount: aggregates.instanceSum, seriesCount: aggregates.seriesSum, studyCount: total }; }, ...(ngDevMode ? [{ debugName: "summary" }] : [])); hasActiveFilters = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => Object.keys(this.criteria()).length > 0, ...(ngDevMode ? [{ debugName: "hasActiveFilters" }] : [])); clearFilters$ = new rxjs__WEBPACK_IMPORTED_MODULE_4__.Subject(); clearFiltersRequests = this.clearFilters$.asObservable(); /** Set while the details (series) view is open; undefined on the study list. */ detailsToolbar = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "detailsToolbar" }] : [])); query$ = new rxjs__WEBPACK_IMPORTED_MODULE_4__.Subject(); constructor() { this.query$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.tap)(() => { this.loading.set(true); this.error.set(undefined); }), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.switchMap)(query => this.provider.search(query).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_7__.catchError)(error => { this.error.set(error.message ?? String(error)); this.loading.set(false); return rxjs__WEBPACK_IMPORTED_MODULE_6__.EMPTY; }))), (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.takeUntilDestroyed)()).subscribe(page => { this.page.set(page); this.loading.set(false); this.refreshReviewStatuses(page.rows); }); } /** Overlay the Reviewed column for the displayed rows (store-resolved); non-blocking, best-effort. */ refreshReviewStatuses(rows) { const storeUid = this.selectedStoreUid(); if (!storeUid) return; const otStudyUids = rows.filter(row => row.modalities.some(modality => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.normalizeModality)(modality) === 'OT')).map(row => row.studyInstanceUID); if (otStudyUids.length === 0) return; this.database.getStudyOtReviewStatuses(otStudyUids, storeUid).then(statuses => { // Merge: keep statuses gathered on other pages so filtering and sorting see them. const merged = new Map([...this.reviewStatuses(), ...statuses]); if (statusMapsEqual(merged, this.reviewStatuses())) return; this.reviewStatuses.set(merged); this.runSearch(); }).catch(() => { // Non-fatal: the column simply stays blank. }); } init() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this.loadStores(); _this.runSearch(); })(); } loadStores() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this2.loadingStores.set(true); try { const stores = yield _this2.storeList.getReachableStores(); _this2.stores.set(stores); const persisted = _this2.preferences.get().storeUid; const defaultStore = stores.find(store => store.uid === persisted) ?? stores[0]; _this2.selectedStoreUid.set(defaultStore?.uid); if (stores.length === 0) { yield _this2.warnIfConfiguredStoresUnreachable(); } } catch (error) { _this2.error.set(error.message ?? String(error)); } finally { _this2.loadingStores.set(false); } })(); } /** * Distinguishes "no DICOM stores configured" (covered by the empty-state banner) from * "stores are configured but none responded to a ping" — the latter warrants a toast * since it usually means bad credentials or an unreachable store instance. */ warnIfConfiguredStoresUnreachable() { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const enabled = yield _this3.storeList.getEnabledStores(); if (enabled.length === 0) return; _this3.messageService.add({ detail: _this3.translate.instant('dicomImporter.storesUnreachable.detail'), life: 8000, severity: 'error', summary: _this3.translate.instant('dicomImporter.storesUnreachable.summary') }); })(); } /** * Whether caching the study would pull anything down, judged from the local database * with the same per-series rule the series view applies. Anything not stored locally * yet cannot be ruled out and counts as cacheable, so a study opened for the first * time always goes through. */ hasCacheableSeries(studyUid, storeUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const series = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.firstValueFrom)(_this4.database.streamSeriesForStudy(studyUid, storeUid)); if (series.length === 0) return true; for (const { modality, seriesInstanceUID: seriesUid } of series) { if (!seriesUid || !(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.isViewableModality)(modality)) continue; const documents = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.firstValueFrom)(_this4.database.streamSeriesInstances(seriesUid, storeUid)); if (documents.length === 0) return true; const cachedCount = documents.filter(d => d.getAttachment('pixelData')).length; if (cachedCount === documents.length) continue; if ((0,_series_cacheability__WEBPACK_IMPORTED_MODULE_14__.resolveSeriesValidationErrors)(modality, documents).length > 0) continue; return true; } return false; })(); } notifyNothingToCache() { this.messageService.add({ detail: this.translate.instant('patientList.nothingToCache.detail'), life: 5000, severity: 'info', summary: this.translate.instant('patientList.nothingToCache.summary') }); } /** Switch store: persist it, keep filters/sort, reset to page 1, re-search. */ selectStore(storeUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (storeUid === _this5.selectedStoreUid()) return; _this5.selectedStoreUid.set(storeUid); _this5.preferences.patch({ storeUid }); _this5.storeStats.set(undefined); _this5.reviewStatuses.set(new Map()); _this5.first.set(0); _this5.runSearch(); })(); } requestClearFilters() { this.clearFilters$.next(); } loadStoreStats() { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const requestedStoreUid = _this6.selectedStoreUid(); if (!requestedStoreUid) return; _this6.storeStats.set(undefined); try { const stats = yield _this6.storeList.getStoreStatistics(requestedStoreUid); if (requestedStoreUid === _this6.selectedStoreUid()) _this6.storeStats.set(stats); } catch { if (requestedStoreUid === _this6.selectedStoreUid()) _this6.storeStats.set({}); } })(); } /** Filter change: reset to page 1 and re-search over the (already-accumulated) set. */ setCriteria(criteria) { this.criteria.set(criteria); this.first.set(0); this.runSearch(); } /** Sort change from the table header. Resets to page 1. */ applySort(sort) { this.sortSpec.set(sort); this.first.set(0); this.runSearch(); } setPage(first, rows) { this.first.set(first); this.pageSize.set(rows); this.runSearch(); } /** Force a fresh accumulation from the store (drops the adapter cache). */ reloadStudies() { this.provider.invalidate(this.selectedStoreUid()); this.reviewStatuses.set(new Map()); this.runSearch(); } runSearch() { const storeUid = this.selectedStoreUid(); if (!storeUid) { this.page.set(EMPTY_PAGE); return; } this.query$.next({ criteria: this.criteria(), page: { limit: this.pageSize(), offset: this.first() }, reviewStatuses: this.reviewStatuses(), sort: this.sortSpec(), storeUid }); } static ɵfac = function PatientLibraryListFacade_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PatientLibraryListFacade)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: PatientLibraryListFacade, factory: PatientLibraryListFacade.ɵfac }); } /***/ }, /***/ 22357 /*!*****************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/patient-library.component.ts ***! \*****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PatientLibraryComponent: () => (/* binding */ PatientLibraryComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _patient_library_details_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./patient-library-details.component */ 71086); /* harmony import */ var _patient_library_list_component__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./patient-library-list.component */ 33784); /* harmony import */ var _patient_library_list_facade__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./patient-library-list.facade */ 67045); /* harmony import */ var _series_sort_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./series-sort.store */ 14900); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 14975); function PatientLibraryComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementStart"](0, "lib-patient-library-details", 2); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵlistener"]("back", function PatientLibraryComponent_Conditional_1_Template_lib_patient_library_details_back_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.closeStudy()); }); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementEnd"](); } if (rf & 2) { const study_r3 = ctx; _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵproperty"]("studyUid", study_r3.studyUid)("storeUid", study_r3.storeUid)("cacheAllOnOpen", study_r3.cacheAll)("numberOfInstancesHint", study_r3.numberOfInstances); } } function PatientLibraryComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementStart"](0, "lib-patient-library-list", 3); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵlistener"]("studySelected", function PatientLibraryComponent_Conditional_2_Template_lib_patient_library_list_studySelected_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.openStudy($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementEnd"](); } } class PatientLibraryComponent { facade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_3__.PatientLibraryListFacade); openedStudy = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "openedStudy" }] : [])); constructor() { // Switching stores invalidates the opened study, so fall back to the study list. (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { this.facade.selectedStoreUid(); this.openedStudy.set(undefined); }); } openStudy(study) { this.openedStudy.set(study); } closeStudy() { this.openedStudy.set(undefined); } static ɵfac = function PatientLibraryComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PatientLibraryComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdefineComponent"]({ type: PatientLibraryComponent, selectors: [["lib-patient-library"]], hostAttrs: [1, "block", "h-full"], features: [_angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵProvidersFeature"]([_series_sort_store__WEBPACK_IMPORTED_MODULE_4__.SeriesSortStore])], decls: 3, vars: 1, consts: [[1, "h-full"], [3, "studyUid", "storeUid", "cacheAllOnOpen", "numberOfInstancesHint"], [3, "back", "studyUid", "storeUid", "cacheAllOnOpen", "numberOfInstancesHint"], [3, "studySelected"]], template: function PatientLibraryComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementStart"](0, "div", 0); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵconditionalCreate"](1, PatientLibraryComponent_Conditional_1_Template, 1, 4, "lib-patient-library-details", 1)(2, PatientLibraryComponent_Conditional_2_Template, 1, 0, "lib-patient-library-list"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵconditional"]((tmp_0_0 = ctx.openedStudy()) ? 1 : 2, tmp_0_0); } }, dependencies: [_patient_library_list_component__WEBPACK_IMPORTED_MODULE_2__.PatientLibraryListComponent, _patient_library_details_component__WEBPACK_IMPORTED_MODULE_1__.PatientLibraryDetailsComponent], encapsulation: 2 }); } /***/ }, /***/ 36088 /*!*********************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/series-bulk-actions.component.ts ***! \*********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SeriesBulkActionsComponent: () => (/* binding */ SeriesBulkActionsComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ count: a0 }); function SeriesBulkActionsComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "div", 0)(1, "p-button", 1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function SeriesBulkActionsComponent_Conditional_0_Template_p_button_click_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵresetView"](ctx_r1.clear.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](4, "lib-icon", 2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](5, "span", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](8, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](10, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function SeriesBulkActionsComponent_Conditional_0_Template_p_button_click_10_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵresetView"](ctx_r1.view.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](12, "lib-icon", 6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](13, "p-button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](14, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](15, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function SeriesBulkActionsComponent_Conditional_0_Template_p_button_click_13_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵresetView"](ctx_r1.cache.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](16, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](17, "p-button", 9); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](19, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function SeriesBulkActionsComponent_Conditional_0_Template_p_button_click_17_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵresetView"](ctx_r1.more.emit($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](20, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](2, 12, "patientDetails.bulkActions.clear"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](3, 14, "patientDetails.bulkActions.clear")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind2"](7, 16, "patientDetails.bulkActions.selected", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction1"](31, _c0, ctx_r1.selectedCount())), " "); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pTooltip", ctx_r1.viewBlockedReason() || _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](9, 19, "patientDetails.bulkActions.view")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("severity", ctx_r1.viewBlockedReason() ? "secondary" : "primary")("disabled", !!ctx_r1.viewBlockedReason())("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](11, 21, "patientDetails.bulkActions.view")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("disabled", ctx_r1.cacheableCount() === 0)("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](14, 23, "patientDetails.bulkActions.cacheSelected"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](15, 25, "patientDetails.bulkActions.cacheSelected")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](18, 27, "patientDetails.bulkActions.more"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](19, 29, "patientDetails.bulkActions.more")); } } class SeriesBulkActionsComponent { selectedCount = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "selectedCount" }] : [])); cacheableCount = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "cacheableCount" }] : [])); /** Empty when the selection can be opened; otherwise why it cannot. */ viewBlockedReason = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "viewBlockedReason" }] : [])); view = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); cache = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); clear = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); more = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); static ɵfac = function SeriesBulkActionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SeriesBulkActionsComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: SeriesBulkActionsComponent, selectors: [["lib-series-bulk-actions"]], inputs: { selectedCount: [1, "selectedCount"], cacheableCount: [1, "cacheableCount"], viewBlockedReason: [1, "viewBlockedReason"] }, outputs: { view: "view", cache: "cache", clear: "clear", more: "more" }, decls: 1, vars: 1, consts: [["data-test-id", "patient-library-div-bulk-actions", 1, "border-primary-500/30", "bg-primary-500/10", "flex", "items-center", "gap-1.5", "rounded-full", "border", "py-1", "pr-2", "pl-1.5"], ["data-test-id", "patient-library-p-button-clear-selection", "severity", "secondary", "text", "", "rounded", "", "size", "small", "tooltipPosition", "bottom", 3, "click", "pTooltip", "ariaLabel"], ["icon", "times", 1, "size-(--p-app-icon-size-xxs)"], [1, "text-primary-200", "text-sm", "whitespace-nowrap"], ["tooltipPosition", "bottom", 1, "inline-flex", 3, "pTooltip"], ["data-test-id", "patient-library-p-button-bulk-view", "text", "", "rounded", "", "size", "small", 3, "click", "severity", "disabled", "ariaLabel"], ["icon", "eye", 1, "size-(--p-app-icon-size-xs)"], ["data-test-id", "patient-library-p-button-bulk-cache", "severity", "secondary", "text", "", "rounded", "", "size", "small", "tooltipPosition", "bottom", 3, "click", "disabled", "pTooltip", "ariaLabel"], ["icon", "cloud-download", 1, "size-(--p-app-icon-size-xs)"], ["data-test-id", "patient-library-p-button-bulk-menu", "severity", "secondary", "text", "", "rounded", "", "size", "small", "tooltipPosition", "bottom", 3, "click", "pTooltip", "ariaLabel"], ["icon", "ellipsis-h", 1, "size-(--p-app-icon-size-xs)"]], template: function SeriesBulkActionsComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](0, SeriesBulkActionsComponent_Conditional_0_Template, 21, 33, "div", 0); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx.selectedCount() > 0 ? 0 : -1); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_2__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_2__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__.IconComponent, primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateModule, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 8487 /*!********************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/series-cache-tasks.component.ts ***! \********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SeriesCacheTasksComponent: () => (/* binding */ SeriesCacheTasksComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var _series_cache_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./series-cache.service */ 60240); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["taskPopover"]; const _c1 = ["taskButton"]; const _c2 = a0 => ({ count: a0 }); const _c3 = () => ({ height: "4px" }); const _forTrack0 = ($index, $item) => $item.id; function SeriesCacheTasksComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](1, 1, "patientDetails.caching.taskCountOne"), " "); } } function SeriesCacheTasksComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](1, "translate"); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind2"](1, 1, "patientDetails.caching.taskCountOther", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction1"](4, _c2, ctx_r2.pendingCount())), " "); } } function SeriesCacheTasksComponent_Conditional_0_For_14_Conditional_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](1, 1, "patientDetails.caching.done"), " "); } } function SeriesCacheTasksComponent_Conditional_0_For_14_Conditional_8_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](0); } if (rf & 2) { const task_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", task_r4.progress, "% "); } } function SeriesCacheTasksComponent_Conditional_0_For_14_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "li", 8)(1, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](2, "i", 10); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](3, "span", 11); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](6, "span", 12); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](7, SeriesCacheTasksComponent_Conditional_0_For_14_Conditional_7_Template, 2, 3)(8, SeriesCacheTasksComponent_Conditional_0_For_14_Conditional_8_Template, 1, 1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](9, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](11, "p-progressBar", 14); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { const task_r4 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵclassMap"](task_r4.done ? "text-(--p-app-status-success)" : "text-primary-400"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](5, 9, "patientDetails.caching.cacheLocally"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](task_r4.done ? 7 : 8); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate"](task_r4.detail); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵstyleMap"](_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction0"](11, _c3)); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("value", task_r4.progress)("showValue", false); } } function SeriesCacheTasksComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "button", 2, 0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function SeriesCacheTasksComponent_Conditional_0_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const taskPopover_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵreference"](7); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](taskPopover_r2.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](2, "i", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](3, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](4, SeriesCacheTasksComponent_Conditional_0_Conditional_4_Template, 2, 3)(5, SeriesCacheTasksComponent_Conditional_0_Conditional_5_Template, 2, 6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](6, "p-popover", null, 1)(8, "div", 5)(9, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](12, "ul", 7); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵrepeaterCreate"](13, SeriesCacheTasksComponent_Conditional_0_For_14_Template, 12, 12, "li", 8, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()()(); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx_r2.pendingCount() === 1 ? 4 : 5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](11, 2, "patientDetails.caching.title"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵrepeater"](ctx_r2.tasks()); } } class SeriesCacheTasksComponent { cache = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_series_cache_service__WEBPACK_IMPORTED_MODULE_5__.SeriesCacheService); tasks = this.cache.tasks; pendingCount = this.cache.pendingCount; popover = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild)('taskPopover', ...(ngDevMode ? [{ debugName: "popover" }] : [])); trigger = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild)('taskButton', ...(ngDevMode ? [{ debugName: "trigger" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { if (this.cache.openRequested() === 0) return; // The anchor button only renders once a task exists. queueMicrotask(() => { const anchor = this.trigger()?.nativeElement; if (anchor) this.popover()?.show(undefined, anchor); }); }); } static ɵfac = function SeriesCacheTasksComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SeriesCacheTasksComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: SeriesCacheTasksComponent, selectors: [["lib-series-cache-tasks"]], viewQuery: function SeriesCacheTasksComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵviewQuerySignal"](ctx.popover, _c0, 5)(ctx.trigger, _c1, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵqueryAdvance"](2); } }, decls: 1, vars: 1, consts: [["taskButton", ""], ["taskPopover", ""], ["type", "button", "data-test-id", "patient-library-button-cache-tasks", 1, "hover:bg-surface-800", "ml-3", "flex", "cursor-pointer", "items-center", "gap-2", "rounded-md", "px-2.5", "py-1.5", 3, "click"], [1, "pi", "pi-spin", "pi-spinner", "text-primary-400", "text-sm"], [1, "text-sm"], [1, "w-80"], [1, "border-surface-700", "mb-2", "border-b", "pb-2", "text-sm", "font-medium"], [1, "flex", "max-h-80", "flex-col", "gap-2.5", "overflow-y-auto"], [1, "border-surface-700", "bg-surface-900/60", "rounded-lg", "border", "p-2.5"], [1, "flex", "items-center", "gap-2"], [1, "pi", "pi-cloud-download", "shrink-0", "text-sm"], [1, "truncate", "text-sm"], [1, "text-muted-color", "ml-auto", "shrink-0", "text-xs", "tabular-nums"], [1, "text-muted-color", "mt-0.5", "truncate", "text-xs"], ["styleClass", "mt-2", 3, "value", "showValue"]], template: function SeriesCacheTasksComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](0, SeriesCacheTasksComponent_Conditional_0_Template, 15, 4); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx.pendingCount() > 0 ? 0 : -1); } }, dependencies: [primeng_popover__WEBPACK_IMPORTED_MODULE_3__.PopoverModule, primeng_popover__WEBPACK_IMPORTED_MODULE_3__.Popover, primeng_progressbar__WEBPACK_IMPORTED_MODULE_4__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_4__.ProgressBar, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateModule, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 60240 /*!************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/series-cache.service.ts ***! \************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SeriesCacheService: () => (/* binding */ SeriesCacheService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 8102); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 9276); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); const DONE_LINGER_MS = 1500; function seriesKey(target) { return `${target.storeUid}::${target.seriesUid}`; } class SeriesCacheService { database = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.DicomDatabaseService); _tasks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "_tasks" }] : [])); sequence = 0; pendingCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this._tasks().filter(task => !task.done).length, ...(ngDevMode ? [{ debugName: "pendingCount" }] : [])); /** A counter rather than a flag, so a second task re-opens an already-dismissed tracker. */ openRequested = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "openRequested" }] : [])); activeTargets = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this._tasks().filter(task => !task.done).flatMap(task => task.targets), ...(ngDevMode ? [{ debugName: "activeTargets" }] : [])); activeKeys = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => new Set(this.activeTargets().map(target => seriesKey(target))), ...(ngDevMode ? [{ debugName: "activeKeys" }] : [])); trackedByStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const byStore = new Map(); for (const task of this._tasks()) { for (const { seriesUid, storeUid } of task.targets) { const seriesUids = byStore.get(storeUid); if (seriesUids) seriesUids.push(seriesUid);else byStore.set(storeUid, [seriesUid]); } } return byStore; }, ...(ngDevMode ? [{ debugName: "trackedByStore" }] : [])); // Counts come from persisted attachments, so a partly-cached series resumes at its real // position rather than restarting from zero. progress = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toObservable)(this.trackedByStore).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_7__.distinctUntilChanged)((previous, next) => signature(previous) === signature(next)), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.switchMap)(byStore => byStore.size === 0 ? (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.of)({}) : (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.combineLatest)([...byStore].map(([storeUid, seriesUids]) => this.database.streamSeriesCacheProgressBySeries(seriesUids, storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_8__.map)(bySeries => Object.fromEntries(Object.entries(bySeries).map(([seriesUid, seriesProgress]) => [seriesKey({ seriesUid, storeUid }), seriesProgress]))), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.of)({})), // combineLatest stays silent until every store's first query resolves. (0,rxjs__WEBPACK_IMPORTED_MODULE_9__.startWith)({})))).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_8__.map)(perStore => { const merged = {}; for (const chunk of perStore) Object.assign(merged, chunk); return merged; })))), { initialValue: {} }); tasks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const progress = this.progress(); return this._tasks().map(task => { let cachedCount = 0; let totalCount = 0; for (const target of task.targets) { const seriesProgress = progress[seriesKey(target)]; cachedCount += seriesProgress?.cachedCount ?? 0; totalCount += seriesProgress?.totalCount ?? 0; } const cached = totalCount ? Math.round(cachedCount / totalCount * 100) : 0; return { ...task, progress: task.done ? 100 : cached }; }); }, ...(ngDevMode ? [{ debugName: "tasks" }] : [])); requestOpen() { this.openRequested.update(count => count + 1); } // Keyed by store as well as series: the same series UID can sit in more than one store, and // caching it from one must not mark it busy in the other. isCachingSeries(target) { return this.activeKeys().has(seriesKey(target)); } /** Caches every target as one task; `detail` is the card's subtitle. */ cache(targets, detail) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const fresh = targets.filter(target => !_this.isCachingSeries(target)); if (fresh.length === 0) return; const id = `series-cache-${++_this.sequence}`; _this._tasks.update(tasks => [...tasks, { detail, done: false, id, targets: fresh }]); _this.requestOpen(); try { const results = yield Promise.allSettled(fresh.map(target => _this.database.ensureSeriesCached(target.studyUid, target.seriesUid, target.storeUid))); const failure = results.find(result => result.status === 'rejected'); if (failure) throw failure.reason; } finally { _this.settle(id); } })(); } settle(id) { this._tasks.update(tasks => tasks.map(task => task.id === id ? { ...task, done: true } : task)); setTimeout(() => this._tasks.update(tasks => tasks.filter(task => task.id !== id)), DONE_LINGER_MS); } static ɵfac = function SeriesCacheService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SeriesCacheService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: SeriesCacheService, factory: SeriesCacheService.ɵfac }); } function signature(byStore) { return [...byStore].map(([storeUid, seriesUids]) => `${storeUid}:${seriesUids}`).join('|'); } /***/ }, /***/ 54759 /*!***********************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/series-cacheability.ts ***! \***********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ hasWorkSessionInstance: () => (/* binding */ hasWorkSessionInstance), /* harmony export */ resolveSeriesValidationErrors: () => (/* binding */ resolveSeriesValidationErrors) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * CT-geometry rules a tvCT OT annotation series is exempt from: these fields are * intentionally absent from Secondary Capture OT files. */ const CT_ONLY_ERRORS = new Set(['ImageOrientationPatient is required field for all instances.', _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.MODALITY_CT_ERROR_MESSAGE, 'PixelSpacing is required field for all instances.', 'SliceThickness is required field for all instances.']); function hasWorkSessionInstance(documents) { return documents.some(document_ => { const meta = document_.toJSON().metadata; return meta !== undefined && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.isTvctWorkSessionInstance)(meta); }); } /** * Everything that stops a series being opened, and so cached. An OT series only qualifies * when its instances identify it as a tvCT analysis, plain OT is not viewable. */ function resolveSeriesValidationErrors(modality, documents) { const seriesMetadata = documents.map(document_ => document_.toJSON()); const errors = [...new Set([...(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.validateCtModality)(modality), ...(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.validateInstances)(seriesMetadata)])]; if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.normalizeModality)(modality) === 'OT' && hasWorkSessionInstance(documents)) { return errors.filter(error => !CT_ONLY_ERRORS.has(error)); } return errors; } /***/ }, /***/ 14900 /*!*********************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/patient-library/series-sort.store.ts ***! \*********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SeriesSortStore: () => (/* binding */ SeriesSortStore) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /** * Series-table sort order, kept separate from the study list's sort so switching * one never clobbers the other. Provided on PatientLibraryComponent so it outlives * PatientLibraryDetailsComponent, which is destroyed and recreated every time a * study is opened or closed. */ class SeriesSortStore { sortSpec = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "sortSpec" }] : [])); setSort(sort) { this.sortSpec.set(sort); } static ɵfac = function SeriesSortStore_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SeriesSortStore)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: SeriesSortStore, factory: SeriesSortStore.ɵfac }); } /***/ }, /***/ 80325 /*!*************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/review-dialog/review-dialog.component.ts ***! \*************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ReviewDialogComponent: () => (/* binding */ ReviewDialogComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_progressspinner__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/progressspinner */ 7271); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_textarea__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/textarea */ 25683); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../services/annotation-export-bridge.service */ 68674); /* harmony import */ var _services_dicom_export_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../services/dicom-export.service */ 8027); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/api */ 62751); function ReviewDialogComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](1, "p-progressSpinner", 6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](2, "span", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](4, 1, "dicomImporter.reviewDialog.submitting"), " "); } } function ReviewDialogComponent_Conditional_2_ng_template_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](1, "translate"); } if (rf & 2) { const item_r3 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](1, 1, "dicomImporter.reviewDialog.reasons." + item_r3.value), " "); } } function ReviewDialogComponent_Conditional_2_ng_template_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](1, "translate"); } if (rf & 2) { const selectedOption_r4 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](1, 1, "dicomImporter.reviewDialog.reasons." + selectedOption_r4.value), " "); } } function ReviewDialogComponent_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p", 15); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](2, 1, ctx), " "); } } function ReviewDialogComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](3, "div", 8)(4, "label", 9); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](7, "p-select", 10); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("ngModelChange", function ReviewDialogComponent_Conditional_2_Template_p_select_ngModelChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.onReasonCodeChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](9, ReviewDialogComponent_Conditional_2_ng_template_9_Template, 2, 3, "ng-template", 11)(10, ReviewDialogComponent_Conditional_2_ng_template_10_Template, 2, 3, "ng-template", 12); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](11, "div", 8)(12, "label", 13); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](13); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](14, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](15, "textarea", 14); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](16, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("ngModelChange", function ReviewDialogComponent_Conditional_2_Template_textarea_ngModelChange_15_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.onCommentChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](17, ReviewDialogComponent_Conditional_2_Conditional_17_Template, 3, 3, "p", 15); } if (rf & 2) { let tmp_9_0; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](2, 9, "dicomImporter.reviewDialog.description"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](6, 11, "dicomImporter.reviewDialog.reasonLabel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("options", ctx_r1.reasonCodes)("ngModel", ctx_r1.reasonCode())("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](8, 13, "dicomImporter.reviewDialog.reasonPlaceholder")); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](14, 15, "dicomImporter.reviewDialog.commentLabel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("ngModel", ctx_r1.comment())("placeholder", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](16, 17, "dicomImporter.reviewDialog.commentPlaceholder")); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"]((tmp_9_0 = ctx_r1.validationError()) ? 17 : -1, tmp_9_0); } } /** Approve/reject dialog for the open OT session; writes a new reviewed instance into the same series. */ class ReviewDialogComponent { ref = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__.DynamicDialogRef); exportService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_11__.DicomExportService); bridge = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_10__.AnnotationExportBridge); auth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.AuthService); state = this.exportService.state; comment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)('', ...(ngDevMode ? [{ debugName: "comment" }] : [])); reasonCode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "reasonCode" }] : [])); /** Set when a rejection is submitted incomplete; cleared as soon as the reviewer edits. */ validationError = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "validationError" }] : [])); reasonCodes = [{ value: 'R1' }, { value: 'R2' }, { value: 'R3' }, { value: 'R4' }, { value: 'R5' }, { value: 'R6' }, { value: 'R7' }, { value: 'R8' }, { value: 'R9' }]; onSubmit(status) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const context = _this.bridge.reviewContext(); const user = _this.auth.currentUser(); // Nothing to submit against - not recoverable from inside the dialog. if (!context || !user) { _this.ref.close(); return; } // Recoverable: hold the dialog open so the reviewer can complete it rather than // silently discarding what they had already entered. const rejectionError = _this.rejectionError(status); if (rejectionError) { _this.validationError.set(rejectionError); return; } _this.validationError.set(undefined); try { const protocolFormValues = _this.bridge.protocolFormValues(); yield _this.exportService.reviewSeriesToStore({ annotations: _this.bridge.annotations(), comment: _this.comment().trim(), context, protocolBindings: _this.bridge.protocolBindings(), ...(protocolFormValues ? { protocolFormValues } : {}), ...(status === 'REJECTED' ? { reasonCode: _this.reasonCode() } : {}), reviewerName: _this.bridge.author, reviewerUserId: _this.bridge.authorUserId, status }); _this.ref.close({ messageKey: 'dicomImporter.reviewDialog.toast.success', severity: 'success' }); } catch (error) { _this.ref.close({ detail: error.message, messageKey: 'dicomImporter.reviewDialog.toast.error', severity: 'error' }); } })(); } /** Clears the error the moment either input changes, so it never contradicts the form. */ onReasonCodeChange(reasonCode) { this.reasonCode.set(reasonCode); this.validationError.set(undefined); } onCommentChange(comment) { this.comment.set(comment); this.validationError.set(undefined); } rejectionError(status) { if (status !== 'REJECTED') return; if (!this.reasonCode()) return 'dicomImporter.reviewDialog.error.reasonRequired'; if (this.reasonCode() === 'R9' && !this.comment().trim()) { return 'dicomImporter.reviewDialog.error.commentRequiredForOther'; } return undefined; } onCancel() { this.ref.close(); } static ɵfac = function ReviewDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ReviewDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵdefineComponent"]({ type: ReviewDialogComponent, selectors: [["lib-review-dialog"]], features: [_angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵProvidersFeature"]([_services_dicom_export_service__WEBPACK_IMPORTED_MODULE_11__.DicomExportService])], decls: 13, vars: 13, consts: [[1, "flex", "flex-col", "gap-6", "p-4"], [1, "flex", "flex-col", "items-center", "gap-3", "py-4"], [1, "flex", "justify-end", "gap-2"], ["data-test-id", "review-dialog-p-button-cancel", "severity", "secondary", "outlined", "", 3, "click", "disabled"], ["data-test-id", "review-dialog-p-button-reject", "severity", "danger", "outlined", "", 3, "click", "disabled"], ["data-test-id", "review-dialog-p-button-approve", 3, "click", "disabled"], ["strokeWidth", "4", 1, "size-12"], [1, "text-muted-color", "text-sm"], [1, "flex", "flex-col", "gap-2"], ["for", "review-reason", 1, "text-sm", "font-medium"], ["inputId", "review-reason", "data-test-id", "review-dialog-p-select-reason", "optionValue", "value", 3, "ngModelChange", "options", "ngModel", "placeholder"], ["pTemplate", "item"], ["pTemplate", "selectedItem"], ["for", "review-comment", 1, "text-sm", "font-medium"], ["id", "review-comment", "data-test-id", "review-dialog-textarea-comment", "pTextarea", "", "fluid", "", "rows", "3", 3, "ngModelChange", "ngModel", "placeholder"], ["data-test-id", "review-dialog-p-validation-error", "role", "alert", 1, "text-sm", "text-(--p-app-status-danger)"]], template: function ReviewDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 0); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](1, ReviewDialogComponent_Conditional_1_Template, 5, 3, "div", 1)(2, ReviewDialogComponent_Conditional_2_Template, 18, 19); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](3, "div", 2)(4, "p-button", 3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function ReviewDialogComponent_Template_p_button_click_4_listener() { return ctx.onCancel(); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](7, "p-button", 4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function ReviewDialogComponent_Template_p_button_click_7_listener() { return ctx.onSubmit("REJECTED"); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](10, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function ReviewDialogComponent_Template_p_button_click_10_listener() { return ctx.onSubmit("APPROVED"); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](11); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.state() === "exporting" ? 1 : 2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("disabled", ctx.state() === "exporting"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](6, 7, "common.cancel"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("disabled", ctx.state() === "exporting"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](9, 9, "dicomImporter.reviewDialog.reject"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("disabled", ctx.state() === "exporting"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](12, 11, "dicomImporter.reviewDialog.approve"), " "); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_4__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_4__.Button, primeng_api__WEBPACK_IMPORTED_MODULE_13__.PrimeTemplate, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgModel, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_6__.ProgressSpinnerModule, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_6__.ProgressSpinner, primeng_select__WEBPACK_IMPORTED_MODULE_7__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_7__.Select, primeng_textarea__WEBPACK_IMPORTED_MODULE_8__.TextareaModule, primeng_textarea__WEBPACK_IMPORTED_MODULE_8__.Textarea, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateModule, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 92729 /*!***********************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/review-status-icon/review-status-icon.component.ts ***! \***********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ReviewStatusIconComponent: () => (/* binding */ ReviewStatusIconComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core */ 14975); function ReviewStatusIconComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementStart"](0, "span", 1); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelement"](3, "lib-icon", 2); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵelementEnd"](); } if (rf & 2) { const d_r1 = ctx; _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵclassMap"](d_r1.colorClass); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipeBind1"](1, 5, d_r1.labelKey)); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵpipeBind1"](2, 7, d_r1.labelKey)); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵproperty"]("icon", d_r1.icon); } } /** Shared tri-state review indicator (study library, Study Series table, instance picker). */ class ReviewStatusIconComponent { status = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "status" }] : [])); display = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { switch (this.status()) { case 'approved': { return { colorClass: 'text-(--p-app-review-approved)', icon: 'check', labelKey: 'reviewStatus.approved' }; } case 'rejected': { return { colorClass: 'text-(--p-app-review-rejected)', icon: 'times', labelKey: 'reviewStatus.rejected' }; } case 'unapproved': { return { colorClass: 'text-(--p-app-review-pending)', icon: 'clock', labelKey: 'reviewStatus.unapproved' }; } default: { return; } } }, ...(ngDevMode ? [{ debugName: "display" }] : [])); static ɵfac = function ReviewStatusIconComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ReviewStatusIconComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵdefineComponent"]({ type: ReviewStatusIconComponent, selectors: [["lib-review-status-icon"]], inputs: { status: [1, "status"] }, decls: 1, vars: 1, consts: [["role", "img", "tooltipPosition", "top", 3, "class", "pTooltip"], ["role", "img", "tooltipPosition", "top", 3, "pTooltip"], [3, "icon"]], template: function ReviewStatusIconComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵconditionalCreate"](0, ReviewStatusIconComponent_Conditional_0_Template, 4, 9, "span", 0); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_5__["ɵɵconditional"]((tmp_0_0 = ctx.display()) ? 0 : -1, tmp_0_0); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__.IconComponent, primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_3__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 88507 /*!***************************************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/components/work-session-library/work-session-library.component.ts ***! \***************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionLibraryComponent: () => (/* binding */ WorkSessionLibraryComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 84356); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 8102); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxjs */ 9276); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! rxjs */ 45541); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ "min-width": "70rem", "table-layout": "fixed" }); function WorkSessionLibraryComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", ctx_r1.error(), " "); } } function WorkSessionLibraryComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "tr")(1, "th", 15); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](4, "th", 15); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](7, "th", 15); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](10, "th", 16); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](11); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](13, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](14); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](15, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](16, "th", 17); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](19, "th", 18); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](20, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](21, "lib-icon", 19); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](22, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](23, "th", 20); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](25, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](3, 9, "dicomImporter.workSessions.table.session")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](6, 11, "dicomImporter.workSessions.table.patientName"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](9, 13, "dicomImporter.workSessions.table.store")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](12, 15, "dicomImporter.workSessions.table.modality")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](15, 17, "dicomImporter.workSessions.table.description"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](18, 19, "dicomImporter.workSessions.table.updatedAt"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](20, 21, "dicomImporter.workSessions.table.localCache")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](22, 23, "dicomImporter.workSessions.table.localCache")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](25, 25, "dicomImporter.workSessions.table.actions"), " "); } } function WorkSessionLibraryComponent_ng_template_4_Conditional_23_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "span", 24); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](2, "lib-icon", 32); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](1, 2, "dicomImporter.workSessions.cachedLocally")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](3, 4, "dicomImporter.workSessions.cachedLocally")); } } function WorkSessionLibraryComponent_ng_template_4_Conditional_24_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "div", 25); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](1, "p-progressBar", 33); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const cache_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](22); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("showValue", false)("value", cache_r6.percent); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate2"]("", cache_r6.cachedCount, "/", cache_r6.totalCount); } } function WorkSessionLibraryComponent_ng_template_4_Conditional_25_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "div", 26)(1, "span", 34); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](3, "p-button", 35); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵlistener"]("click", function WorkSessionLibraryComponent_ng_template_4_Conditional_25_Template_p_button_click_3_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const row_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.cacheRow(row_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](5, "lib-icon", 36); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const row_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](2, 3, "dicomImporter.workSessions.cacheLocally")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](4, 5, "dicomImporter.workSessions.cacheLocally"))("disabled", ctx_r1.loading() || ctx_r1.isCaching(row_r4)); } } function WorkSessionLibraryComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵdeclareLet"](0); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](1, "tr", 21); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵlistener"]("contextmenu", function WorkSessionLibraryComponent_ng_template_4_Template_tr_contextmenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const row_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const rowMenuContext_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](9); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.rowMenu.openAtPointer(rowMenuContext_r5, $event, row_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](2, "td", 22, 2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](5, "td", 22, 3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](8, "td", 22, 4); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](11, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](12); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](13, "td", 22, 5); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](15); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](16, "td", 22, 6); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](18, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](19); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](20, "dicomDate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](21, "td", 23); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵdeclareLet"](22); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵconditionalCreate"](23, WorkSessionLibraryComponent_ng_template_4_Conditional_23_Template, 4, 6, "span", 24)(24, WorkSessionLibraryComponent_ng_template_4_Conditional_24_Template, 4, 4, "div", 25)(25, WorkSessionLibraryComponent_ng_template_4_Conditional_25_Template, 6, 7, "div", 26); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](26, "td")(27, "div", 27)(28, "p-button", 28); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](29, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵlistener"]("click", function WorkSessionLibraryComponent_ng_template_4_Template_p_button_click_28_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const row_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.open(row_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](30, "lib-icon", 29); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](31, "p-button", 30); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](32, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵlistener"]("click", function WorkSessionLibraryComponent_ng_template_4_Template_p_button_click_31_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const row_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreadContextLet"](0); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const rowMenuPopup_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](7); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.rowMenu.openFromButton(rowMenuPopup_r8, $event, row_r4)); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](33, "lib-icon", 31); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()()()(); } if (rf & 2) { const rawRow_r9 = ctx.$implicit; const nameTip_r10 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](3); const patientNameTip_r11 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](6); const storeTip_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](9); const descriptionTip_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](14); const updatedAtTip_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵreference"](17); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵnextContext"](); const row_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵstoreLet"](ctx_r1.asRow(rawRow_r9)); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pSelectableRow", row_r15); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", nameTip_r10.truncated() ? row_r15.name : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", row_r15.name, " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", patientNameTip_r11.truncated() ? row_r15.patientName : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", row_r15.patientName, " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", storeTip_r12.truncated() ? row_r15.storeName : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", row_r15.storeName, " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate"](row_r15.modality); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", descriptionTip_r13.truncated() ? row_r15.seriesDescription : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", row_r15.seriesDescription, " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("pTooltip", updatedAtTip_r14.truncated() ? _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind2"](18, 17, row_r15.updatedAt, true) ?? row_r15.updatedAt : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind2"](20, 20, row_r15.updatedAt, true) ?? row_r15.updatedAt, " "); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); const cache_r16 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵstoreLet"](ctx_r1.progressFor(row_r15)); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵconditional"](ctx_r1.isFullyCached(row_r15) ? 23 : ctx_r1.isCaching(row_r15) || cache_r16.cachedCount > 0 ? 24 : 25); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("disabled", ctx_r1.loading() || ctx_r1.isActive(row_r15))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](29, 24, "dicomImporter.workSessions.menu.view")); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](32, 26, "dicomImporter.workSessions.table.actions")); } } function WorkSessionLibraryComponent_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "tr")(1, "td", 37); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpipeBind1"](3, 1, "dicomImporter.workSessions.empty")); } } const NO_CACHE_PROGRESS = { cachedCount: 0, percent: 0, totalCount: 0 }; class WorkSessionLibraryComponent { workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_23__.WorkSessionDatabaseService); dicomDatabase = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_23__.DicomDatabaseService); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_23__.DicomStoreListService); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_4__.Router); confirmationService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_15__.ConfirmationService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__.TranslateService); dialogRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_18__.DynamicDialogRef, { optional: true }); loading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(true, ...(ngDevMode ? [{ debugName: "loading" }] : [])); error = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "error" }] : [])); rows = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)(this.workSessionDb.workSessions$({}).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_13__.tap)(() => { this.loading.set(true); this.error.set(undefined); }), (0,rxjs__WEBPACK_IMPORTED_MODULE_12__.switchMap)(sessions => (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.from)(this.buildRows(sessions)).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_13__.tap)(() => this.loading.set(false)), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.catchError)(error => { this.error.set(error.message ?? String(error)); this.loading.set(false); return (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.of)([]); })))), { initialValue: [] }); activeWorkSessionUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(undefined, ...(ngDevMode ? [{ debugName: "activeWorkSessionUid" }] : [])); rowMenu = new _tomoverse_ui__WEBPACK_IMPORTED_MODULE_24__.RowMenuController(row => this.buildRowMenuItems(row)); cachingSeries = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)({}, ...(ngDevMode ? [{ debugName: "cachingSeries" }] : [])); seriesKey(row) { return `${row.storeUid}::${row.seriesUid}`; } isCaching(row) { return !!this.cachingSeries()[this.seriesKey(row)]; } groupSeriesByStore(rows) { const byStore = new Map(); for (const row of rows) { const seriesUids = byStore.get(row.storeUid) ?? new Set(); seriesUids.add(row.seriesUid); byStore.set(row.storeUid, seriesUids); } return new Map([...byStore].toSorted(([a], [b]) => a.localeCompare(b)).map(([storeUid, seriesUids]) => [storeUid, [...seriesUids].toSorted()])); } cacheProgress = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toObservable)(this.rows).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(rows => this.groupSeriesByStore(rows)), (0,rxjs__WEBPACK_IMPORTED_MODULE_9__.distinctUntilChanged)((previous, next) => this.seriesSetSignature(previous) === this.seriesSetSignature(next)), (0,rxjs__WEBPACK_IMPORTED_MODULE_12__.switchMap)(byStore => byStore.size === 0 ? (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.of)({}) : (0,rxjs__WEBPACK_IMPORTED_MODULE_5__.combineLatest)([...byStore].map(([storeUid, seriesUids]) => this.dicomDatabase.streamSeriesCacheProgressBySeries(seriesUids, storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(bySeries => Object.fromEntries(Object.entries(bySeries).map(([seriesUid, progress]) => [this.seriesKey({ seriesUid, storeUid }), progress]))), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.of)({})), (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.startWith)({})))).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(perStore => { const merged = {}; for (const chunk of perStore) Object.assign(merged, chunk); return merged; })))), { initialValue: {} }); seriesSetSignature(byStore) { return [...byStore].map(([storeUid, seriesUids]) => `${storeUid}:${seriesUids}`).join('|'); } progressFor(row) { return this.cacheProgress()[this.seriesKey(row)] ?? NO_CACHE_PROGRESS; } isFullyCached(row) { return (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_23__.isSeriesFullyCached)(this.progressFor(row)); } rowClickedRow = undefined; lastClickedRowUid = undefined; lastClickAtMs = 0; doubleClickThresholdMs = 300; open(row) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this.isActive(row)) return; _this.dialogRef?.close(); yield _this.router.navigate(['/volume-viewer', row.storeUid, row.studyUid, row.seriesUid, row.uid]); })(); } onRowSelect(event) { const row = Array.isArray(event?.data) ? event.data[0] : event?.data; const uid = row?.uid; const now = Date.now(); const isDoubleClick = uid !== undefined && uid === this.lastClickedRowUid && now - this.lastClickAtMs <= this.doubleClickThresholdMs; if (isDoubleClick) { this.lastClickedRowUid = undefined; this.lastClickAtMs = 0; if (row && !this.loading() && !this.isActive(row)) { this.open(row); } return; } this.lastClickedRowUid = uid; this.lastClickAtMs = now; } deleteRow(row) { var _this2 = this; if (this.isActive(row)) return; this.confirmationService.confirm({ accept: function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { yield _this2.workSessionDb.delete(row.uid); } catch (error) { _this2.error.set(error.message ?? String(error)); } }); return function accept() { return _ref.apply(this, arguments); }; }(), acceptButtonProps: { label: this.translate.instant('dicomImporter.workSessions.deleteSession.acceptLabel'), severity: 'danger' }, header: this.translate.instant('dicomImporter.workSessions.deleteSession.header'), icon: 'exclamation-triangle', message: this.translate.instant('dicomImporter.workSessions.deleteSession.message'), rejectButtonProps: { label: this.translate.instant('dicomImporter.workSessions.deleteSession.rejectLabel'), severity: 'secondary', text: true } }); } cacheRow(row) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const key = _this3.seriesKey(row); if (_this3.cachingSeries()[key]) return; _this3.cachingSeries.update(state => ({ ...state, [key]: true })); try { yield _this3.dicomDatabase.ensureSeriesCached(row.studyUid, row.seriesUid, row.storeUid); } catch (error) { _this3.error.set(error.message ?? String(error)); } finally { _this3.cachingSeries.update(({ [key]: _finished, ...rest }) => rest); } })(); } buildRowMenuItems(row) { return [{ command: () => this.open(row), disabled: this.loading() || this.isActive(row), icon: 'pi pi-box', label: this.translate.instant('dicomImporter.workSessions.menu.view') }, { separator: true }, { command: () => this.cacheRow(row), disabled: this.isCaching(row) || this.isFullyCached(row), icon: 'pi pi-cloud-download', label: this.translate.instant('dicomImporter.workSessions.menu.cache') }, { separator: true }, (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_24__.dangerMenuItem)({ command: () => this.deleteRow(row), disabled: this.loading() || this.isActive(row), icon: 'pi pi-trash', label: this.translate.instant('dicomImporter.workSessions.delete') })]; } asRow(value) { return value; } isActive(row) { return row.uid === this.activeWorkSessionUid(); } buildRows(sessions) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const metadataCache = new Map(); const sorted = sessions.toSorted((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()); const storeNamesByUid = yield _this4.resolveStoreNames(); const rows = yield Promise.all(sorted.map(/*#__PURE__*/function () { var _ref2 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (session) { const key = `${session.studyUid}::${session.seriesUid}`; if (!metadataCache.has(key)) { try { const metadata = yield _this4.dicomDatabase.getSeriesCommonMetadata(session.studyUid, session.seriesUid, session.storeUid); metadataCache.set(key, metadata); } catch { metadataCache.set(key, undefined); } } const metadata = metadataCache.get(key); return { modality: metadata?.modality ?? 'Unknown', name: session.name, patientName: metadata?.patientName ?? 'Unknown', seriesDescription: metadata?.seriesDescription ?? metadata?.studyDescription ?? 'Unknown', seriesUid: session.seriesUid, storeName: storeNamesByUid.get(session.storeUid) ?? session.storeUid, storeUid: session.storeUid, studyUid: session.studyUid, uid: session.uid, updatedAt: session.updatedAt }; }); return function (_x) { return _ref2.apply(this, arguments); }; }())); return [...rows]; })(); } resolveStoreNames() { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const stores = yield _this5.storeList.getEnabledStores(); return new Map(stores.map(store => [store.uid, store.name])); } catch { return new Map(); } })(); } static ɵfac = function WorkSessionLibraryComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionLibraryComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵdefineComponent"]({ type: WorkSessionLibraryComponent, selectors: [["lib-work-session-library"]], inputs: { activeWorkSessionUid: [1, "activeWorkSessionUid"] }, decls: 10, vars: 9, consts: [["rowMenuPopup", ""], ["rowMenuContext", ""], ["nameTip", "libEllipsisTip"], ["patientNameTip", "libEllipsisTip"], ["storeTip", "libEllipsisTip"], ["descriptionTip", "libEllipsisTip"], ["updatedAtTip", "libEllipsisTip"], [1, "flex", "h-full", "min-h-0", "flex-col", "py-4"], [1, "border-destructive/30", "bg-destructive/10", "text-destructive", "mx-4", "mb-4", "shrink-0", "rounded-md", "border", "px-3", "py-2"], ["dataKey", "uid", "selectionMode", "single", "scrollable", "", "scrollHeight", "flex", 1, "library-table", "min-h-0", "flex-1", 3, "selectionChange", "onRowSelect", "value", "loading", "tableStyle", "selection", "metaKeySelection"], ["pTemplate", "header"], ["pTemplate", "body"], ["pTemplate", "emptymessage"], ["data-test-id", "work-session-library-p-menu-row", "popup", "", "appendTo", "body", 3, "model"], ["data-test-id", "work-session-library-p-contextmenu-row", "appendTo", "body", 3, "model"], [1, "w-[10rem]"], [1, "w-[6.875rem]"], [1, "w-[11.5625rem]"], ["tooltipPosition", "top", 1, "w-[3.125rem]", "text-center", "whitespace-nowrap", 3, "pTooltip"], ["icon", "cloud-download", 1, "text-muted-color"], [1, "w-[8.4375rem]", "text-center"], [3, "contextmenu", "pSelectableRow"], ["libEllipsisTip", "", "tooltipPosition", "top", 3, "pTooltip"], [1, "text-center"], ["tooltipPosition", "top", 1, "text-muted-color", "inline-flex", "cursor-default", 3, "pTooltip"], [1, "text-muted-color", "flex", "items-center", "justify-center", "text-xs"], [1, "flex", "items-center", "justify-center", "gap-2"], [1, "flex", "items-center", "justify-end", "gap-2"], ["data-test-id", "work-session-library-p-button-open", "size", "small", "rounded", "", "text", "", "styleClass", "h-[30px] w-[30px] p-0", 3, "click", "disabled", "ariaLabel"], ["icon", "eye", 1, "size-(--p-app-icon-size-xs)"], ["data-test-id", "work-session-library-p-button-row-menu", "severity", "secondary", "size", "small", "text", "", 3, "click", "ariaLabel"], ["icon", "ellipsis-v"], ["icon", "check-circle"], [1, "mr-2", "h-2", "w-16", 3, "showValue", "value"], ["tooltipPosition", "top", 1, "inline-flex", 3, "pTooltip"], ["data-test-id", "work-session-library-p-button-cache", "severity", "secondary", "rounded", "", "text", "", "size", "small", "styleClass", "h-[30px] w-[30px] p-0", 3, "click", "ariaLabel", "disabled"], ["icon", "cloud-download", 1, "size-(--p-app-icon-size-xs)"], ["colspan", "8"]], template: function WorkSessionLibraryComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](0, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵconditionalCreate"](1, WorkSessionLibraryComponent_Conditional_1_Template, 2, 1, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementStart"](2, "p-table", 9); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtwoWayListener"]("selectionChange", function WorkSessionLibraryComponent_Template_p_table_selectionChange_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtwoWayBindingSet"](ctx.rowClickedRow, $event) || (ctx.rowClickedRow = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵlistener"]("onRowSelect", function WorkSessionLibraryComponent_Template_p_table_onRowSelect_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.onRowSelect($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtemplate"](3, WorkSessionLibraryComponent_ng_template_3_Template, 26, 27, "ng-template", 10)(4, WorkSessionLibraryComponent_ng_template_4_Template, 34, 28, "ng-template", 11)(5, WorkSessionLibraryComponent_ng_template_5_Template, 4, 3, "ng-template", 12); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵelement"](6, "p-menu", 13, 0)(8, "p-contextmenu", 14, 1); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵconditional"](ctx.error() ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("value", ctx.rows())("loading", ctx.loading())("tableStyle", _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵpureFunction0"](8, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵtwoWayProperty"]("selection", ctx.rowClickedRow); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("metaKeySelection", true); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("model", ctx.rowMenu.items()); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_26__["ɵɵproperty"]("model", ctx.rowMenu.items()); } }, dependencies: [primeng_table__WEBPACK_IMPORTED_MODULE_21__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_21__.Table, primeng_api__WEBPACK_IMPORTED_MODULE_15__.PrimeTemplate, primeng_table__WEBPACK_IMPORTED_MODULE_21__.SelectableRow, primeng_button__WEBPACK_IMPORTED_MODULE_16__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_16__.Button, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_17__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_17__.ContextMenu, primeng_menu__WEBPACK_IMPORTED_MODULE_19__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_19__.Menu, primeng_progressbar__WEBPACK_IMPORTED_MODULE_20__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_20__.ProgressBar, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__.TranslateModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_22__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_22__.Tooltip, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_24__.EllipsisTipDirective, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_24__.IconComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__.TranslatePipe, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_25__.DicomDatePipe], encapsulation: 2 }); } /***/ }, /***/ 68674 /*!******************************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/services/annotation-export-bridge.service.ts ***! \******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationExportBridge: () => (/* binding */ AnnotationExportBridge), /* harmony export */ buildProtocolBindings: () => (/* reexport safe */ _protocol_binding_utils__WEBPACK_IMPORTED_MODULE_3__.buildProtocolBindings), /* harmony export */ rebuildProtocolState: () => (/* reexport safe */ _protocol_binding_utils__WEBPACK_IMPORTED_MODULE_3__.rebuildProtocolState) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _protocol_binding_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./protocol-binding-utils */ 59639); /** Root bridge: the volume viewer shares annotation/protocol snapshots here for the export/review dialogs. */ class AnnotationExportBridge { auth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.AuthService); annotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "annotations" }] : [])); protocolBindings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "protocolBindings" }] : [])); protocolFormValues = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "protocolFormValues" }] : [])); reviewComment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('', ...(ngDevMode ? [{ debugName: "reviewComment" }] : [])); workSessionName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('', ...(ngDevMode ? [{ debugName: "workSessionName" }] : [])); sourceInstanceUIDs = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "sourceInstanceUIDs" }] : [])); activePhaseLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('', ...(ngDevMode ? [{ debugName: "activePhaseLabel" }] : [])); renderSettings2D = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "renderSettings2D" }] : [])); renderSettings3D = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "renderSettings3D" }] : [])); capturePreview = undefined; /** Set when the session was opened from an existing OT; undefined for fresh sessions. */ reviewContext = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "reviewContext" }] : [])); dirtySinceOpen = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "dirtySinceOpen" }] : [])); /** Current user's stable id (accountId). */ get authorUserId() { return this.auth.currentUser()?.accountId ?? ''; } get author() { const user = this.auth.currentUser(); if (!user) return ''; return [user.name, user.lastName].filter(Boolean).join(' ').trim() || user.email; } /** Reviewable OT open, reviewer ≠ annotator, and annotations unchanged since open. */ canReview = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const context = this.reviewContext(); if (!context) return false; if (this.dirtySinceOpen()) return false; return this.authorUserId !== context.creatorUserId; }, ...(ngDevMode ? [{ debugName: "canReview" }] : [])); static ɵfac = function AnnotationExportBridge_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationExportBridge)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: AnnotationExportBridge, factory: AnnotationExportBridge.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 19462 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/services/dicom-annotation-codec.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ buildScOtDicom: () => (/* binding */ buildScOtDicom), /* harmony export */ deserializeAnnotationPayload: () => (/* binding */ deserializeAnnotationPayload), /* harmony export */ extractAnnotationTags: () => (/* binding */ extractAnnotationTags), /* harmony export */ readDicomModality: () => (/* binding */ readDicomModality), /* harmony export */ readDicomStringTag: () => (/* binding */ readDicomStringTag), /* harmony export */ serializeAnnotationPayload: () => (/* binding */ serializeAnnotationPayload) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var dicom_parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! dicom-parser */ 99564); /* harmony import */ var dicom_parser__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(dicom_parser__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); // --------------------------------------------------------------------------- // Compression helpers (Web Streams API — available in all modern browsers) // --------------------------------------------------------------------------- function gzipBytes(_x) { return _gzipBytes.apply(this, arguments); } function _gzipBytes() { _gzipBytes = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (input) { const cs = new CompressionStream('gzip'); const writer = cs.writable.getWriter(); writer.write(input); writer.close(); return collectStream(cs.readable); }); return _gzipBytes.apply(this, arguments); } function gunzipBytes(_x2) { return _gunzipBytes.apply(this, arguments); } function _gunzipBytes() { _gunzipBytes = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (input) { const ds = new DecompressionStream('gzip'); const writer = ds.writable.getWriter(); // Suppress writable-side rejections — the error surfaces on the readable side via collectStream. writer.write(input).catch(() => { /* surfaces on readable side */ }); writer.close().catch(() => { /* surfaces on readable side */ }); return collectStream(ds.readable); }); return _gunzipBytes.apply(this, arguments); } function collectStream(_x3) { return _collectStream.apply(this, arguments); } // --------------------------------------------------------------------------- // Serialize / deserialize // --------------------------------------------------------------------------- /** Serialize the annotation payload to gzip-compressed JSON bytes. */ function _collectStream() { _collectStream = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (stream) { const chunks = []; const reader = stream.getReader(); for (;;) { const { done, value } = yield reader.read(); if (done) break; if (value) chunks.push(value); } const total = chunks.reduce((sum, c) => sum + c.length, 0); const out = new Uint8Array(total); let offset = 0; for (const chunk of chunks) { out.set(chunk, offset); offset += chunk.length; } return out; }); return _collectStream.apply(this, arguments); } function serializeAnnotationPayload(_x4) { return _serializeAnnotationPayload.apply(this, arguments); } /** Deserialize gzip-compressed JSON bytes back to an annotation payload. */ function _serializeAnnotationPayload() { _serializeAnnotationPayload = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (payload) { const json = new TextEncoder().encode(JSON.stringify(payload)); return gzipBytes(json); }); return _serializeAnnotationPayload.apply(this, arguments); } function deserializeAnnotationPayload(_x5) { return _deserializeAnnotationPayload.apply(this, arguments); } /** Tag key in dcmjs' 8-hex-digit uppercase form, e.g. (0008,0060) → "00080060". */ function _deserializeAnnotationPayload() { _deserializeAnnotationPayload = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (bytes) { let raw; try { raw = yield gunzipBytes(bytes); } catch { // Retry without the DICOM OB even-alignment null padding byte appended on write. raw = yield gunzipBytes(bytes.slice(0, -1)); } return _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__.annotationPayloadSchema.parse(JSON.parse(new TextDecoder().decode(raw))); }); return _deserializeAnnotationPayload.apply(this, arguments); } function tagKey(group, element) { return (group * 0x1_00_00 + element).toString(16).padStart(8, '0').toUpperCase(); } /** Build one denaturalized element. Empty strings stay as `['']` so Type-2 tags are written zero-length. */ function makeElement(vr, ...values) { return { Value: values, vr }; } /** OB element whose value is an exact-length copy of the bytes (dcmjs pads to even length on write). */ function makeObElement(data) { return { Value: [data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)], vr: 'OB' }; } // --------------------------------------------------------------------------- // Timezone offset helper // --------------------------------------------------------------------------- function formatTimezoneOffset() { const offsetMinutes = new Date().getTimezoneOffset(); const sign = offsetMinutes <= 0 ? '+' : '-'; const abs = Math.abs(offsetMinutes); const hh = Math.floor(abs / 60).toString().padStart(2, '0'); const mm = (abs % 60).toString().padStart(2, '0'); return `${sign}${hh}${mm}`; } // --------------------------------------------------------------------------- // SHA-256 helper // --------------------------------------------------------------------------- function sha256Hex(_x6) { return _sha256Hex.apply(this, arguments); } function _sha256Hex() { _sha256Hex = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (data) { const hashBuffer = yield crypto.subtle.digest('SHA-256', data); return [...new Uint8Array(hashBuffer)].map(b => b.toString(16).padStart(2, '0')).join(''); }); return _sha256Hex.apply(this, arguments); } function resolvePatientTagFallbacks(options) { return { accessionNumber: options.accessionNumber ?? '', patientBirthDate: options.patientBirthDate ?? '', patientID: options.patientID ?? '', patientName: options.patientName ?? '', patientSex: options.patientSex ?? '', studyDate: options.studyDate ?? '', studyDescription: options.studyDescription ?? '', studyID: options.studyID ?? '', studyTime: options.studyTime ?? '' }; } function resolveSeriesTagFallbacks(options, date, time) { return { seriesDate: options.seriesDate ?? date, seriesNumber: options.seriesNumber ?? 1, seriesTime: options.seriesTime ?? time }; } const SC_SOP_CLASS = '1.2.840.10008.5.1.4.1.1.7'; const EXPLICIT_VR_LE = '1.2.840.10008.1.2.1'; const IMPL_CLASS_UID = '1.3.6.1.4.1.66095.1.1.1'; const IMPL_VERSION = 'TVCT_DCM_1_0'; const PRIVATE_CREATOR = 'TOMOVERSE_TVCT_1'; const CT_SOP_CLASS = '1.2.840.10008.5.1.4.1.1.2'; const PRIVATE_TAG_PHASE_LABEL = 0x10_19; const PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION = 0x10_1a; const PRIVATE_TAG_SOURCE_INSTANCE_UIDS = 0x10_1b; const PRIVATE_TAG_SOURCE_SERIES_UID = 0x10_1c; const LEGACY_PRIVATE_TAG_SOURCE_INSTANCE_UIDS = 0x10_1a; const LEGACY_PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION = 0x10_1b; /** * Build a complete DICOM Part 10 file (Secondary Capture, OT modality) from scratch. * Contains a 1×1 black RGB placeholder pixel and the TVCT annotation payload in a * chunked private SQ at group 0029 (creator TOMOVERSE_TVCT_1). */ function buildScOtDicom(_x7) { return _buildScOtDicom.apply(this, arguments); } // --------------------------------------------------------------------------- // DICOM read helpers (dicom-parser) // // The exported OT file carries a standard Part-10 file-meta group, so we read it // back with dicom-parser's public `parseDicom`, which transparently handles the // undefined-length sequences dcmjs emits. Callers may pass arbitrary buffers, so // unparseable input resolves to `undefined` rather than throwing. // --------------------------------------------------------------------------- /** Tag lookup key in dicom-parser's `xggggeeee` form, e.g. (0008,0060) → "x00080060". */ function _buildScOtDicom() { _buildScOtDicom = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (options) { const { author = '', authorUserId = '', instanceCreationDate, instanceCreationTime, payload, payloadSchemaVersion, phaseLabel = '', reviewComment = '', reviewDate = '', reviewDateTime = '', reviewerName = '', reviewerUserId = '', reviewReasonCode = '', reviewStatus = 'UNAPPROVED', reviewTime = '', seriesDescription, seriesInstanceUID, softwareVersion, sopInstanceUID, sourceInstanceUIDs, sourceSeriesDescription = '', sourceSeriesUID, studyInstanceUID, workSessionRevision, workSessionUID } = options; // ── 1. Serialize + compress payload ─────────────────────────────────────── const fullPayload = { ...payload, sourceInstanceUIDs, sourceSeriesUID }; const jsonBytes = new TextEncoder().encode(JSON.stringify(fullPayload)); const originalLength = jsonBytes.length; const compressedBytes = yield gzipBytes(jsonBytes); // Pad to even length so (0029,1023) == OB element length (DICOM OB padding rule). // gzip ignores trailing bytes beyond the end-of-stream marker on decompression. const storedBytes = compressedBytes.length % 2 === 0 ? compressedBytes : new Uint8Array([...compressedBytes, 0x00]); const sha256 = yield sha256Hex(storedBytes); // ── 2. Build the chunked private payload sequence (0029,1009) ───────────── // Single chunk today; the reader reassembles by chunk index so multi-chunk // payloads remain forward-compatible. const payloadSq = makeElement('SQ', { [tagKey(0x00_29, 0x00_10)]: makeElement('LO', PRIVATE_CREATOR), [tagKey(0x00_29, 0x10_21)]: makeElement('UL', 0), [tagKey(0x00_29, 0x10_22)]: makeElement('UL', 1), [tagKey(0x00_29, 0x10_23)]: makeElement('UL', storedBytes.length), [tagKey(0x00_29, 0x10_24)]: makeObElement(storedBytes) }); // ── 3. Public reference sequences ──────────────────────────────────────── // (0008,1115) Referenced Series Sequence — source CT series const referencedSeriesSq = makeElement('SQ', { [tagKey(0x00_20, 0x00_0e)]: makeElement('UI', sourceSeriesUID) }); // (0008,2112) Source Image Sequence — one item per source CT instance const sourceImgSeq = makeElement('SQ', ...sourceInstanceUIDs.map(uid => ({ [tagKey(0x00_08, 0x11_50)]: makeElement('UI', CT_SOP_CLASS), [tagKey(0x00_08, 0x11_55)]: makeElement('UI', uid) }))); let previewRows; let previewCols; let pixelData; if (options.previewPixels) { const inferredSize = Math.round(Math.sqrt(options.previewPixels.length / 3)); previewRows = options.previewRows ?? inferredSize; previewCols = options.previewCols ?? inferredSize; if (options.previewPixels.length !== previewRows * previewCols * 3) { throw new Error(`previewPixels length ${options.previewPixels.length} does not match ${previewRows}×${previewCols}×3`); } pixelData = options.previewPixels; } else { previewRows = options.previewRows ?? 128; previewCols = options.previewCols ?? 128; pixelData = new Uint8Array(previewRows * previewCols * 3); } const d = instanceCreationDate; const t = instanceCreationTime; const dt = d + t; const pt = resolvePatientTagFallbacks(options); const sr = resolveSeriesTagFallbacks(options, d, t); // ── 4. Assemble the dataset ─────────────────────────────────────────────── const dataset = { // 0008 group [tagKey(0x00_08, 0x00_05)]: makeElement('CS', 'ISO_IR 192'), [tagKey(0x00_08, 0x00_08)]: makeElement('CS', 'DERIVED', 'SECONDARY'), [tagKey(0x00_08, 0x00_12)]: makeElement('DA', d), [tagKey(0x00_08, 0x00_13)]: makeElement('TM', t), [tagKey(0x00_08, 0x00_16)]: makeElement('UI', SC_SOP_CLASS), [tagKey(0x00_08, 0x00_18)]: makeElement('UI', sopInstanceUID), [tagKey(0x00_08, 0x00_20)]: makeElement('DA', pt.studyDate), [tagKey(0x00_08, 0x00_21)]: makeElement('DA', sr.seriesDate), [tagKey(0x00_08, 0x00_30)]: makeElement('TM', pt.studyTime), [tagKey(0x00_08, 0x00_31)]: makeElement('TM', sr.seriesTime), [tagKey(0x00_08, 0x00_50)]: makeElement('SH', pt.accessionNumber), [tagKey(0x00_08, 0x00_60)]: makeElement('CS', 'OT'), [tagKey(0x00_08, 0x00_64)]: makeElement('CS', 'WSD'), [tagKey(0x00_08, 0x00_70)]: makeElement('LO', 'Tomoverse Imaging'), [tagKey(0x00_08, 0x02_01)]: makeElement('SH', formatTimezoneOffset()), [tagKey(0x00_08, 0x10_30)]: makeElement('LO', pt.studyDescription), [tagKey(0x00_08, 0x10_3e)]: makeElement('LO', seriesDescription), [tagKey(0x00_08, 0x10_70)]: makeElement('PN', author), [tagKey(0x00_08, 0x10_90)]: makeElement('LO', 'tvCT'), [tagKey(0x00_08, 0x11_15)]: referencedSeriesSq, [tagKey(0x00_08, 0x21_11)]: makeElement('ST', 'tvCT worksession preview and private analysis state derived from source CT images.'), [tagKey(0x00_08, 0x21_12)]: sourceImgSeq, // 0010 group [tagKey(0x00_10, 0x00_10)]: makeElement('PN', pt.patientName), [tagKey(0x00_10, 0x00_20)]: makeElement('LO', pt.patientID), [tagKey(0x00_10, 0x00_30)]: makeElement('DA', pt.patientBirthDate), [tagKey(0x00_10, 0x00_40)]: makeElement('CS', pt.patientSex), // 0018 group [tagKey(0x00_18, 0x10_12)]: makeElement('DA', d), [tagKey(0x00_18, 0x10_14)]: makeElement('TM', t), [tagKey(0x00_18, 0x10_16)]: makeElement('LO', 'Tomoverse Imaging'), [tagKey(0x00_18, 0x10_18)]: makeElement('LO', 'tvCT'), [tagKey(0x00_18, 0x10_19)]: makeElement('LO', softwareVersion), [tagKey(0x00_18, 0x10_20)]: makeElement('LO', softwareVersion), // 0020 group [tagKey(0x00_20, 0x00_0d)]: makeElement('UI', studyInstanceUID), [tagKey(0x00_20, 0x00_0e)]: makeElement('UI', seriesInstanceUID), [tagKey(0x00_20, 0x00_10)]: makeElement('SH', pt.studyID), [tagKey(0x00_20, 0x00_11)]: makeElement('IS', sr.seriesNumber), [tagKey(0x00_20, 0x00_13)]: makeElement('IS', 1), // 0028 group [tagKey(0x00_28, 0x00_02)]: makeElement('US', 3), [tagKey(0x00_28, 0x00_04)]: makeElement('CS', 'RGB'), [tagKey(0x00_28, 0x00_06)]: makeElement('US', 0), [tagKey(0x00_28, 0x00_10)]: makeElement('US', previewRows), [tagKey(0x00_28, 0x00_11)]: makeElement('US', previewCols), [tagKey(0x00_28, 0x01_00)]: makeElement('US', 8), [tagKey(0x00_28, 0x01_01)]: makeElement('US', 8), [tagKey(0x00_28, 0x01_02)]: makeElement('US', 7), [tagKey(0x00_28, 0x01_03)]: makeElement('US', 0), [tagKey(0x00_28, 0x03_01)]: makeElement('CS', 'NO'), [tagKey(0x00_28, 0x21_10)]: makeElement('CS', '00'), // 0029 group — TOMOVERSE_TVCT_1 private block [tagKey(0x00_29, 0x00_10)]: makeElement('LO', PRIVATE_CREATOR), [tagKey(0x00_29, 0x10_01)]: makeElement('LO', 'TVCT_WORKSESSION'), [tagKey(0x00_29, 0x10_02)]: makeElement('LO', payloadSchemaVersion), [tagKey(0x00_29, 0x10_03)]: makeElement('LO', workSessionUID), [tagKey(0x00_29, 0x10_04)]: makeElement('UL', workSessionRevision), [tagKey(0x00_29, 0x10_05)]: makeElement('CS', 'JSON'), [tagKey(0x00_29, 0x10_06)]: makeElement('CS', 'GZIP'), [tagKey(0x00_29, 0x10_07)]: makeElement('UL', originalLength), [tagKey(0x00_29, 0x10_08)]: makeElement('UT', `sha256:${sha256}`), [tagKey(0x00_29, 0x10_09)]: payloadSq, [tagKey(0x00_29, 0x10_11)]: makeElement('LO', authorUserId || author), [tagKey(0x00_29, 0x10_12)]: makeElement('PN', author), [tagKey(0x00_29, 0x10_13)]: makeElement('DT', dt), // Private mirror of the standard (300E) review tags, in case a PACS drops non-indexed attributes. [tagKey(0x00_29, 0x10_14)]: makeElement('CS', reviewStatus), [tagKey(0x00_29, 0x10_15)]: makeElement('LO', reviewerUserId), [tagKey(0x00_29, 0x10_16)]: makeElement('PN', reviewerName), [tagKey(0x00_29, 0x10_17)]: makeElement('DT', reviewDateTime), [tagKey(0x00_29, 0x10_18)]: makeElement('UT', reviewComment), [tagKey(0x00_29, 0x10_1d)]: makeElement('LO', reviewReasonCode), [tagKey(0x00_29, PRIVATE_TAG_PHASE_LABEL)]: makeElement('LO', phaseLabel), [tagKey(0x00_29, PRIVATE_TAG_SOURCE_INSTANCE_UIDS)]: makeElement('UT', sourceInstanceUIDs.join('\\')), [tagKey(0x00_29, PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION)]: makeElement('LO', sourceSeriesDescription), [tagKey(0x00_29, PRIVATE_TAG_SOURCE_SERIES_UID)]: makeElement('UI', sourceSeriesUID), // 0070 group [tagKey(0x00_70, 0x00_84)]: makeElement('PN', author), // 300E group — standard approval/review module [tagKey(0x30_0e, 0x00_02)]: makeElement('CS', reviewStatus), [tagKey(0x30_0e, 0x00_04)]: makeElement('DA', reviewDate), [tagKey(0x30_0e, 0x00_05)]: makeElement('TM', reviewTime), [tagKey(0x30_0e, 0x00_08)]: makeElement('PN', reviewerName), // 7FE0 group — RGB pixel data (128×128 when captured, black placeholder otherwise) [tagKey(0x7f_e0, 0x00_10)]: makeObElement(pixelData) }; // ── 5. File meta (group 0002); dcmjs computes the group length and preamble ─ const meta = { [tagKey(0x00_02, 0x00_01)]: makeObElement(new Uint8Array([0x00, 0x01])), [tagKey(0x00_02, 0x00_02)]: makeElement('UI', SC_SOP_CLASS), [tagKey(0x00_02, 0x00_03)]: makeElement('UI', sopInstanceUID), [tagKey(0x00_02, 0x00_10)]: makeElement('UI', EXPLICIT_VR_LE), [tagKey(0x00_02, 0x00_12)]: makeElement('UI', IMPL_CLASS_UID), [tagKey(0x00_02, 0x00_13)]: makeElement('SH', IMPL_VERSION) }; // ── 6. Emit preamble + DICM + file-meta + dataset via dcmjs ──────────────── // dcmjs is loaded on demand so it stays out of the initial bundle — it is only // needed here, on an explicit export, not on the (dicom-parser) read path. const { default: dcmjs } = yield __webpack_require__.e(/*! import() */ "default-node_modules_dcmjs_build_dcmjs_es_js").then(__webpack_require__.bind(__webpack_require__, /*! dcmjs */ 545)); const dicomDict = new dcmjs.data.DicomDict(meta); dicomDict.dict = dataset; return dicomDict.write(); }); return _buildScOtDicom.apply(this, arguments); } function elementKey(group, element) { return `x${tagKey(group, element).toLowerCase()}`; } /** Parse a DICOM binary, returning `undefined` for input dicom-parser cannot read. */ function parseDataSet(dicomBuffer) { try { return dicom_parser__WEBPACK_IMPORTED_MODULE_1___default().parseDicom(new Uint8Array(dicomBuffer)); } catch { return undefined; } } /** Decode a single element's raw value bytes to text (null-stripped, trimmed). */ function decodeElement(dataSet, element) { const raw = dataSet.byteArray.slice(element.dataOffset, element.dataOffset + element.length); return new TextDecoder().decode(raw).replaceAll('\0', '').trim(); } /** Read a string-valued DICOM tag. Returns `undefined` if the tag is not found. */ function readDicomStringTag(dicomBuffer, targetGroup, targetElement) { const dataSet = parseDataSet(dicomBuffer); const element = dataSet?.elements[elementKey(targetGroup, targetElement)]; if (!dataSet || !element) return undefined; return decodeElement(dataSet, element); } /** Read the Modality tag (0008,0060) value from a DICOM binary. */ function readDicomModality(dicomBuffer) { return readDicomStringTag(dicomBuffer, 0x00_08, 0x00_60); } function looksLikeDicomUid(value) { return /^\d+(?:\.\d+)+$/.test(value); } function looksLikeDicomUidList(value) { const parts = value.split('\\').map(v => v.trim()).filter(v => v.length > 0); return parts.length > 0 && parts.every(part => looksLikeDicomUid(part)); } function parseUidList(value) { return value.split('\\').filter(v => v.length > 0); } function resolveSourceSeriesUid(read, dataSet) { const legacySourceSeriesUid = read(0x00_29, PRIVATE_TAG_PHASE_LABEL); return read(0x00_29, PRIVATE_TAG_SOURCE_SERIES_UID) || (looksLikeDicomUid(legacySourceSeriesUid) ? legacySourceSeriesUid : '') || readSequenceUid(dataSet, 0x00_08, 0x11_15, 0x00_20, 0x00_0e); } function resolveSourceSeriesDescription(read) { const candidate = read(0x00_29, PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION); return candidate.length > 0 && !looksLikeDicomUidList(candidate) ? candidate : read(0x00_29, LEGACY_PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION); } function resolveSourceInstanceUids(read, dataSet) { const descriptionCandidate = read(0x00_29, PRIVATE_TAG_SOURCE_SERIES_DESCRIPTION); const storedValue = read(0x00_29, PRIVATE_TAG_SOURCE_INSTANCE_UIDS) || (looksLikeDicomUidList(descriptionCandidate) ? descriptionCandidate : read(0x00_29, LEGACY_PRIVATE_TAG_SOURCE_INSTANCE_UIDS)); if (storedValue) return parseUidList(storedValue); return readSequenceUids(dataSet, 0x00_08, 0x21_12, 0x00_08, 0x11_55); } /** Read the first item of a SQ tag and return one child tag value as a string. */ function readSequenceUid(dataSet, sqGroup, sqElement, childGroup, childElement) { const sq = dataSet.elements[elementKey(sqGroup, sqElement)]; const itemSet = sq?.items?.[0]?.dataSet; if (!itemSet) return ''; const element = itemSet.elements[elementKey(childGroup, childElement)]; return element ? decodeElement(itemSet, element) : ''; } /** Read a SQ tag and return the given child tag value from every item. */ function readSequenceUids(dataSet, sqGroup, sqElement, childGroup, childElement) { const sq = dataSet.elements[elementKey(sqGroup, sqElement)]; const uids = []; for (const item of sq?.items ?? []) { const itemSet = item.dataSet; if (!itemSet) continue; const element = itemSet.elements[elementKey(childGroup, childElement)]; if (element) uids.push(decodeElement(itemSet, element)); } return uids; } /** Reassemble the chunked payload from the private (0029,1009) sequence, ordered by chunk index. */ function readChunkedPayload(sequence) { const chunks = []; for (const item of sequence.items ?? []) { const itemSet = item.dataSet; const payload = itemSet?.elements[elementKey(0x00_29, 0x10_24)]; if (!itemSet || !payload) continue; const actualLength = itemSet.uint32(elementKey(0x00_29, 0x10_23)) ?? payload.length; const index = itemSet.uint32(elementKey(0x00_29, 0x10_21)) ?? 0; chunks.push({ data: itemSet.byteArray.slice(payload.dataOffset, payload.dataOffset + actualLength), index }); } if (chunks.length === 0) return undefined; const ordered = chunks.toSorted((a, b) => a.index - b.index).map(c => c.data); const total = ordered.reduce((sum, c) => sum + c.length, 0); const result = new Uint8Array(total); let pos = 0; for (const chunk of ordered) { result.set(chunk, pos); pos += chunk.length; } return result; } /** * Read the TOMOVERSE_TVCT_1 (0029) private block from a DICOM binary and return the * annotation payload bytes plus author/source metadata. * Returns `undefined` when the private creator tag or payload sequence is absent. */ function extractAnnotationTags(dicomBuffer) { const dataSet = parseDataSet(dicomBuffer); if (!dataSet) return undefined; const creator = dataSet.elements[elementKey(0x00_29, 0x00_10)]; if (!creator || decodeElement(dataSet, creator) !== PRIVATE_CREATOR) return undefined; const sequence = dataSet.elements[elementKey(0x00_29, 0x10_09)]; const payloadBytes = sequence ? readChunkedPayload(sequence) : undefined; if (!payloadBytes) return undefined; const read = (group, element) => { const found = dataSet.elements[elementKey(group, element)]; return found ? decodeElement(dataSet, found) : ''; }; const sourceSeriesUid = resolveSourceSeriesUid(read, dataSet); const sourceSeriesDescription = resolveSourceSeriesDescription(read); const sourceInstanceUids = resolveSourceInstanceUids(read, dataSet); // Prefer the standard ApprovalStatus (300E,0002); fall back to the private mirror. const reviewStatus = read(0x30_0e, 0x00_02) || read(0x00_29, 0x10_14); return { creatorName: read(0x00_29, 0x10_12), creatorUserId: read(0x00_29, 0x10_11), payloadBytes, phaseLabel: read(0x00_29, PRIVATE_TAG_PHASE_LABEL), reviewComment: read(0x00_29, 0x10_18), reviewDateTime: read(0x00_29, 0x10_17), reviewerName: read(0x00_29, 0x10_16), reviewerUserId: read(0x00_29, 0x10_15), reviewReasonCode: read(0x00_29, 0x10_1d), reviewStatus, sourceInstanceUids, sourceSeriesDescription, sourceSeriesUid, workSessionRevision: dataSet.uint32(elementKey(0x00_29, 0x10_04)) ?? 0 }; } /***/ }, /***/ 8027 /*!******************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/services/dicom-export.service.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DicomExportService: () => (/* binding */ DicomExportService), /* harmony export */ TAVI_PROTOCOL_ID: () => (/* reexport safe */ _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_4__.TAVI_PROTOCOL_ID) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./dicom-annotation-codec */ 19462); const UID_ROOT = '1.3.6.1.4.1.66095'; function generateUid() { const buf = crypto.getRandomValues(new Uint32Array(4)); let n = 0n; for (const v of buf) n = n << 32n | BigInt(v >>> 0); return `${UID_ROOT}.${n}`; } /** * Derive a deterministic DICOM UID from an arbitrary string via SHA-256. * Same input always yields the same Tomoverse-rooted UID. */ function deterministicUid(_x) { return _deterministicUid.apply(this, arguments); } function _deterministicUid() { _deterministicUid = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (input) { const hash = yield crypto.subtle.digest('SHA-256', new TextEncoder().encode(input)); const bytes = new Uint8Array(hash).slice(0, 16); let n = 0n; for (const b of bytes) { n = n << 8n | BigInt(b); } return `${UID_ROOT}.${n}`; }); return _deterministicUid.apply(this, arguments); } function formatDate(d) { const mm = String(d.getMonth() + 1).padStart(2, '0'); const dd = String(d.getDate()).padStart(2, '0'); return `${d.getFullYear()}${mm}${dd}`; } function formatTime(d) { const hh = String(d.getHours()).padStart(2, '0'); const min = String(d.getMinutes()).padStart(2, '0'); const ss = String(d.getSeconds()).padStart(2, '0'); return `${hh}${min}${ss}`; } /** No review → UNAPPROVED at revision 0; a review stamps the decision + increments the revision. */ function resolveReviewFields(review, now) { if (!review) { return { reviewComment: '', reviewDate: '', reviewDateTime: '', reviewerName: '', reviewerUserId: '', reviewReasonCode: '', reviewStatus: 'UNAPPROVED', reviewTime: '', workSessionRevision: 0 }; } const reviewDate = formatDate(now); const reviewTime = formatTime(now); return { reviewComment: review.comment, reviewDate, reviewDateTime: reviewDate + reviewTime, reviewerName: review.reviewerName, reviewerUserId: review.reviewerUserId, reviewReasonCode: review.reasonCode ?? '', reviewStatus: review.status, reviewTime, workSessionRevision: review.baseRevision + 1 }; } /** Extract patient / study demographics from a raw WADO-RS metadata JSON object. */ function extractDemographics(meta) { if (!meta) return {}; const tagValue = tag => meta[tag]?.Value?.[0] ?? ''; return { accessionNumber: tagValue('00080050'), patientBirthDate: tagValue('00100030'), patientID: tagValue('00100020'), patientName: meta['00100010']?.Value?.[0]?.Alphabetic ?? '', patientSex: tagValue('00100040'), studyDate: tagValue('00080020'), studyDescription: tagValue('00081030'), studyID: tagValue('00200010'), studyTime: tagValue('00080030') }; } function computeMaxSeriesNumber(studySeries) { let max = 0; for (const s of studySeries ?? []) { if (typeof s.seriesNumber === 'number' && s.seriesNumber > max) max = s.seriesNumber; } return max; } class DicomExportService { db = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_3__.DicomDatabaseService); api = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_3__.DicomApiService); env = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.ENV); state = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)('idle', ...(ngDevMode ? [{ debugName: "state" }] : [])); error = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "error" }] : [])); /** * Derives the OT series identity from (work session, analysis name), so the series * follows the name shown at export time rather than colliding across renames. * Deterministic: every export under the same name — first or repeated — lands on the * same series, since identity can't depend on whether a rename "just happened". */ deriveRenamedWorkSessionUid(originalWorkSessionUid, newName) { return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return deterministicUid(`${originalWorkSessionUid}:${newName}`); })(); } /** * Build and upload a new OT DICOM file for each source series. * The file is built from scratch (no CT binary fetched) using WADO-RS instance * metadata for demographics and the given annotation payload. */ exportSeriesToStore(options) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { activePhaseInstanceUIDs = [], annotations = [], author = '', authorUserId = '', calculatedPaths = {}, destinationStoreUid, existingOtSeriesUid, phaseLabel = '', previewPixels, protocolBindings = [], protocolFormValues, renderSettings2D, renderSettings3D, review, seriesUids, sourceStudyUid = '', storeUid, workSessionName = '', workSessionUID = '' } = options; _this.state.set('exporting'); _this.error.set(undefined); try { for (const [seriesIndex, seriesUid] of seriesUids.entries()) { yield _this.exportOneSeries(seriesUid, seriesIndex, { activePhaseInstanceUIDs, annotations, author, authorUserId, calculatedPaths, destinationStoreUid: destinationStoreUid ?? storeUid, existingOtSeriesUid, phaseLabel, previewPixels, protocolBindings, protocolFormValues, renderSettings2D, renderSettings3D, review, sourceStudyUid, storeUid, workSessionName, workSessionUID }); } _this.state.set('done'); } catch (error) { _this.error.set(error.message ?? String(error)); _this.state.set('error'); throw error; } })(); } /** Record a review decision as a new OT instance in the same series (creator preserved, current user = reviewer). */ reviewSeriesToStore(parameters) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { context } = parameters; yield _this2.exportSeriesToStore({ activePhaseInstanceUIDs: context.activePhaseInstanceUIDs, annotations: parameters.annotations ?? [], author: context.creatorName, authorUserId: context.creatorUserId, calculatedPaths: parameters.calculatedPaths ?? {}, phaseLabel: context.phaseLabel, previewPixels: parameters.previewPixels, protocolBindings: parameters.protocolBindings ?? [], protocolFormValues: parameters.protocolFormValues, review: { baseRevision: context.revision, comment: parameters.comment, reasonCode: parameters.reasonCode, reviewerName: parameters.reviewerName, reviewerUserId: parameters.reviewerUserId, status: parameters.status }, seriesUids: [context.sourceSeriesUid], sourceStudyUid: context.studyUid, storeUid: context.storeUid, workSessionName: context.workSessionName, workSessionUID: context.workSessionUid }); })(); } exportOneSeries(seriesUid, seriesIndex, options) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { activePhaseInstanceUIDs, annotations, author, authorUserId, calculatedPaths, destinationStoreUid, existingOtSeriesUid, phaseLabel, previewPixels, protocolBindings, protocolFormValues, renderSettings2D, renderSettings3D, review, sourceStudyUid, storeUid, workSessionName, workSessionUID } = options; // Authoritative study UID from local cache; fall back to the route param. const localStudyUid = yield _this3.db.getStudyUidForSeries(seriesUid); const studyUid = localStudyUid ?? sourceStudyUid; if (!studyUid) { throw new Error('Could not determine study UID for series. Please reload the viewer and try again.'); } // Series UID is deterministic per (work session, source series): all exports // of the same analysis group under one OT series; different analyses each // get their own series even when they reference the same source CT. const newSeriesUid = existingOtSeriesUid ?? (yield deterministicUid(workSessionUID + seriesUid)); // Instance UID is always fresh so each upload creates a new DICOM instance. const now = new Date(); const newInstanceUid = generateUid(); // Fetch study series (from the destination store) to compute the next available series number. let studySeries; try { studySeries = yield _this3.db.getSeriesForStudy(studyUid, destinationStoreUid); } catch { // Non-fatal — fall back to series number 1 } const existingOtSeries = studySeries?.find(s => s.seriesInstanceUID === newSeriesUid); const maxSeriesNumber = computeMaxSeriesNumber(studySeries); const seriesNumber = typeof existingOtSeries?.seriesNumber === 'number' ? existingOtSeries.seriesNumber : maxSeriesNumber + 1 + seriesIndex; // Fetch instance metadata (no binary download needed). const instances = yield _this3.db.getSeriesInstancesMetadata(studyUid, seriesUid, storeUid); if (instances.length === 0) { throw new Error('Series could not be cached before export. Please cache the series first and try again.'); } const sourceInstanceUIDs = activePhaseInstanceUIDs.length > 0 ? activePhaseInstanceUIDs : instances.map(inst => inst.sopInstanceUID).filter(Boolean); // Pull patient / study demographics from the first instance's WADO-RS metadata. const firstMeta = instances[0].toJSON?.()?.metadata; const demographics = extractDemographics(firstMeta); const sourceSeriesDescription = String(firstMeta?.['0008103E']?.Value?.[0] ?? '').trim(); // Normalize the TAVI snapshot before writing so an OT can always be read by // the same constrained payload schema used for external imports. const payload = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__.annotationPayloadV1Schema.parse({ annotationProtocolBindings: protocolBindings, annotations, calculatedPaths, protocolFormValues, renderSettings2D, renderSettings3D, sourceInstanceUIDs, sourceSeriesUID: seriesUid, version: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__.OT_PAYLOAD_LATEST_VERSION }); const otInstance = yield (0,_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__.buildScOtDicom)({ ...demographics, ...resolveReviewFields(review, now), author, authorUserId, instanceCreationDate: formatDate(now), instanceCreationTime: formatTime(now), payload, payloadSchemaVersion: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_2__.OT_PAYLOAD_SCHEMA_VERSION, phaseLabel: phaseLabel || undefined, previewPixels, seriesDescription: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_4__.toTvctWorkSessionDescription)(workSessionName), seriesInstanceUID: newSeriesUid, seriesNumber, softwareVersion: _this3.env.version ?? '0.0.0', sopInstanceUID: newInstanceUid, sourceInstanceUIDs, sourceSeriesDescription, sourceSeriesUID: seriesUid, studyInstanceUID: studyUid, workSessionUID }); yield _this3.api.uploadToStore([otInstance], destinationStoreUid); yield _this3.verifyExportIntegrity(otInstance, newInstanceUid, studyUid, newSeriesUid, destinationStoreUid); // Best-effort: cache locally so the viewer can open immediately without WADO-RS. try { const remoteInstances = yield _this3.api.getInstancesForSeries(studyUid, newSeriesUid, destinationStoreUid); yield _this3.db.saveInstances(remoteInstances, studyUid, newSeriesUid, destinationStoreUid); yield _this3.db.saveBinary(newInstanceUid, otInstance, destinationStoreUid); } catch { // Non-fatal — viewer falls back to WADO-RS once the store has indexed. } })(); } /** * Downloads the just-uploaded OT instance back from the store and verifies its * annotation tags are intact. Throws if the round-trip corrupts or strips the * private-tag payload — this surfaces store-side degradation (e.g. transcoding * that drops private tags) as an explicit export error rather than a silent * broken file. * * Uses the locally-built buffer as the source of truth when the store has not * indexed the instance yet (Google Healthcare can take a few seconds). */ verifyExportIntegrity(localBuffer, instanceUid, studyUid, seriesUid, storeUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { let buffer = localBuffer; try { const remote = yield _this4.api.getInstanceDicomFile(studyUid, seriesUid, instanceUid, storeUid); buffer = remote instanceof SharedArrayBuffer ? localBuffer : remote; } catch { // Store may not have indexed yet — fall back to verifying the local build. } const tags = (0,_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__.extractAnnotationTags)(buffer); if (!tags) { throw new Error('Export integrity check failed: annotation private tags are missing from the stored OT file. ' + 'The DICOM store may have stripped private tags during upload.'); } })(); } /** * Read annotation data embedded in a DICOM file and deserialize the payload. * Returns undefined if the file is not an OT DICOM with TOMOVERSE private tags. */ importAnnotationsFromDicom(dicomBuffer) { return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if ((0,_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__.readDicomModality)(dicomBuffer) !== 'OT') return undefined; const tags = (0,_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__.extractAnnotationTags)(dicomBuffer); if (!tags) return undefined; return (0,_dicom_annotation_codec__WEBPACK_IMPORTED_MODULE_6__.deserializeAnnotationPayload)(tags.payloadBytes); })(); } static ɵfac = function DicomExportService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomExportService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: DicomExportService, factory: DicomExportService.ɵfac }); } /***/ }, /***/ 14043 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/services/dicom-importer.service.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 32348); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 53291); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../logging/utils */ 14337); /* harmony import */ var _components_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../components/patient-library/patient-library-list.facade */ 67045); const SERIES_REFRESH_THROTTLE_MS = 250; class DicomImporterDialogService { db = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.DicomDatabaseService); api = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.DicomApiService); storeList = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_9__.DicomStoreListService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_8__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_7__.TranslateService); libraryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_components_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_11__.PatientLibraryListFacade); static log; isImportingToLibrary = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "isImportingToLibrary" }] : [])); series = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_2__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_2__.toObservable)(this.libraryFacade.selectedStoreUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.switchMap)(storeUid => this.db.getAllNotUploadedSeries(storeUid ?? '')), (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.throttleTime)(SERIES_REFRESH_THROTTLE_MS, rxjs__WEBPACK_IMPORTED_MODULE_3__.asyncScheduler, { leading: true, trailing: true }), // Absent display values stay empty so the table renders NO_DATA_PLACEHOLDER. (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.map)(seriesList => seriesList.map(seriesDocument => ({ images: seriesDocument.instances.length, modality: seriesDocument.modality ?? '', patientID: seriesDocument.patientID ?? '', patientName: seriesDocument.patientName ?? '', seriesDescription: seriesDocument.seriesDescription ?? '', seriesInstanceUID: seriesDocument.seriesInstanceUID, seriesNumber: seriesDocument.seriesNumber ?? 0, studyDate: seriesDocument.studyDate ?? '', studyDescription: seriesDocument.studyDescription ?? '', studyInstanceUID: seriesDocument.studyInstanceUID })))), { initialValue: [] }); constructor() { if (!DicomImporterDialogService.log) { DicomImporterDialogService.log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_10__.getLogger)(DicomImporterDialogService.name); } } /** * Returns the UID of the store the importer is currently working against. */ resolveCurrentStore() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this.libraryFacade.selectedStoreUid() ?? (yield _this.storeList.resolveStoreUid()); })(); } toUploadErrorMessage(error) { const serverMessage = error?.error?.message; if (serverMessage && /permission|denied|forbidden/i.test(serverMessage)) { return this.translate.instant('dicomImporter.importToast.permissionDenied'); } return serverMessage ?? this.translate.instant('dicomImporter.importToast.uploadFailed'); } importToLibrary(rows) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this2.isImportingToLibrary.set(true); try { const storeUid = yield _this2.resolveCurrentStore(); const uploadedSeriesUids = []; for (const row of rows) { const seriesUid = row.seriesInstanceUID; if (!seriesUid) continue; try { const files = yield _this2.db.getSeriesInstanceFiles(seriesUid, storeUid); // A file whose attachment write failed leaves an instance without cached // pixel data. Uploading the rest would store an incomplete series. if (files.length === 0 || files.length < row.images) { _this2.messageService.add({ life: 4000, severity: 'warn', summary: _this2.translate.instant('dicomImporter.importToast.noFiles') }); continue; } yield _this2.api.uploadToStore(files, storeUid); uploadedSeriesUids.push(seriesUid); _this2.messageService.add({ life: 3000, severity: 'success', summary: _this2.translate.instant('dicomImporter.importToast.success') }); } catch (error) { DicomImporterDialogService.log?.error('Import to library failed', error); _this2.messageService.add({ detail: _this2.toUploadErrorMessage(error), life: 6000, severity: 'error', summary: _this2.translate.instant('dicomImporter.importToast.error') }); } } if (uploadedSeriesUids.length > 0) { _this2.deleteUploadedSeriesInBackground(uploadedSeriesUids); _this2.libraryFacade.reloadStudies(); } return uploadedSeriesUids; } finally { _this2.isImportingToLibrary.set(false); } })(); } /** * Deletes the staged local copies of the given series from the store the * importer is currently working against. */ deleteStagedSeries(seriesUids) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const storeUid = yield _this3.resolveCurrentStore(); yield Promise.all(seriesUids.map(uid => _this3.db.deleteLocalSeries(uid, storeUid))); })(); } deleteUploadedSeriesInBackground(seriesUids) { this.deleteStagedSeries(seriesUids).catch(error => { DicomImporterDialogService.log?.error('Failed to delete staged series after upload', error); }); } getSeriesInstancesMetadata(studyUid, seriesUid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this4.db.getSeriesInstancesMetadata(studyUid, seriesUid, yield _this4.resolveCurrentStore()); })(); } getSeriesCommonMetadata(studyUid, seriesUid) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this5.db.getSeriesComputedMetadata(studyUid, seriesUid, yield _this5.resolveCurrentStore()); })(); } getSeriesImageUrls(studyUid, seriesUid) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this6.db.getSeriesImageUrls(studyUid, seriesUid, yield _this6.resolveCurrentStore()); })(); } static ɵfac = function DicomImporterDialogService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DicomImporterDialogService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: DicomImporterDialogService, factory: DicomImporterDialogService.ɵfac }); } /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DicomImporterDialogService); /***/ }, /***/ 59639 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/dicom-importer/services/protocol-binding-utils.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ buildProtocolBindings: () => (/* binding */ buildProtocolBindings), /* harmony export */ rebuildProtocolState: () => (/* binding */ rebuildProtocolState) /* harmony export */ }); function buildProtocolBindings(definitions, instances) { const definitionMap = Object.fromEntries(definitions.map(d => [d.id, d])); const bindings = []; for (const instance of instances) { const definition = definitionMap[instance.protocolId]; if (!definition) continue; for (const [placeholderId, annotationId] of Object.entries(instance.placeholderMappings)) { const placeholderIndex = definition.placeholders.findIndex(p => p.id === placeholderId); if (placeholderIndex === -1) continue; const placeholder = definition.placeholders[placeholderIndex]; if (!placeholder) continue; bindings.push({ annotationId, annotationType: placeholder.annotationType, color: placeholder.color, placeholderIndex, placeholderName: placeholder.name, protocolId: instance.protocolId, protocolName: definition.name, protocolPlaceholderId: placeholderId, role: placeholder.relationship == undefined ? '' : JSON.stringify(placeholder.relationship) }); } } return bindings; } /** * Reconstruct protocol definitions and instances from serialized bindings. * This is the inverse of `buildProtocolBindings` — call it during OT import to * restore the full protocol state that was captured at export time. */ function rebuildProtocolState(bindings) { const byProtocol = new Map(); for (const binding of bindings) { const group = byProtocol.get(binding.protocolId) ?? []; group.push(binding); byProtocol.set(binding.protocolId, group); } const definitions = []; const instances = []; for (const [protocolId, protocolBindings] of byProtocol) { const sorted = protocolBindings.toSorted((a, b) => a.placeholderIndex - b.placeholderIndex); const placeholders = sorted.map(b => { let relationship; if (b.role) { try { relationship = JSON.parse(b.role); } catch { // malformed role — omit relationship } } return { annotationType: b.annotationType, color: b.color, id: b.protocolPlaceholderId, name: b.placeholderName, ...(relationship === undefined ? {} : { relationship }) }; }); const protocolName = protocolBindings[0]?.protocolName ?? ''; definitions.push({ id: protocolId, name: protocolName, placeholders }); const placeholderMappings = {}; for (const b of protocolBindings) { placeholderMappings[b.protocolPlaceholderId] = b.annotationId; } instances.push({ placeholderMappings, protocolId }); } return { definitions, instances }; } /***/ }, /***/ 66039 /*!**************************************************************************!*\ !*** ./libs/feature/src/lib/dual-axis-slider/camera-slider.component.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CameraSliderComponent: () => (/* binding */ CameraSliderComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 14975); class CameraSliderComponent { CCType = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.SliderSourceType.CCSLIDER; RLType = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.SliderSourceType.RLSLIDER; step = 1; isDarkMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(true, { ...(ngDevMode ? { debugName: "isDarkMode" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_0__.booleanAttribute }); //save current slider states ccSliderValue = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.model)(0, ...(ngDevMode ? [{ debugName: "ccSliderValue" }] : [])); rlSliderValue = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.model)(0, ...(ngDevMode ? [{ debugName: "rlSliderValue" }] : [])); ccChanged = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); rlChanged = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); didReset = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); rlSliderChanged(newValueRL) { this.rlChanged.emit(newValueRL); } ccSliderChanged(newValueCC) { this.ccChanged.emit(newValueCC); } resetAngulations(event) { this.didReset.emit(event); } static ɵfac = function CameraSliderComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CameraSliderComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵdefineComponent"]({ type: CameraSliderComponent, selectors: [["lib-camera-slider"]], inputs: { isDarkMode: [1, "isDarkMode"], ccSliderValue: [1, "ccSliderValue"], rlSliderValue: [1, "rlSliderValue"] }, outputs: { ccSliderValue: "ccSliderValueChange", rlSliderValue: "rlSliderValueChange", ccChanged: "ccChanged", rlChanged: "rlChanged", didReset: "didReset" }, decls: 1, vars: 12, consts: [["toolTipValue", "Reset", 3, "hSliderChanged", "vSliderChanged", "didReset", "hSliderType", "vSliderType", "cSliderStep", "hMaxValue", "hMinValue", "vMaxValue", "vMinValue", "vStartingValue", "hStartingValue", "vSliderValue", "hSliderValue", "isDarkMode"]], template: function CameraSliderComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "lib-corner-sliders", 0); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵlistener"]("hSliderChanged", function CameraSliderComponent_Template_lib_corner_sliders_hSliderChanged_0_listener($event) { return ctx.rlSliderChanged($event); })("vSliderChanged", function CameraSliderComponent_Template_lib_corner_sliders_vSliderChanged_0_listener($event) { return ctx.ccSliderChanged($event); })("didReset", function CameraSliderComponent_Template_lib_corner_sliders_didReset_0_listener($event) { return ctx.resetAngulations($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("hSliderType", ctx.RLType)("vSliderType", ctx.CCType)("cSliderStep", 0.05)("hMaxValue", 89)("hMinValue", -89)("vMaxValue", 89)("vMinValue", -89)("vStartingValue", 0)("hStartingValue", 0)("vSliderValue", ctx.ccSliderValue())("hSliderValue", ctx.rlSliderValue())("isDarkMode", ctx.isDarkMode()); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.CornerSlidersComponent], encapsulation: 2 }); } /***/ }, /***/ 96472 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/imaging-library/imaging-library-page.component.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ImagingLibraryPageComponent: () => (/* binding */ ImagingLibraryPageComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/progressspinner */ 7271); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _dicom_importer_components_dicom_importer_dialog_dicom_importer_dialog_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../dicom-importer/components/dicom-importer-dialog/dicom-importer-dialog.component */ 18809); /* harmony import */ var _dicom_importer_components_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../dicom-importer/components/patient-library/patient-library-list.facade */ 67045); /* harmony import */ var _dicom_importer_components_patient_library_patient_library_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../dicom-importer/components/patient-library/patient-library.component */ 22357); /* harmony import */ var _dicom_importer_components_patient_library_series_cache_tasks_component__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../dicom-importer/components/patient-library/series-cache-tasks.component */ 8487); /* harmony import */ var _dicom_importer_components_patient_library_series_cache_service__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../dicom-importer/components/patient-library/series-cache.service */ 60240); /* harmony import */ var _dicom_importer_services_dicom_importer_service__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../dicom-importer/services/dicom-importer.service */ 14043); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _work_session_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../work-session/work-session-dialog.service */ 35009); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @angular/core */ 14975); function ImagingLibraryPageComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](1, "p-progressSpinner", 13); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](2, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](4, 1, "dicomImporter.exportToStoreDialog.checkingStores")); } } function ImagingLibraryPageComponent_Conditional_7_Conditional_15_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 22)(1, "div", 23); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](2, "i", 24); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](3, "div", 25)(4, "div", 26); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](6, "div", 15); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](9, "div", 27)(10, "div", 28)(11, "div", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](13, "div", 30); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](15, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](16, "div", 28)(17, "div", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](18); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](19, "div", 30); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](20); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](21, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](22, "div", 31)(23, "div", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](25, "libFileSize"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](26, "div", 30); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](27); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](28, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](29, "div", 32)(30, "span", 33); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](31); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](32, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](33, "span", 34); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](34, "DICOMweb"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](35, "span", 33); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](36); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](37, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](38, "span", 35, 3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](40); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { let tmp_10_0; let tmp_12_0; let tmp_14_0; const store_r6 = ctx; const urlTip_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](39); const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵclassMap"](ctx_r4.storeIcon(store_r6)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](store_r6.name); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](8, 14, ctx_r4.storeKindKey(store_r6))); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", ((tmp_10_0 = ctx_r4.storeStats()) == null ? null : tmp_10_0.studyCount) ?? "\u2014", " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](15, 16, "imagingLibrary.storeInfo.studies"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", ((tmp_12_0 = ctx_r4.storeStats()) == null ? null : tmp_12_0.seriesCount) ?? "\u2014", " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](21, 18, "imagingLibrary.storeInfo.series"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](25, 20, (tmp_14_0 = ctx_r4.storeStats()) == null ? null : tmp_14_0.totalSizeBytes), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](28, 22, "imagingLibrary.storeInfo.totalSize"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](32, 24, "imagingLibrary.storeInfo.protocol"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](37, 26, "imagingLibrary.storeInfo.baseUrl"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", urlTip_r7.truncated() ? store_r6.url : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", store_r6.url, " "); } } function ImagingLibraryPageComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "button", 14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ImagingLibraryPageComponent_Conditional_7_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const storeMenu_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](6); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](storeMenu_r2.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](1, "i", 15); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](4, "i", 16); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](5, "p-menu", 17, 0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](7, "button", 18, 1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](10, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ImagingLibraryPageComponent_Conditional_7_Template_button_click_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const infoButton_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](8); const storeInfo_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](13); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](storeInfo_r4.toggle($event, infoButton_r3)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](11, "i", 19); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](12, "p-popover", 20, 2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("onShow", function ImagingLibraryPageComponent_Conditional_7_Template_p_popover_onShow_12_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r4.loadStoreStats()); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](14, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](15, ImagingLibraryPageComponent_Conditional_7_Conditional_15_Template, 41, 28); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { let tmp_5_0; let tmp_10_0; const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵclassMap"](ctx_r4.storeIcon(ctx_r4.selectedStore())); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", ((tmp_5_0 = ctx_r4.selectedStore()) == null ? null : tmp_5_0.name) ?? _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](3, 8, "patientList.store"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("model", ctx_r4.storeMenuItems())("popup", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](9, 10, "imagingLibrary.storeDetails")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](10, 12, "imagingLibrary.storeDetails")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](8); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"]((tmp_10_0 = ctx_r4.selectedStore()) ? 15 : -1, tmp_10_0); } } function ImagingLibraryPageComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](0, "p-progressBar", 36); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](1, "span", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](3, "span", 38); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](4, "%"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("showValue", false)("value", ctx_r4.totalProgress()); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](ctx_r4.totalProgress()); } } function ImagingLibraryPageComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "p-button", 39); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ImagingLibraryPageComponent_Conditional_11_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r8); const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r4.clearFilters()); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](1, 1, "patientList.filters.clear")); } } const STORE_TYPE_ICONS = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.CLOUD]: 'pi pi-cloud', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.DICOM_WEB]: 'pi pi-globe', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.DIMSE]: 'pi pi-server' }; const STORE_KIND_KEYS = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.CLOUD]: 'imagingLibrary.storeKind.cloud', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.DICOM_WEB]: 'imagingLibrary.storeKind.dicomweb', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_11__.StoreType.DIMSE]: 'imagingLibrary.storeKind.dimse' }; class ImagingLibraryPageComponent { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_20__.getLogger)(ImagingLibraryPageComponent.name); destroyRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef); nestedDialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DialogService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateService); importDialogRef; dicomImportService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__.DicomImportService); patientLibraryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_dicom_importer_components_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_15__.PatientLibraryListFacade); stores = this.patientLibraryFacade.stores; selectedStoreUid = this.patientLibraryFacade.selectedStoreUid; loadingStores = this.patientLibraryFacade.loadingStores; storeStats = this.patientLibraryFacade.storeStats; loading = this.patientLibraryFacade.loading; detailsToolbar = this.patientLibraryFacade.detailsToolbar; reloadDisabled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.detailsToolbar()?.loading() ?? this.loading(), ...(ngDevMode ? [{ debugName: "reloadDisabled" }] : [])); selectedStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.stores().find(store => store.uid === this.selectedStoreUid()), ...(ngDevMode ? [{ debugName: "selectedStore" }] : [])); /** * Menu model grouped by store type in {@link STORE_TYPE_ORDER}, separated by dividers. * Per-store icons convey the category; there are no group labels. */ storeMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const selectedUid = this.selectedStoreUid(); const toItem = store => ({ command: () => this.onStoreChange(store.uid), icon: STORE_TYPE_ICONS[(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.storeTypeForVendor)(store.vendor)], label: store.name, styleClass: store.uid === selectedUid ? 'active-store' : '' }); return _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.STORE_TYPE_ORDER.map(type => this.stores().filter(store => (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.storeTypeForVendor)(store.vendor) === type)).filter(group => group.length > 0).flatMap((group, index) => { const items = group.map(store => toItem(store)); return index > 0 ? [{ separator: true }, ...items] : items; }); }, ...(ngDevMode ? [{ debugName: "storeMenuItems" }] : [])); totalProgress = this.dicomImportService.totalProgress; constructor() { this.patientLibraryFacade.init().catch(error => { this.log.error('Failed to load studies:', error); }); this.destroyRef.onDestroy(() => this.importDialogRef?.close()); } storeIcon(store) { return store ? STORE_TYPE_ICONS[(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.storeTypeForVendor)(store.vendor)] : 'pi pi-database'; } storeKindKey(store) { return STORE_KIND_KEYS[(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.storeTypeForVendor)(store.vendor)]; } clearFilters() { this.patientLibraryFacade.requestClearFilters(); } /** Reloads whichever view is open: the series list at study level, the study list otherwise. */ reload() { const details = this.detailsToolbar(); if (details) { details.reload(); } else { this.patientLibraryFacade.reloadStudies(); } } loadStoreStats() { this.patientLibraryFacade.loadStoreStats().catch(error => { this.log.error('Failed to load store statistics:', error); }); } onStoreChange(storeUid) { this.patientLibraryFacade.selectStore(storeUid).catch(error => { this.log.error('Failed to switch store:', error); }); } openImportDialog() { this.importDialogRef = this.nestedDialogService.open(_dicom_importer_components_dicom_importer_dialog_dicom_importer_dialog_component__WEBPACK_IMPORTED_MODULE_14__.DicomImporterDialogComponent, { ..._dicom_importer_components_dicom_importer_dialog_dicom_importer_dialog_component__WEBPACK_IMPORTED_MODULE_14__.DICOM_IMPORTER_DIALOG_OPTIONS, header: this.translate.instant('dicomImporter.importDialog.header') }) ?? undefined; } static ɵfac = function ImagingLibraryPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ImagingLibraryPageComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵdefineComponent"]({ type: ImagingLibraryPageComponent, selectors: [["lib-imaging-library-page"]], hostAttrs: [1, "dark", "flex", "h-full", "flex-col", "bg-surface-950", "text-color"], features: [_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵProvidersFeature"]([primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DialogService, _dicom_importer_services_dicom_importer_service__WEBPACK_IMPORTED_MODULE_19__["default"], _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__.DicomImportService, _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__.VolumeLoaderService, _work_session_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_21__.WorkSessionDialogService, _dicom_importer_components_patient_library_patient_library_list_facade__WEBPACK_IMPORTED_MODULE_15__.PatientLibraryListFacade, // Above the library views: caching outlives the series screen, and the top bar hosts its tracker. _dicom_importer_components_patient_library_series_cache_service__WEBPACK_IMPORTED_MODULE_18__.SeriesCacheService, { provide: _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__.StudySearchProvider, useClass: _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_10__.ClientStudySearchProvider }])], decls: 16, vars: 10, consts: [["storeMenu", ""], ["infoButton", ""], ["storeInfo", ""], ["urlTip", "libEllipsisTip"], [1, "border-surface-800", "flex", "h-14", "shrink-0", "items-center", "gap-3", "border-b", "bg-(--p-app-chrome-page-header)", "px-5", "select-none"], [1, "font-semibold", "tracking-wide"], [1, "bg-surface-700", "mx-2", "h-6", "w-px"], [1, "flex", "items-center", "gap-1.5", "text-sm"], [1, "text-muted-color", "flex", "items-center", "gap-2", "px-2.5", "py-1.5"], [1, "grow"], ["data-test-id", "imaging-library-p-button-clear-filters", "icon", "pi pi-filter-slash", "severity", "secondary", "size", "small", "variant", "outlined", 3, "label"], ["data-test-id", "imaging-library-p-button-reload", "icon", "pi pi-refresh", "severity", "secondary", "size", "small", "variant", "outlined", 3, "click", "label", "disabled"], [1, "bg-surface-950", "min-h-0", "flex-1", "py-4"], ["strokeWidth", "4", 1, "size-4"], ["type", "button", "data-test-id", "imaging-library-button-store-menu", "aria-haspopup", "menu", 1, "hover:bg-surface-800", "flex", "cursor-pointer", "items-center", "gap-2", "rounded-md", "px-2.5", "py-1.5", "transition-colors", 3, "click"], [1, "text-muted-color", "text-xs"], [1, "pi", "pi-angle-down", "text-muted-color", "text-xs"], ["data-test-id", "imaging-library-p-menu-store", "appendTo", "body", 3, "model", "popup"], ["type", "button", "data-test-id", "imaging-library-button-store-info", "tooltipPosition", "bottom", 1, "text-muted-color", "hover:text-surface-300", "ml-1", "flex", "cursor-pointer", "items-center", "justify-center", 3, "click", "pTooltip"], [1, "pi", "pi-info-circle", "text-base"], [3, "onShow"], [1, "text-color", "w-72", "p-1"], [1, "flex", "items-center", "gap-3", "pb-3"], [1, "bg-primary-500/10", "border-primary-500/30", "flex", "h-10", "w-10", "shrink-0", "items-center", "justify-center", "rounded-md", "border"], [1, "text-primary-400"], [1, "min-w-0"], [1, "truncate", "font-semibold"], [1, "grid", "grid-cols-2", "gap-2", "pb-3"], [1, "bg-surface-800/70", "rounded-md", "py-2", "text-center"], [1, "text-base", "font-semibold", "tabular-nums"], [1, "text-muted-color", "text-[10px]", "tracking-wide", "uppercase"], [1, "bg-surface-800/70", "col-span-2", "rounded-md", "py-2", "text-center"], [1, "border-surface-700", "grid", "grid-cols-[auto_1fr]", "gap-x-4", "gap-y-1.5", "border-t", "pt-2.5", "text-xs"], [1, "text-muted-color"], [1, "text-right"], ["libEllipsisTip", "", "tooltipPosition", "bottom", 1, "min-w-0", "text-right", "font-mono", 3, "pTooltip"], ["styleClass", "h-2 w-24", 3, "showValue", "value"], [1, "w-8", "text-right", "text-sm"], [1, "text-sm"], ["data-test-id", "imaging-library-p-button-clear-filters", "icon", "pi pi-filter-slash", "severity", "secondary", "size", "small", "variant", "outlined", 3, "click", "label"]], template: function ImagingLibraryPageComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "header", 4)(1, "h1", 5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](4, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](5, "nav", 7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](6, ImagingLibraryPageComponent_Conditional_6_Template, 5, 3, "div", 8)(7, ImagingLibraryPageComponent_Conditional_7_Template, 16, 14); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](8, "div", 9)(9, "lib-series-cache-tasks"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](10, ImagingLibraryPageComponent_Conditional_10_Template, 5, 3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditionalCreate"](11, ImagingLibraryPageComponent_Conditional_11_Template, 2, 3, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](12, "p-button", 11); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipe"](13, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ImagingLibraryPageComponent_Template_p_button_click_12_listener() { return ctx.reload(); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](14, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](15, "lib-patient-library"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](3, 6, "imagingLibrary.title")); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx.loadingStores() ? 6 : 7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](ctx.totalProgress() > 0 && ctx.totalProgress() < 100 ? 10 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵconditional"](!ctx.detailsToolbar() ? 11 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpipeBind1"](13, 8, "patientList.reload"))("disabled", ctx.reloadDisabled()); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_3__.Button, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateModule, _dicom_importer_components_patient_library_patient_library_component__WEBPACK_IMPORTED_MODULE_16__.PatientLibraryComponent, primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_7__.ProgressBar, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__.ProgressSpinnerModule, primeng_progressspinner__WEBPACK_IMPORTED_MODULE_8__.ProgressSpinner, primeng_menu__WEBPACK_IMPORTED_MODULE_5__.Menu, primeng_popover__WEBPACK_IMPORTED_MODULE_6__.Popover, primeng_tooltip__WEBPACK_IMPORTED_MODULE_9__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_9__.Tooltip, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_13__.EllipsisTipDirective, _dicom_importer_components_patient_library_series_cache_tasks_component__WEBPACK_IMPORTED_MODULE_17__.SeriesCacheTasksComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_13__.FileSizePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 99957 /*!******************************************************************************!*\ !*** ./libs/feature/src/lib/imaging-library/live-analyses-page.component.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LiveAnalysesPageComponent: () => (/* binding */ LiveAnalysesPageComponent) /* harmony export */ }); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _dicom_importer_components_work_session_library_work_session_library_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../dicom-importer/components/work-session-library/work-session-library.component */ 88507); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 14975); class LiveAnalysesPageComponent { static ɵfac = function LiveAnalysesPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || LiveAnalysesPageComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineComponent"]({ type: LiveAnalysesPageComponent, selectors: [["lib-live-analyses-page"]], hostAttrs: [1, "dark", "flex", "h-full", "flex-col", "bg-surface-950", "text-color"], decls: 6, vars: 3, consts: [[1, "border-surface-800", "flex", "h-14", "shrink-0", "items-center", "gap-3", "border-b", "bg-(--p-app-chrome-page-header)", "px-5", "select-none"], [1, "font-semibold", "tracking-wide"], [1, "min-h-0", "flex-1"], [1, "block", "h-full"]], template: function LiveAnalysesPageComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵelementStart"](0, "header", 0)(1, "h1", 1); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵelementStart"](4, "div", 2); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵelement"](5, "lib-work-session-library", 3); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵpipeBind1"](3, 1, "imagingLibrary.liveAnalysesTitle"), " "); } }, dependencies: [_ngx_translate_core__WEBPACK_IMPORTED_MODULE_0__.TranslateModule, _dicom_importer_components_work_session_library_work_session_library_component__WEBPACK_IMPORTED_MODULE_1__.WorkSessionLibraryComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_0__.TranslatePipe], encapsulation: 2 }); } /***/ }, /***/ 72754 /*!***************************************************************************!*\ !*** ./libs/feature/src/lib/interaction-mode/interaction-mode.service.ts ***! \***************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ InteractionModeService: () => (/* binding */ InteractionModeService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/store */ 15585); class InteractionModeService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.AnnotationFacade); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.ProtocolFacade); _interactionMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.linkedSignal)(() => { const annotation = this.annotationFacade.annotationBeingCreated(); if (annotation !== undefined) { return { annotation, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.CREATE }; } return { type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.SELECT }; }, ...(ngDevMode ? [{ debugName: "_interactionMode" }] : [])); get interactionMode() { return this._interactionMode; } annotationAddingPointsTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { let annotation; const interactionMode = this._interactionMode(); const annotations = this.annotationFacade.annotationMap(); if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.ADD_POINTS) { annotation = annotations[interactionMode.annotationId]; } return annotation; }, ...(ngDevMode ? [{ debugName: "annotationAddingPointsTo" }] : [])); startAddingPoints(annotationId) { this._interactionMode.set({ annotationId, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.ADD_POINTS }); } clearMode() { if (this._interactionMode().type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.SELECT) { this._interactionMode.set({ type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.InteractionModeType.SELECT }); } } static ɵfac = function InteractionModeService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || InteractionModeService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: InteractionModeService, factory: InteractionModeService.ɵfac }); } /***/ }, /***/ 47136 /*!*********************************************************!*\ !*** ./libs/feature/src/lib/logging/logging.service.ts ***! \*********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ LoggingService: () => (/* binding */ LoggingService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var consola__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! consola */ 84544); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/utils */ 49585); class LoggingService { log = (0,consola__WEBPACK_IMPORTED_MODULE_1__.createConsola)({ level: (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_2__.IS_DEV_BUILD) ? 4 : 2 }); constructor() { this.log.withTag('other').wrapAll(); } getChildLogger(tag) { return this.log.withTag(tag); } static ɵfac = function LoggingService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || LoggingService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: LoggingService, factory: LoggingService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 14337 /*!***********************************************!*\ !*** ./libs/feature/src/lib/logging/utils.ts ***! \***********************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getLogger: () => (/* binding */ getLogger) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _logging_service__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logging.service */ 47136); function getLogger(name) { (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.assertInInjectionContext)(getLogger); return (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_logging_service__WEBPACK_IMPORTED_MODULE_1__.LoggingService).getChildLogger(name); } /***/ }, /***/ 42948 /*!*****************************************************************************************!*\ !*** ./libs/feature/src/lib/oauth-feature-pages/auth-wrapper/auth-wrapper.component.ts ***! \*****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AuthWrapperComponent: () => (/* binding */ AuthWrapperComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common_http__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common/http */ 19305); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/router */ 38709); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = (a0, a1) => ({ clientVersion: a0, backendVersion: a1 }); function AuthWrapperComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p", 12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "a", 14); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](2, 2, "auth.already-have-account"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](5, 4, "auth.sign-in"), " "); } } function AuthWrapperComponent_Conditional_27_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p", 12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "a", 15); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](2, 2, "auth.no-account"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](5, 4, "auth.create-one"), " "); } } function AuthWrapperComponent_Conditional_28_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p", 13); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind2"](2, 1, "auth.login-form.version-info", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction2"](4, _c0, ctx_r0.clientVersion, ctx_r0.backendVersion())), " "); } } class AuthWrapperComponent { authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.AuthService); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_5__.Router); environment = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.ENV); loading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(false, ...(ngDevMode ? [{ debugName: "loading" }] : [])); error = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "error" }] : [])); provider = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.Provider; clientVersion = this.environment.version ?? 'unknown'; backendVersion = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "backendVersion" }] : [])); constructor() { this.loadBackendVersion(); } currentUrl = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)(this.router.events.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_8__.filter)(event => event instanceof _angular_router__WEBPACK_IMPORTED_MODULE_5__.NavigationEnd), (0,rxjs__WEBPACK_IMPORTED_MODULE_9__.map)(event => event.urlAfterRedirects)), { initialValue: this.router.url }); isSignUp = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.currentUrl().startsWith('/sign-up'), ...(ngDevMode ? [{ debugName: "isSignUp" }] : [])); continueWith(provider) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const api = globalThis.electronAPI; const authUrl = `${_this.environment.apiUrl}/oauth/${provider}`; if (api && typeof api.openOAuth === 'function') { _this.loading.set(true); try { const { accessToken, refreshToken } = yield api.openOAuth(authUrl); if (accessToken && refreshToken) { _this.authService.setOauthTokens(accessToken, refreshToken); yield (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.firstValueFrom)(_this.authService.fetchUser()); yield _this.router.navigate([_this.environment.loginRouteRedirect]); } } catch (error) { _this.error.set(error instanceof _angular_common_http__WEBPACK_IMPORTED_MODULE_1__.HttpErrorResponse ? error.error?.error?.message : 'Login failed'); } finally { _this.loading.set(false); } } else { _this.authService.loginWith(provider); } })(); } loadBackendVersion() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const apiUrl = _this2.environment.apiUrl; if (!apiUrl || !(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.isValidBackendApiUrl)(apiUrl)) return; try { const response = yield fetch(`${(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.normalizeBackendApiUrl)(apiUrl)}/system/version`); if (!response.ok) return; const payload = yield response.json(); if (payload.version) _this2.backendVersion.set(payload.version); } catch { // Keep the unavailable fallback when the backend cannot be reached. } })(); } static ɵfac = function AuthWrapperComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AuthWrapperComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵdefineComponent"]({ type: AuthWrapperComponent, selectors: [["lib-auth-wrapper"]], decls: 29, vars: 20, consts: [[1, "bg-surface-950", "flex", "min-h-screen", "items-center", "justify-center"], [1, "animate-fade-in-up", "bg-surface-900", "w-full", "max-w-md", "rounded-2xl", "shadow-2xl"], [1, "p-8"], ["data-test-id", "auth-wrapper-div-logo", 1, "mb-4", "flex", "justify-center"], ["src", "assets/svg/logo.svg", "fill", "", "alt", "Logo", 1, "size-20"], [1, "text-color", "mb-4", "text-center", "text-xl", "font-bold"], [1, "text-md", "text-color", "mb-6", "text-center"], [1, "my-6", "flex", "items-center"], [1, "bg-surface-700", "h-px", "grow"], [1, "text-muted-color", "px-3", "text-sm"], [1, "space-y-2"], ["data-test-id", "auth-wrapper-button-google-sign-in", "type", "button", 1, "bg-surface-800", "text-surface-300", "hover:bg-surface-700", "flex", "w-full", "items-center", "justify-center", "rounded-lg", "border-0", "py-2", "transition", 3, "click"], [1, "text-muted-color", "mt-6", "text-center", "text-sm"], [1, "text-surface-500", "my-2", "text-center", "text-xs"], ["data-test-id", "auth-wrapper-a-sign-in", "routerLink", "/login", 1, "text-color", "underline"], ["data-test-id", "auth-wrapper-a-sign-up", "routerLink", "/sign-up", 1, "text-color", "underline"]], template: function AuthWrapperComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](4, "img", 4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](5, "h1", 5); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](9, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](11, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](13, "router-outlet"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](14, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](15, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](16, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](17); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](18, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](19, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](20, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](21, "div", 10)(22, "button", 11); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("click", function AuthWrapperComponent_Template_button_click_22_listener() { return ctx.continueWith(ctx.provider.GOOGLE); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](23); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](24, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](25, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](26, AuthWrapperComponent_Conditional_26_Template, 6, 6, "p", 12)(27, AuthWrapperComponent_Conditional_27_Template, 6, 6, "p", 12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](28, AuthWrapperComponent_Conditional_28_Template, 3, 7, "p", 13); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", ctx.isSignUp() ? _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](7, 6, "auth.welcome-message-new-user") : _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](8, 8, "auth.welcome-message-returning-user"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", ctx.isSignUp() ? _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](11, 10, "auth.welcome-subtitle-new-user") : _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](12, 12, "auth.welcome-subtitle-returning-user"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", ctx.isSignUp() ? _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](18, 14, "auth.sign-up-form.provider-sign-up-alternative-message") : _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](19, 16, "auth.login-form.provider-sign-in-alternative-message"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](24, 18, "auth.provider-sign-in.google"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx.isSignUp() ? 26 : 27); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](!ctx.isSignUp() ? 28 : -1); } }, dependencies: [_angular_router__WEBPACK_IMPORTED_MODULE_6__.RouterLink, _angular_router__WEBPACK_IMPORTED_MODULE_5__.RouterOutlet, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 40531 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/oauth-feature-pages/oauth-page.routes.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ oauthPageRoutes: () => (/* binding */ oauthPageRoutes) /* harmony export */ }); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _auth_wrapper_auth_wrapper_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./auth-wrapper/auth-wrapper.component */ 42948); const oauthPageRoutes = [{ canActivate: [_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_0__.authGuard, _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_0__.sessionCleanupGuard], children: [{ loadComponent: () => Promise.all(/*! import() */[__webpack_require__.e("common"), __webpack_require__.e("libs_feature_src_lib_oauth-feature-pages_login_login_component_ts")]).then(__webpack_require__.bind(__webpack_require__, /*! ./login/login.component */ 12578)).then(m => m.LoginComponent), path: 'login' }, { loadComponent: () => Promise.all(/*! import() */[__webpack_require__.e("common"), __webpack_require__.e("libs_feature_src_lib_oauth-feature-pages_sign-up_sign-up_component_ts")]).then(__webpack_require__.bind(__webpack_require__, /*! ./sign-up/sign-up.component */ 19026)).then(m => m.SignUpComponent), path: 'sign-up' }], component: _auth_wrapper_auth_wrapper_component__WEBPACK_IMPORTED_MODULE_1__.AuthWrapperComponent, path: '' }, { canActivate: [_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_0__.sessionCleanupGuard], loadComponent: () => __webpack_require__.e(/*! import() */ "libs_feature_src_lib_oauth-feature-pages_oauth-callback_oauth-callback_component_ts").then(__webpack_require__.bind(__webpack_require__, /*! ./oauth-callback/oauth-callback.component */ 11718)).then(m => m.OauthCallbackComponent), path: 'oauth-callback' }]; /***/ }, /***/ 76860 /*!*****************************************************************************************!*\ !*** ./libs/feature/src/lib/phase-selection-dialog/phase-selection-dialog.component.ts ***! \*****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PhaseSelectionDialogComponent: () => (/* binding */ PhaseSelectionDialogComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ count: a0 }); function PhaseSelectionDialogComponent_ng_template_2_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind2"](2, 1, "phaseSelection.selectedCount", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpureFunction1"](4, _c0, ctx_r1.selectedPhases().length)), " "); } } function PhaseSelectionDialogComponent_ng_template_2_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](0); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate1"](" ", ctx_r1.columnLabel, " "); } } function PhaseSelectionDialogComponent_ng_template_2_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](2, 1, "multiphase.rWaveLabel")); } } function PhaseSelectionDialogComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "tr")(1, "th", 7); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](2, "p-tableHeaderCheckbox", 8); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](3, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](4, PhaseSelectionDialogComponent_ng_template_2_Conditional_4_Template, 3, 6, "span", 9)(5, PhaseSelectionDialogComponent_ng_template_2_Conditional_5_Template, 1, 1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](6, PhaseSelectionDialogComponent_ng_template_2_Conditional_6_Template, 3, 3, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx_r1.selectedPhases().length > 0 ? 4 : 5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx_r1.gated ? 6 : -1); } } function PhaseSelectionDialogComponent_ng_template_4_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "td", 13); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { const phase_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate"](phase_r3.detail ?? "\u2014"); } } function PhaseSelectionDialogComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "tr", 10)(1, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelement"](2, "p-tableCheckbox", 11); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](3, "td")(4, "span", 12); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditionalCreate"](6, PhaseSelectionDialogComponent_ng_template_4_Conditional_6_Template, 2, 1, "td", 13); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); } if (rf & 2) { const phase_r3 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("pSelectableRow", phase_r3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("value", phase_r3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtextInterpolate"](phase_r3.label); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵconditional"](ctx_r1.gated ? 6 : -1); } } class PhaseSelectionDialogComponent { dialogRef = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DynamicDialogRef); config = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DynamicDialogConfig); phases = this.config.data?.phases ?? []; columnLabel = this.config.data?.columnLabel ?? ''; // Gated series carry an R-R value per phase → show the R-R column; non-gated volumes don't. gated = this.phases.some(phase => phase.detail !== undefined); // All phases selected initially; the header checkbox toggles them. selectedPhases = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([...this.phases], ...(ngDevMode ? [{ debugName: "selectedPhases" }] : [])); canConfirm() { return this.selectedPhases().length > 0; } confirm() { if (!this.canConfirm()) return; // Return ids in the original phase order, not selection order. const selectedIds = new Set(this.selectedPhases().map(phase => phase.id)); this.dialogRef.close(this.phases.filter(phase => selectedIds.has(phase.id)).map(p => p.id)); } cancel() { this.dialogRef.close(undefined); } static ɵfac = function PhaseSelectionDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PhaseSelectionDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵdefineComponent"]({ type: PhaseSelectionDialogComponent, selectors: [["lib-phase-selection-dialog"]], decls: 11, vars: 11, consts: [["header", ""], ["body", ""], [1, "flex", "flex-col", "gap-3"], ["dataKey", "id", "selectionMode", "multiple", "scrollHeight", "20rem", 3, "selectionChange", "value", "selection", "scrollable"], [1, "flex", "justify-end", "gap-2", "pt-2"], ["data-test-id", "phase-selection-dialog-p-button-cancel", "severity", "secondary", 3, "click", "outlined", "label"], ["data-test-id", "phase-selection-dialog-p-button-confirm", 3, "click", "label", "disabled"], [2, "width", "3rem"], ["data-test-id", "phase-selection-dialog-p-tableHeaderCheckbox-select-all"], [1, "text-primary-500"], [3, "pSelectableRow"], [3, "value"], [1, "text-sm", "font-medium"], [1, "text-muted-color", "text-sm"]], template: function PhaseSelectionDialogComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](0, "div", 2)(1, "p-table", 3); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayListener"]("selectionChange", function PhaseSelectionDialogComponent_Template_p_table_selectionChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayBindingSet"](ctx.selectedPhases, $event) || (ctx.selectedPhases = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplate"](2, PhaseSelectionDialogComponent_ng_template_2_Template, 7, 2, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplateRefExtractor"])(4, PhaseSelectionDialogComponent_ng_template_4_Template, 7, 4, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](6, "div", 4)(7, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function PhaseSelectionDialogComponent_Template_p_button_click_7_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx.cancel()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementStart"](9, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipe"](10, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵlistener"]("click", function PhaseSelectionDialogComponent_Template_p_button_click_9_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx.confirm()); }); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("value", ctx.phases); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵtwoWayProperty"]("selection", ctx.selectedPhases); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("scrollable", true); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("outlined", true)("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](8, 7, "phaseSelection.cancel")); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_6__["ɵɵpipeBind1"](10, 9, "phaseSelection.confirm"))("disabled", !ctx.canConfirm()); } }, dependencies: [_angular_forms__WEBPACK_IMPORTED_MODULE_1__.FormsModule, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateModule, primeng_button__WEBPACK_IMPORTED_MODULE_3__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_3__.Button, primeng_table__WEBPACK_IMPORTED_MODULE_5__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_5__.Table, primeng_table__WEBPACK_IMPORTED_MODULE_5__.SelectableRow, primeng_table__WEBPACK_IMPORTED_MODULE_5__.TableCheckbox, primeng_table__WEBPACK_IMPORTED_MODULE_5__.TableHeaderCheckbox, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 3124 /*!***************************************************************************************!*\ !*** ./libs/feature/src/lib/phase-selection-dialog/phase-selection-dialog.service.ts ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PhaseSelectionDialogService: () => (/* binding */ PhaseSelectionDialogService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _phase_selection_dialog_component__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./phase-selection-dialog.component */ 76860); class PhaseSelectionDialogService { dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DialogService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); database = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__.DicomDatabaseService); // Metadata-only separation + prompt — runs before any volume loads. selectForSeries(studyUid, seriesUid, storeUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const { phases } = yield (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__.separateSeriesPhases)(_this.database, studyUid, seriesUid, storeUid); return _this.selectFromPhases(phases); })(); } // Single-phase shows no dialog. selectFromPhases(phases) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (phases.length <= 1) { return phases.map(phase => phase.id); } const triggerUnit = _this2.translate.instant('multiphase.triggerUnit'); const items = phases.map(phase => ({ detail: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.formatPhaseIdentification)(phase.identification, { triggerUnit }), id: phase.id, label: phase.label })); // "Phase" only when the volumes carry cardiac timing (an R-R value was derived); else "Volume". const gated = items.some(item => item.detail !== undefined); const columnLabel = _this2.translate.instant(gated ? 'multiphase.phase' : 'multiphase.volume'); const dialogReference = _this2.dialogService.open(_phase_selection_dialog_component__WEBPACK_IMPORTED_MODULE_7__.PhaseSelectionDialogComponent, { data: { columnLabel, phases: items }, header: _this2.translate.instant('phaseSelection.header'), resizable: false, width: '32rem' }); if (!dialogReference) return undefined; const result = yield (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.firstValueFrom)(dialogReference.onClose); return result; })(); } static ɵfac = function PhaseSelectionDialogService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PhaseSelectionDialogService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: PhaseSelectionDialogService, factory: PhaseSelectionDialogService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 18194 /*!***********************************************************!*\ !*** ./libs/feature/src/lib/pipes/modality-label.pipe.ts ***! \***********************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ModalityLabelPipe: () => (/* binding */ ModalityLabelPipe) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 14975); class ModalityLabelPipe { translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateService); transform(value) { if (!value) { return this.translate.instant('modality.unknown'); } const key = `modality.${value.toLowerCase()}`; const translation = this.translate.instant(key); return translation === key ? value : translation; } static ɵfac = function ModalityLabelPipe_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ModalityLabelPipe)(); }; static ɵpipe = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefinePipe"]({ name: "modalityLabel", type: ModalityLabelPipe, pure: true }); } /***/ }, /***/ 23093 /*!*************************************************************!*\ !*** ./libs/feature/src/lib/protocols/definitions/index.ts ***! \*************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DEFAULT_PROTOCOLS: () => (/* binding */ DEFAULT_PROTOCOLS), /* harmony export */ RelativeTestProtocol: () => (/* reexport safe */ _relative_test_protocol__WEBPACK_IMPORTED_MODULE_0__.RelativeTestProtocol), /* harmony export */ TaviProtocol: () => (/* reexport safe */ _tavi_protocol__WEBPACK_IMPORTED_MODULE_1__.TaviProtocol) /* harmony export */ }); /* harmony import */ var _relative_test_protocol__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./relative-test.protocol */ 34682); /* harmony import */ var _tavi_protocol__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tavi.protocol */ 12541); const DEFAULT_PROTOCOLS = [_tavi_protocol__WEBPACK_IMPORTED_MODULE_1__.TaviProtocol]; /***/ }, /***/ 34682 /*!******************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/definitions/relative-test.protocol.ts ***! \******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RelativeTestProtocol: () => (/* binding */ RelativeTestProtocol) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/ui */ 79048); // Figma-sourced colors, one per placeholder group. The picks are arbitrary, // this fixture only needs the groups to be visually distinct. const COLOR_AB = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['sinus-point']; const COLOR_CD = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.appColorTokens.amber['400']; const COLOR_ABCD = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.appColorTokens.blue['500']; const COLOR_EF = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.appColorTokens.neutral['400']; const COLOR_ABCDEF = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.appColorTokens.neutral['900']; const COLOR_OTHER = _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.appColorTokens.green['500']; // Define protocol/placeholder ids here for easy reference / clearer relationship definitions const PROTOCOL_ID_RELTEST = '3fd5bdbe-9810-40d8-ac49-084cd625b8a0'; const PLACEHOLDER_ID_POINT_A = '99d32d70-74da-449c-9b7d-5a530439a380'; const PLACEHOLDER_ID_POINT_B = 'cda3ffbe-5e96-4d2d-ae00-cf8096512474'; const PLACEHOLDER_ID_AB_DISTANCE = '4a87118a-1f28-4c78-8ca4-15e71c827e94'; const PLACEHOLDER_ID_POINT_C = '802d04c2-9738-4f6a-b814-1b4225495737'; const PLACEHOLDER_ID_POINT_D = '29783463-df18-481c-95b6-6e5bce9d87b2'; const PLACEHOLDER_ID_CD_DISTANCE = '29562f4d-0c54-475e-9e88-91f8fad9ca1f'; const PLACEHOLDER_ID_ABCD_DISTANCE = '6f53af52-08c4-407c-afce-fb3f9086e66f'; const PLACEHOLDER_ID_POINT_E = '9f36fd39-18b7-47a6-acd3-b853a472fefe'; const PLACEHOLDER_ID_POINT_F = '5130ce4b-b654-4dd3-801b-6f55f7642e4c'; const PLACEHOLDER_ID_EF_DISTANCE = '8b848d8a-469a-45aa-8fd0-fe0508b41138'; const PLACEHOLDER_ID_ABCDEF_DISTANCE = 'c5299064-c1b7-4390-aefe-de1a0bfcca54'; const CLOSEST_DISTANCE = 'closest-distance-between-annotations'; // Not to be used in production - just for testing that relative measurements populate as expected const RelativeTestProtocol = { id: PROTOCOL_ID_RELTEST, name: 'Relative Measurements Test', placeholders: [(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_AB, id: PLACEHOLDER_ID_POINT_A, name: 'Point A' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_OTHER, name: 'OTHER' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_AB, id: PLACEHOLDER_ID_POINT_B, name: 'Point B' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_OTHER, name: 'OTHER2' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: COLOR_AB, id: PLACEHOLDER_ID_AB_DISTANCE, name: 'A-B Distance', relationship: { sourceIds: [PLACEHOLDER_ID_POINT_A, PLACEHOLDER_ID_POINT_B], type: CLOSEST_DISTANCE } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_CD, id: PLACEHOLDER_ID_POINT_C, name: 'Point C' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_CD, id: PLACEHOLDER_ID_POINT_D, name: 'Point D' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: COLOR_CD, id: PLACEHOLDER_ID_CD_DISTANCE, name: 'C-D Distance', relationship: { sourceIds: [PLACEHOLDER_ID_POINT_C, PLACEHOLDER_ID_POINT_D], type: CLOSEST_DISTANCE } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: COLOR_ABCD, id: PLACEHOLDER_ID_ABCD_DISTANCE, name: 'AB-CD Distance', relationship: { sourceIds: [PLACEHOLDER_ID_AB_DISTANCE, PLACEHOLDER_ID_CD_DISTANCE], type: CLOSEST_DISTANCE } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_EF, id: PLACEHOLDER_ID_POINT_E, name: 'Point E' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: COLOR_EF, id: PLACEHOLDER_ID_POINT_F, name: 'Point F' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: COLOR_EF, id: PLACEHOLDER_ID_EF_DISTANCE, name: 'E-F Distance', relationship: { sourceIds: [PLACEHOLDER_ID_POINT_E, PLACEHOLDER_ID_POINT_F], type: CLOSEST_DISTANCE } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: COLOR_ABCDEF, id: PLACEHOLDER_ID_ABCDEF_DISTANCE, name: 'ABCD-EF Distance', relationship: { sourceIds: [PLACEHOLDER_ID_ABCD_DISTANCE, PLACEHOLDER_ID_EF_DISTANCE], type: CLOSEST_DISTANCE } })] }; /***/ }, /***/ 12541 /*!*********************************************************************!*\ !*** ./libs/feature/src/lib/protocols/definitions/tavi.protocol.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TaviProtocol: () => (/* binding */ TaviProtocol) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/ui */ 79048); // Define protocol/placeholder ids here for easy reference / clearer relationship definitions const PROTOCOL_ID_TAVI = _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.TAVI_PROTOCOL_ID; const PLACEHOLDER_ID_AV_ANNULUS = '23967a10-9b37-4467-895a-1b678cca6dc2'; const PLACEHOLDER_ID_LCC_NADIR = 'c1c0f1e3-fc4c-4b17-b6b8-c6501834ff19'; const PLACEHOLDER_ID_RCC_NADIR = '35a56ca9-c484-433c-973e-24409cb975d7'; const PLACEHOLDER_ID_NCC_NADIR = '00b786f7-f8ec-43a8-bbbb-90deb1ce4bb6'; const PLACEHOLDER_ID_SOV_CONTOUR = '5b0c20c7-94ee-4ea8-ab7b-b9952c85e8dd'; const PLACEHOLDER_ID_COMMISSURE_1 = 'baee0a2c-e0b7-5202-b0d5-d7583ead10f5'; const PLACEHOLDER_ID_COMMISSURE_2 = '9a279730-05ca-59f2-a861-3c155d8f88be'; const PLACEHOLDER_ID_COMMISSURE_3 = 'f6d09d1a-ca66-5e28-8da0-3bf8a24902fe'; const PLACEHOLDER_ID_SINUS_1 = 'dbc9f17a-93e4-559b-a25d-e602ab3c98f9'; const PLACEHOLDER_ID_SINUS_2 = '613f9d24-efdc-5fbd-bd7e-c335d2ba1a76'; const PLACEHOLDER_ID_SINUS_3 = 'ca687a0d-908b-5211-b76e-c2d0e7e95e58'; const PLACEHOLDER_ID_LEFT_CORONARY_HEIGHT = '8dc0516e-0d3a-53d8-8923-a96e7ec8f9a6'; const PLACEHOLDER_ID_RIGHT_CORONARY_HEIGHT = '45c3d9d0-c234-5bb0-97a1-bed2d8c79ac3'; const PLACEHOLDER_ID_SINOTUBULAR_JUNCTION = '64889f29-e86f-46db-acdd-2cb252d2a18b'; const PLACEHOLDER_ID_LVOT_CONTOUR = '724af5bf-e4ca-508e-84eb-f7f797b4ffef'; const ATTACHED_POINT = 'attached-point'; const TaviProtocol = { form: { // Unless proceed is true + the form is valid, we can't proceed with the rest canProceedRule: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('proceed', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(true)), fields: [{ key: 'variant', options: [{ value: 'tricuspid' }, { value: 'tricommissural-functional-bicuspid' }, { value: 'bav-type-0' }, { value: 'bav-type-1-rl' }, { value: 'bav-type-1-ln' }, { value: 'bav-type-1-rn' }, { value: 'bav-type-2' }, { value: 'unicuspid' }, { value: 'tav-balloon-expandable' }, { value: 'tav-self-expanding' }, { value: 'sav-tissue' }, { value: 'sav-metallic' }, { value: 'undetermined' }], representation: 'select', valueType: 'text' }, { key: 'artifacts', options: [{ exclusive: true, value: 'none' }, { value: 'calcium-blooming' }, { value: 'contrast-related-streaks' }, { value: 'metal-related-streaks' }, { value: 'high-noise-level' }, { value: 'poor-contrast-opacification' }, { value: 'banding-stitching' }], representation: 'checkboxes', valueType: 'multi-text' }, { key: 'imageQuality', options: [{ value: 'good' }, { value: 'fair' }, { value: 'poor' }], representation: 'select', valueType: 'text' }, { key: 'proceed', representation: 'radio', valueType: 'boolean' }, { key: 'proceedReason', options: [{ value: 'n1' }, { value: 'n2' }, { value: 'n3' }, { value: 'n4' }, { value: 'n5' }], representation: 'select', valueType: 'text', visibleWhen: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('proceed', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(false)) }, { key: 'comments', representation: 'textarea', valueType: 'text' }], name: 'Classification and quality', required: true, validation: { artifacts: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)(), // Comments must be added when the other reason is selected comments: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.iff)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.and)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('proceed', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(false)), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('proceedReason', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)('n5'))), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)('protocolDef.tavi.form.error.notProceeding')), imageQuality: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)(), proceed: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.and)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)(), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.iff)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('imageQuality', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)('poor')), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(false, 'protocolDef.tavi.form.error.poorImageQuality')), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.iff)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('variant', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.oneOf)(['tricuspid', 'tricommissural-functional-bicuspid', 'bav-type-1-rl', 'bav-type-1-ln', 'bav-type-1-rn'])), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)(), // If one of the above is selected, can still be skipped for other reasons (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(false, 'protocolDef.tavi.form.error.cannotProceedWithSelectedVariant'))), proceedReason: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.iff)((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.forField)('proceed', (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.equals)(false)), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)()), variant: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)(), volumeIdentifier: (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.required)() } }, id: PROTOCOL_ID_TAVI, name: 'TAVI/TAVR', placeholders: [(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.annulus, id: PLACEHOLDER_ID_AV_ANNULUS, name: 'Aortic valve annulus' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['nadir-lcc'], id: PLACEHOLDER_ID_LCC_NADIR, name: 'LCC nadir', relationship: { sourceIds: [PLACEHOLDER_ID_AV_ANNULUS], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['nadir-rcc'], id: PLACEHOLDER_ID_RCC_NADIR, name: 'RCC nadir', relationship: { sourceIds: [PLACEHOLDER_ID_AV_ANNULUS], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['nadir-ncc'], id: PLACEHOLDER_ID_NCC_NADIR, name: 'NCC nadir', relationship: { sourceIds: [PLACEHOLDER_ID_AV_ANNULUS], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['coronary-height-left'], id: PLACEHOLDER_ID_LEFT_CORONARY_HEIGHT, name: 'Left coronary height', relationship: { sourceIds: [PLACEHOLDER_ID_AV_ANNULUS], type: 'projected-distance' } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.DISTANCE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['coronary-height-right'], id: PLACEHOLDER_ID_RIGHT_CORONARY_HEIGHT, name: 'Right coronary height', relationship: { sourceIds: [PLACEHOLDER_ID_AV_ANNULUS], type: 'projected-distance' } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.sov, id: PLACEHOLDER_ID_SOV_CONTOUR, name: 'SoV contour' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.commissure, id: PLACEHOLDER_ID_COMMISSURE_1, name: 'Commissure 1', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.commissure, id: PLACEHOLDER_ID_COMMISSURE_2, name: 'Commissure 2', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.commissure, id: PLACEHOLDER_ID_COMMISSURE_3, name: 'Commissure 3', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['sinus-point'], id: PLACEHOLDER_ID_SINUS_1, name: 'Sinus 1', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['sinus-point'], id: PLACEHOLDER_ID_SINUS_2, name: 'Sinus 2', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.POINT, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors['sinus-point'], id: PLACEHOLDER_ID_SINUS_3, name: 'Sinus 3', relationship: { sourceIds: [PLACEHOLDER_ID_SOV_CONTOUR], type: ATTACHED_POINT } }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.stj, id: PLACEHOLDER_ID_SINOTUBULAR_JUNCTION, name: 'STJ contour' }), (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.placeholder)({ annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_1__.AnnotationSourceType.CLOSED_SPLINE, color: _tomoverse_ui__WEBPACK_IMPORTED_MODULE_2__.annotationHexColors.lvot, id: PLACEHOLDER_ID_LVOT_CONTOUR, name: 'LVOT contour' })] }; /***/ }, /***/ 61632 /*!*************************************************!*\ !*** ./libs/feature/src/lib/protocols/index.ts ***! \*************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DEFAULT_PROTOCOLS: () => (/* reexport safe */ _definitions__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_PROTOCOLS), /* harmony export */ PlaceholderCardComponent: () => (/* reexport safe */ _placeholder_card_placeholder_card_component__WEBPACK_IMPORTED_MODULE_1__.PlaceholderCardComponent), /* harmony export */ ProtocolCreationService: () => (/* reexport safe */ _protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_2__.ProtocolCreationService), /* harmony export */ RelativeTestProtocol: () => (/* reexport safe */ _definitions__WEBPACK_IMPORTED_MODULE_0__.RelativeTestProtocol), /* harmony export */ TaviProtocol: () => (/* reexport safe */ _definitions__WEBPACK_IMPORTED_MODULE_0__.TaviProtocol) /* harmony export */ }); /* harmony import */ var _definitions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./definitions */ 23093); /* harmony import */ var _placeholder_card_placeholder_card_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./placeholder-card/placeholder-card.component */ 37076); /* harmony import */ var _protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./protocol-creation-service/protocol-creation.service */ 88304); /***/ }, /***/ 37076 /*!***************************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/placeholder-card/placeholder-card.component.ts ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PlaceholderCardComponent: () => (/* binding */ PlaceholderCardComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../card-theme/card-theme */ 92147); /* harmony import */ var _protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../protocol-creation-service/protocol-creation.service */ 88304); const _c0 = ["nameLabel"]; const _c1 = () => ({ color: "var(--p-accordion-header-toggle-icon-color)" }); const _c2 = a0 => ({ secondary: a0 }); const _c3 = a0 => ({ outlined: a0 }); function PlaceholderCardComponent_ng_container_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementContainer"](0); } } function PlaceholderCardComponent_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelement"](0, "span", 13); } } function PlaceholderCardComponent_ng_container_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementContainer"](0); } } function PlaceholderCardComponent_ng_container_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementContainer"](0); } } function PlaceholderCardComponent_ng_template_11_ng_container_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementContainer"](0); } } function PlaceholderCardComponent_ng_template_11_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "div", 14)(1, "span", 15, 6); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplate"](4, PlaceholderCardComponent_ng_template_11_ng_container_4_Template, 1, 0, "ng-container", 10); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵnextContext"](); const createBtn_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵreference"](16); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("pTooltip", ctx_r0.isNameClamped() ? ctx_r0.placeholder().name : undefined); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtextInterpolate1"](" ", ctx_r0.placeholder().name, " "); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("ngTemplateOutlet", createBtn_r2); } } function PlaceholderCardComponent_ng_template_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelement"](1, "lib-icon", 16); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵclassMap"](ctx_r0.cn("flex size-7.5 shrink-0 items-center justify-center rounded-full", ctx_r0.active() ? "bg-surface-900" : "bg-surface-800")); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵstyleProp"]("color", ctx_r0.placeholder().color); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("icon", ctx_r0.placeholder().annotationType); } } function PlaceholderCardComponent_ng_template_15_Conditional_0_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelement"](0, "lib-icon", 20); } } function PlaceholderCardComponent_ng_template_15_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵlistener"]("click", function PlaceholderCardComponent_ng_template_15_Conditional_0_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r0.onCreateClick()); }); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplate"](2, PlaceholderCardComponent_ng_template_15_Conditional_0_ng_template_2_Template, 1, 0, "ng-template", null, 7, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵpureFunction1"](7, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵpureFunction1"](5, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵpureFunction0"](4, _c1))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵpipeBind1"](1, 2, "protocols.createAnnotation")); } } function PlaceholderCardComponent_ng_template_15_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelement"](0, "span", 18); } } function PlaceholderCardComponent_ng_template_15_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵconditionalCreate"](0, PlaceholderCardComponent_ng_template_15_Conditional_0_Template, 4, 9, "p-button", 17)(1, PlaceholderCardComponent_ng_template_15_Conditional_1_Template, 1, 0, "span", 18); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵconditional"](ctx_r0.showCreateButton() ? 0 : 1); } } function PlaceholderCardComponent_ng_template_17_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelement"](0, "div", 21); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵstyleProp"]("background-color", ctx_r0.active() ? ctx_r0.placeholder().color : ""); } } const TOKEN_SURFACE_200 = '{surface.200}'; const TOKEN_SURFACE_300 = '{surface.300}'; const TOKEN_SURFACE_500 = '{surface.500}'; const DARK_CARD_THEME = { active: { bg: '{surface.800}', hover: TOKEN_SURFACE_200, icon: TOKEN_SURFACE_500, text: '{surface.100}' }, default: { bg: '{app.surface.card}', hover: TOKEN_SURFACE_300, icon: TOKEN_SURFACE_500, text: '{surface.500}' }, disabled: { bg: '{app.surface.card}', hover: TOKEN_SURFACE_500, icon: TOKEN_SURFACE_500, text: TOKEN_SURFACE_500 } }; class PlaceholderCardComponent { placeholder = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "placeholder" }] : [])); annotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(...(ngDevMode ? [undefined, { debugName: "annotation" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); active = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "active" }] : [])); disabled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "disabled" }] : [])); host = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.ElementRef); protocolCreation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_14__.ProtocolCreationService); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.ProtocolFacade); nameLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild)('nameLabel', ...(ngDevMode ? [{ debugName: "nameLabel" }] : [])); isNameClamped = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(false, ...(ngDevMode ? [{ debugName: "isNameClamped" }] : [])); filled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => !!this.annotation(), ...(ngDevMode ? [{ debugName: "filled" }] : [])); showCreateButton = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const active = this.active(); const disabled = this.disabled(); const filled = this.filled(); const placeholder = this.placeholder(); const { instance } = this.protocolFacade.activeProtocol(); return !active && !disabled && !filled && !(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_9__.canPlaceholderBeAutocreated)(placeholder) && instance && (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_9__.canPlaceholderBeCompleted)(placeholder, instance); }, ...(ngDevMode ? [{ debugName: "showCreateButton" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.afterEveryRender)(() => { const element = this.nameLabel()?.nativeElement; if (!element) return; const clamped = element.scrollHeight > element.clientHeight; if (clamped !== this.isNameClamped()) this.isNameClamped.set(clamped); }); } mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const pt = this.pt(); const state = this.cardState(); const hoverClass = ['active', 'disabled'].includes(state) ? '' : _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_13__.CARD_HOVER_CLASS; return { ...pt, header: { ...pt?.header, root: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.cn)('flex-row gap-3 rounded-none pr-1 justify-start', hoverClass, pt?.header?.root), toggleicon: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.cn)('toggle-icon', pt?.header?.toggleicon) }, panel: { ...pt?.panel, root: { class: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.cn)('py-0 flex w-full border-none', hoverClass, pt?.panel?.root, state === 'disabled' && 'pointer-events-none'), style: { backgroundColor: 'var(--p-accordion-header-background)' } } } }; }, ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_13__.buildCardDt)(DARK_CARD_THEME[this.cardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_13__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.cn; cardState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const isActive = this.active(); const isDisabled = this.disabled(); if (isDisabled) return 'disabled'; if (isActive) return 'active'; return 'default'; }, ...(ngDevMode ? [{ debugName: "cardState" }] : [])); onCreateClick() { this.protocolCreation.start(this.placeholder()); } scrollTo() { this.host.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } static ɵfac = function PlaceholderCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PlaceholderCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵdefineComponent"]({ type: PlaceholderCardComponent, selectors: [["lib-placeholder-card"]], viewQuery: function PlaceholderCardComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵviewQuerySignal"](ctx.nameLabel, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵqueryAdvance"](); } }, inputs: { placeholder: [1, "placeholder"], annotation: [1, "annotation"], pt: [1, "pt"], active: [1, "active"], disabled: [1, "disabled"] }, decls: 19, vars: 11, consts: [["panel", ""], ["toggleicon", ""], ["headerTitle", ""], ["cardIcon", ""], ["createBtn", ""], ["accentBar", ""], ["nameLabel", ""], ["icon", ""], [1, "grow", 3, "pt", "dt", "value"], [3, "pt"], [4, "ngTemplateOutlet"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-3", "py-0.5"], [1, "ml-2.5", "size-3"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], [1, "line-clamp-2", "wrap-anywhere", 3, "pTooltip"], [1, "size-(--p-app-icon-size-sm)", 3, "icon"], ["data-test-id", "placeholder-card-p-button-create-annotation", "severity", "secondary", "outlined", "", "size", "small", 3, "dt", "pTooltip"], [1, "size-4", "h-[34px]"], ["data-test-id", "placeholder-card-p-button-create-annotation", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "dt", "pTooltip"], ["icon", "plus", 1, "text-surface-200", "size-(--p-app-icon-size-xs)"], [1, "absolute", "top-0", "left-0", "h-full", "w-1"]], template: function PlaceholderCardComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "div")(1, "p-accordion-panel", 8, 0)(3, "p-accordion-header", 9); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplate"](4, PlaceholderCardComponent_ng_container_4_Template, 1, 0, "ng-container", 10)(5, PlaceholderCardComponent_ng_template_5_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](7, "div", 11)(8, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplate"](9, PlaceholderCardComponent_ng_container_9_Template, 1, 0, "ng-container", 10)(10, PlaceholderCardComponent_ng_container_10_Template, 1, 0, "ng-container", 10); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"]()()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplate"](11, PlaceholderCardComponent_ng_template_11_Template, 5, 3, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"])(13, PlaceholderCardComponent_ng_template_13_Template, 2, 5, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"])(15, PlaceholderCardComponent_ng_template_15_Template, 2, 1, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"])(17, PlaceholderCardComponent_ng_template_17_Template, 1, 2, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { const headerTitle_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵreference"](12); const cardIcon_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵreference"](14); const accentBar_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵreference"](18); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵclassMap"](ctx.cn("group border-surface-800 flex w-full overflow-hidden border-b", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", ctx.placeholder().id); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r6); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r5); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("ngTemplateOutlet", headerTitle_r4); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_6__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_6__.AccordionPanel, primeng_button__WEBPACK_IMPORTED_MODULE_7__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.IconComponent, _angular_common__WEBPACK_IMPORTED_MODULE_0__.NgTemplateOutlet, primeng_tooltip__WEBPACK_IMPORTED_MODULE_8__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 88304 /*!***********************************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/protocol-creation-service/protocol-creation.service.ts ***! \***********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ProtocolCreationService: () => (/* binding */ ProtocolCreationService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../logging/utils */ 14337); /* harmony import */ var _protocol_form_dialog_protocol_form_dialog_component__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../protocol-form-dialog/protocol-form-dialog.component */ 62472); class ProtocolCreationService { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_8__.getLogger)(ProtocolCreationService.name); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.AnnotationFacade); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.ProtocolFacade); dialog = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DialogService); activeProtocolForm = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { definition } = this.protocolFacade.activeProtocol(); return definition?.form; }, ...(ngDevMode ? [{ debugName: "activeProtocolForm" }] : [])); _activePlaceholder = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "_activePlaceholder" }] : [])); activePlaceholder = this._activePlaceholder.asReadonly(); activePlaceholderFilled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const placeholder = this.activePlaceholder(); const { instance } = this.protocolFacade.activeProtocol(); return placeholder && instance?.placeholderMappings[placeholder.id] !== undefined; }, ...(ngDevMode ? [{ debugName: "activePlaceholderFilled" }] : [])); _creationSub = this.annotationFacade.creations$.subscribe(([createdId]) => { const placeholder = this.activePlaceholder(); const { definition, instance } = this.protocolFacade.activeProtocol(); if (placeholder && definition && instance && createdId) { this.protocolFacade.fillPlaceholder(definition.id, placeholder.id, createdId); } }); isEmpty = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition || !instance) { return true; } return Object.keys(instance.placeholderMappings).length === 0; }, ...(ngDevMode ? [{ debugName: "isEmpty" }] : [])); isBeingCreated = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.activePlaceholder() !== undefined, ...(ngDevMode ? [{ debugName: "isBeingCreated" }] : [])); progress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition || !instance) { return; } return { current: Object.keys(instance.placeholderMappings).length + 1, total: definition.placeholders.length }; }, ...(ngDevMode ? [{ debugName: "progress" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.DestroyRef).onDestroy(() => { this._creationSub.unsubscribe(); }); } tryCreatingAnnotation(placeholder, instance) { if (!placeholder || !instance) { return; } const annotation = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.createAnnotationFromPlaceholder)(placeholder, instance); if (annotation) { if (!(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canPlaceholderBeCompleted)(placeholder, instance)) { this.goToNextPlaceholder(); } else if ((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canPlaceholderBeAutocreated)(placeholder)) { const annotationMap = this.annotationFacade.annotationMap(); const sources = placeholder.relationship?.sourceIds.map(placeholderId => { const annotationId = instance.placeholderMappings[placeholderId]; if (!annotationId) { return; } return annotationMap[annotationId]; }).filter(annotation => annotation !== undefined) ?? []; this.annotationFacade.addAnnotations((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_7__.updateRelativeMeasurement)(annotation, sources)); } else { this.annotationFacade.creatingAnnotation(annotation); } } } /** * Start the Protocol creation process, optionally at a specified placeholder. * Only works if there is an active protocol and the placeholder is part of it. */ start(placeholder) { const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition) { return; } const form = this.activeProtocolForm(); if (form && !(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canProceedFromProtocolForm)(form, instance?.formValues)) { this.handleProtocolFormInFlow(); return; } // Ensure provided placeholder is part of active protocol if (placeholder && !definition.placeholders.some(({ id }) => id === placeholder.id)) { this.log.warn('Placeholder received for different protocol'); return; } const startingPlaceholder = placeholder ?? (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getNextPlaceholder)(definition, instance); if (startingPlaceholder) { this._activePlaceholder.set(startingPlaceholder); } this.handleRelativePlaceholders(); } stop() { this._activePlaceholder.set(undefined); } cancelCurrentStep() { const placeholder = this.activePlaceholder(); const { instance } = this.protocolFacade.activeProtocol(); if (!instance || !placeholder) { return false; } // Cancel any in-progress annotations this.annotationFacade.cancelAnnotationCreation(); // If this placeholder already has an annotation, delete it if (this.activePlaceholderFilled()) { const toDelete = instance.placeholderMappings[placeholder.id]; if (toDelete) { this.annotationFacade.deleteAnnotations([toDelete]); } } // Unset the current placeholder this._activePlaceholder.set(undefined); return true; } restartCurrentStep() { const placeholder = this.activePlaceholder(); const { instance } = this.protocolFacade.activeProtocol(); if (!instance || !placeholder) { return; } // If this placeholder already has an annotation, delete it if (this.activePlaceholderFilled()) { const toDelete = instance.placeholderMappings[placeholder.id]; if (toDelete) { this.annotationFacade.deleteAnnotations([toDelete]); } } } undo() { console.log('undo()'); const placeholder = this.activePlaceholder(); const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition || !instance || !placeholder) { return; } const previous = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getPreviousPlaceholder)(definition, instance, placeholder.id); if (previous) { console.log('undo to', previous); const annotationId = instance.placeholderMappings[previous.id]; if (annotationId !== undefined) { this.annotationFacade.deleteAnnotations([annotationId]); } this._activePlaceholder.set(previous); } } clear() { const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition || !instance) { return; } const toDeleteIds = Object.values(instance.placeholderMappings); if (toDeleteIds.length > 0) { this.annotationFacade.deleteAnnotations(toDeleteIds); } this.protocolFacade.clearFormValues(instance.protocolId); } goToNextPlaceholder() { this._activePlaceholder.update(previous => { const { definition, instance } = this.protocolFacade.activeProtocol(); if (!definition || !instance) { return; } return (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getNextPlaceholder)(definition, instance, { afterPlaceholderId: previous?.id, loopBack: true, prioritizeAutoCreate: true }); }); this.handleRelativePlaceholders(); } handleCurrentPlaceholder() { const placeholder = this._activePlaceholder(); if (placeholder) { const { instance } = this.protocolFacade.activeProtocol(); this.tryCreatingAnnotation(placeholder, instance); } } openProtocolForm() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const formDefinition = _this.activeProtocolForm(); if (formDefinition === undefined) { return false; } const dialog = _this.dialog.open(_protocol_form_dialog_protocol_form_dialog_component__WEBPACK_IMPORTED_MODULE_9__.ProtocolFormDialog, { closeOnEscape: true, header: formDefinition.name, modal: true, pt: { content: { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' } } }, styleClass: 'max-h-9/10', width: '600px' }); if (dialog) { return !!(yield (0,rxjs__WEBPACK_IMPORTED_MODULE_3__.firstValueFrom)(dialog.onClose)); } return false; })(); } handleProtocolFormInFlow() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const saved = yield _this2.openProtocolForm(); if (saved) { const form = _this2.activeProtocolForm(); const { instance } = _this2.protocolFacade.activeProtocol(); if (instance && form && (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canProceedFromProtocolForm)(form, instance?.formValues)) { _this2.goToNextPlaceholder(); } } })(); } handleRelativePlaceholders() { const placeholder = this._activePlaceholder(); const { instance } = this.protocolFacade.activeProtocol(); if (instance === undefined || placeholder === undefined) { return; } if ((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canPlaceholderBeAutocreated)(placeholder) && (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.canPlaceholderBeCompleted)(placeholder, instance)) { const annotation = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.createAnnotationFromPlaceholder)(placeholder, instance); if (annotation === undefined) { return; } const annotationMap = this.annotationFacade.annotationMap(); const sources = placeholder.relationship?.sourceIds.map(placeholderId => { const annotationId = instance.placeholderMappings[placeholderId]; if (!annotationId) { return; } return annotationMap[annotationId]; }).filter(annotation => annotation !== undefined) ?? []; this.annotationFacade.addAnnotations((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_7__.updateRelativeMeasurement)(annotation, sources)); this.goToNextPlaceholder(); } } static ɵfac = function ProtocolCreationService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProtocolCreationService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: ProtocolCreationService, factory: ProtocolCreationService.ɵfac }); } /***/ }, /***/ 47716 /*!*******************************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/protocol-form-card/protocol-form-card.component.ts ***! \*******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ProtocolFormCardComponent: () => (/* binding */ ProtocolFormCardComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../card-theme/card-theme */ 92147); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @angular/core */ 14975); function ProtocolFormCardComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](0, "span", 10); } } function ProtocolFormCardComponent_ng_container_8_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementContainer"](0); } } function ProtocolFormCardComponent_ng_container_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementContainer"](0); } } function ProtocolFormCardComponent_ng_template_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "div", 11)(1, "span", 12, 4); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtextInterpolate1"](" ", ctx_r0.formDefinition().name, " "); } } function ProtocolFormCardComponent_ng_template_12_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](1, "lib-icon", 13); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵclassMap"](ctx_r0.cn("flex size-7.5 shrink-0 items-center justify-center rounded-full", ctx_r0.complete() ? "bg-surface-900" : "bg-surface-800")); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("icon", ctx_r0.icon()); } } const DARK_CARD_THEME = { blocked: { bg: '{app.surface.card}', hover: '{surface.300}', icon: '{surface.500}', text: '{amber.500}' }, complete: { bg: '{app.surface.card}', hover: '{surface.300}', icon: '{surface.500}', text: '{surface.100}' }, default: { bg: '{app.surface.card}', hover: '{surface.300}', icon: '{surface.500}', text: '{surface.500}' }, invalid: { bg: '{app.surface.card}', hover: '{surface.300}', icon: '{surface.500}', text: '{red.500}' } }; class ProtocolFormCardComponent { formDefinition = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "formDefinition" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); blocked = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "blocked" }] : [])); complete = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "complete" }] : [])); invalid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "invalid" }] : [])); mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const pt = this.pt(); const hoverClass = ''; return { ...pt, header: { ...pt?.header, root: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.cn)('flex-row gap-3 rounded-none pr-1 justify-start', hoverClass, pt?.header?.root), toggleicon: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.cn)('toggle-icon', pt?.header?.toggleicon) }, panel: { ...pt?.panel, root: { class: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.cn)('py-0 flex w-full border-none', hoverClass, pt?.panel?.root), style: { backgroundColor: 'var(--p-accordion-header-background)' } } } }; }, ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_6__.buildCardDt)(DARK_CARD_THEME[this.cardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_6__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.cn; cardState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const blocked = this.blocked(); const complete = this.complete(); const invalid = this.invalid(); if (blocked) { return 'blocked'; } if (invalid) { return 'invalid'; } if (complete) { return 'complete'; } return 'default'; }, ...(ngDevMode ? [{ debugName: "cardState" }] : [])); icon = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const cardState = this.cardState(); return CARD_STATE_ICONS[cardState]; }, ...(ngDevMode ? [{ debugName: "icon" }] : [])); static ɵfac = function ProtocolFormCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProtocolFormCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵdefineComponent"]({ type: ProtocolFormCardComponent, selectors: [["lib-protocol-form-card"]], inputs: { formDefinition: [1, "formDefinition"], pt: [1, "pt"], blocked: [1, "blocked"], complete: [1, "complete"], invalid: [1, "invalid"] }, decls: 14, vars: 10, consts: [["panel", ""], ["toggleicon", ""], ["headerTitle", ""], ["cardIcon", ""], ["nameLabel", ""], [1, "grow", 3, "pt", "dt", "value"], [3, "pt"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-3", "py-0.5"], [4, "ngTemplateOutlet"], [1, "ml-2.5", "size-3"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], [1, "line-clamp-2", "wrap-anywhere"], [1, "size-(--p-app-icon-size-sm)", 3, "icon"]], template: function ProtocolFormCardComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "div")(1, "p-accordion-panel", 5, 0)(3, "p-accordion-header", 6); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplate"](4, ProtocolFormCardComponent_ng_template_4_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](6, "div", 7)(7, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplate"](8, ProtocolFormCardComponent_ng_container_8_Template, 1, 0, "ng-container", 9)(9, ProtocolFormCardComponent_ng_container_9_Template, 1, 0, "ng-container", 9); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"]()()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplate"](10, ProtocolFormCardComponent_ng_template_10_Template, 4, 1, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplateRefExtractor"])(12, ProtocolFormCardComponent_ng_template_12_Template, 2, 3, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { const headerTitle_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵreference"](11); const cardIcon_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵreference"](13); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵclassMap"](ctx.cn("group border-surface-800 flex w-full overflow-hidden border-b", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", "form"); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r3); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("ngTemplateOutlet", headerTitle_r2); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_3__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_3__.AccordionPanel, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_4__.IconComponent, _angular_common__WEBPACK_IMPORTED_MODULE_0__.NgTemplateOutlet], encapsulation: 2, changeDetection: 0 }); } const CARD_STATE_ICONS = { blocked: 'ban', complete: 'check', default: 'clipboard', invalid: 'times' }; /***/ }, /***/ 62472 /*!***********************************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/protocol-form-dialog/protocol-form-dialog.component.ts ***! \***********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ProtocolFormDialog: () => (/* binding */ ProtocolFormDialog) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _protocol_form_protocol_form_component__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../protocol-form/protocol-form.component */ 51430); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["form"]; function ProtocolFormDialog_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelement"](0, "lib-protocol-form", 2, 0); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementStart"](2, "div", 3)(3, "p-button", 4); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵlistener"]("click", function ProtocolFormDialog_Conditional_1_Template_p_button_click_3_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.cancel()); }); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementStart"](5, "p-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵlistener"]("click", function ProtocolFormDialog_Conditional_1_Template_p_button_click_5_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.save()); }); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵproperty"]("formDefinition", ctx)("formValues", ctx_r1.formValues()); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵpipeBind1"](4, 4, "common.cancel")); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵpipeBind1"](6, 6, "common.save")); } } class ProtocolFormDialog { dialogReference = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__.DynamicDialogRef); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.ProtocolFacade); form = _angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild.required('form'); formDefinition = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.protocolFacade.activeProtocol().definition?.form, ...(ngDevMode ? [{ debugName: "formDefinition" }] : [])); formValues = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.protocolFacade.activeProtocol().instance?.formValues ?? {}, ...(ngDevMode ? [{ debugName: "formValues" }] : [])); cancel() { this.dialogReference.close(false); } save() { this.form().save(); this.dialogReference.close(true); } static ɵfac = function ProtocolFormDialog_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProtocolFormDialog)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵdefineComponent"]({ type: ProtocolFormDialog, selectors: [["lib-protocol-form-dialog"]], viewQuery: function ProtocolFormDialog_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵviewQuerySignal"](ctx.form, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵqueryAdvance"](); } }, hostAttrs: [1, "flex", "flex-col", "min-h-0", "overflow-y-auto"], decls: 2, vars: 1, consts: [["form", ""], [1, "flex", "min-h-0", "flex-1", "flex-col", "gap-4"], [1, "flex", "min-h-0", "flex-col", "overflow-y-auto", 3, "formDefinition", "formValues"], [1, "flex", "justify-end", "gap-2"], ["severity", "secondary", "variant", "text", "data-test-id", "protocol-form-dialog-p-button-cancel", 3, "click", "label"], ["data-test-id", "protocol-form-dialog-p-button-save", 3, "click", "label"]], template: function ProtocolFormDialog_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementStart"](0, "div", 1); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵconditionalCreate"](1, ProtocolFormDialog_Conditional_1_Template, 7, 8); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_8__["ɵɵconditional"]((tmp_0_0 = ctx.formDefinition()) ? 1 : -1, tmp_0_0); } }, dependencies: [primeng_button__WEBPACK_IMPORTED_MODULE_4__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_4__.Button, _protocol_form_protocol_form_component__WEBPACK_IMPORTED_MODULE_7__.ProtocolFormComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 51430 /*!*********************************************************************************!*\ !*** ./libs/feature/src/lib/protocols/protocol-form/protocol-form.component.ts ***! \*********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ProtocolFormComponent: () => (/* binding */ ProtocolFormComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_checkbox__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/checkbox */ 10026); /* harmony import */ var primeng_fieldset__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/fieldset */ 48749); /* harmony import */ var primeng_radiobutton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/radiobutton */ 93522); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_textarea__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/textarea */ 25683); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_validators__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/validators */ 74208); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ standalone: true }); const _forTrack0 = ($index, $item) => $item.key; const _forTrack1 = ($index, $item) => $item.value; function ProtocolFormComponent_For_2_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](2, 1, ctx)); } } function ProtocolFormComponent_For_2_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p", 3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](2, 1, ctx)); } } function ProtocolFormComponent_For_2_Conditional_0_Case_3_Case_0_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 4)(1, "div", 5)(2, "p-radiobutton", 6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function ProtocolFormComponent_For_2_Conditional_0_Case_3_Case_0_Template_p_radiobutton_ngModelChange_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setFieldValue(fieldDef_r2, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "label", 7); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](4, "Yes"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](5, "div", 5)(6, "p-radiobutton", 8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function ProtocolFormComponent_For_2_Conditional_0_Case_3_Case_0_Template_p_radiobutton_ngModelChange_6_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setFieldValue(fieldDef_r2, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](7, "label", 9); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](8, "No"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()()(); } if (rf & 2) { const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("ngModel", ctx_r2.values()[fieldDef_r2.key])("name", fieldDef_r2.key)("value", true); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("ngModel", ctx_r2.values()[fieldDef_r2.key])("name", fieldDef_r2.key)("value", false); } } function ProtocolFormComponent_For_2_Conditional_0_Case_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](0, ProtocolFormComponent_For_2_Conditional_0_Case_3_Case_0_Template, 9, 6, "div", 4); } if (rf & 2) { let tmp_12_0; const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_12_0 = fieldDef_r2.representation) === "radio" ? 0 : -1); } } function ProtocolFormComponent_For_2_Conditional_0_Case_4_Case_0_For_2_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 5)(1, "p-checkbox", 10); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function ProtocolFormComponent_For_2_Conditional_0_Case_4_Case_0_For_2_Template_p_checkbox_ngModelChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](4).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setFieldValue(fieldDef_r2, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](2, "label", 11); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { const option_r5 = ctx.$implicit; const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](4).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("ngModel", ctx_r2.values()[fieldDef_r2.key])("name", fieldDef_r2.key)("inputId", option_r5.value)("value", option_r5.value)("disabled", ctx_r2.isOptionDisabled(fieldDef_r2, option_r5.value))("ngModelOptions", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction0"](10, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵattribute"]("data-test-id", `protocol-form-p-checkbox-${fieldDef_r2.key}-${option_r5.value}`); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("pTooltip", option_r5.description)("for", option_r5.value); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", option_r5.label, " "); } } function ProtocolFormComponent_For_2_Conditional_0_Case_4_Case_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeaterCreate"](1, ProtocolFormComponent_For_2_Conditional_0_Case_4_Case_0_For_2_Template, 4, 11, "div", 5, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeater"](ctx_r2.fieldOptions(fieldDef_r2)); } } function ProtocolFormComponent_For_2_Conditional_0_Case_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](0, ProtocolFormComponent_For_2_Conditional_0_Case_4_Case_0_Template, 3, 0, "div", 4); } if (rf & 2) { let tmp_12_0; const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_12_0 = fieldDef_r2.representation) === "checkboxes" ? 0 : -1); } } function ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_0_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-select", 14); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_0_Template_p_select_ngModelChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setFieldValue(fieldDef_r2, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("name", fieldDef_r2.key)("ngModel", ctx_r2.values()[fieldDef_r2.key])("options", ctx_r2.fieldOptions(fieldDef_r2)); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵattribute"]("data-test-id", `protocol-form-p-select-${fieldDef_r2.key}`); } } function ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_1_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "textarea", 15); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_1_Template_textarea_ngModelChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r7); const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.setFieldValue(fieldDef_r2, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](3).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("name", fieldDef_r2.key)("ngModel", ctx_r2.values()[fieldDef_r2.key]); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵattribute"]("data-test-id", `protocol-form-textarea-${fieldDef_r2.key}`); } } function ProtocolFormComponent_For_2_Conditional_0_Case_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](0, ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_0_Template, 1, 4, "p-select", 12)(1, ProtocolFormComponent_For_2_Conditional_0_Case_5_Case_1_Template, 1, 3, "textarea", 13); } if (rf & 2) { let tmp_12_0; const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_12_0 = fieldDef_r2.representation) === "select" ? 0 : tmp_12_0 === "textarea" ? 1 : -1); } } function ProtocolFormComponent_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-fieldset", 1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](1, ProtocolFormComponent_For_2_Conditional_0_Conditional_1_Template, 3, 3, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](2, ProtocolFormComponent_For_2_Conditional_0_Conditional_2_Template, 3, 3, "p", 3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](3, ProtocolFormComponent_For_2_Conditional_0_Case_3_Template, 1, 1)(4, ProtocolFormComponent_For_2_Conditional_0_Case_4_Template, 1, 1)(5, ProtocolFormComponent_For_2_Conditional_0_Case_5_Template, 2, 1); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_12_0; let tmp_13_0; let tmp_14_0; const fieldDef_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"]().$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("legend", ctx_r2.fieldLabel(fieldDef_r2)); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_12_0 = ctx_r2.fieldDescription(fieldDef_r2)) ? 1 : -1, tmp_12_0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_13_0 = ctx_r2.fieldError(fieldDef_r2)) ? 2 : -1, tmp_13_0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"]((tmp_14_0 = fieldDef_r2.valueType) === "boolean" ? 3 : tmp_14_0 === "multi-text" ? 4 : tmp_14_0 === "text" ? 5 : -1); } } function ProtocolFormComponent_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](0, ProtocolFormComponent_For_2_Conditional_0_Template, 6, 4, "p-fieldset", 1); } if (rf & 2) { const fieldDef_r2 = ctx.$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx_r2.isFieldVisible(fieldDef_r2) ? 0 : -1); } } class ProtocolFormComponent { translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslateService); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_12__.ProtocolFacade); formDefinition = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "formDefinition" }] : [])); formValues = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(...(ngDevMode ? [undefined, { debugName: "formValues" }] : [])); values = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.linkedSignal)(() => this.enforceExclusiveOptions(this.clearHiddenFields({ ...this.formValues() })), ...(ngDevMode ? [{ debugName: "values" }] : [])); validation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const definition = this.formDefinition(); const values = this.values(); return (0,_tomoverse_validators__WEBPACK_IMPORTED_MODULE_13__.validateProtocolForm)(definition.validation, values); }, ...(ngDevMode ? [{ debugName: "validation" }] : [])); isValid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.validation().valid, ...(ngDevMode ? [{ debugName: "isValid" }] : [])); save() { const { definition } = this.protocolFacade.activeProtocol(); if (definition) { this.protocolFacade.setFormValues(definition.id, this.values()); } } fieldLabel(field) { return (field.label ?? this.translate.instant(`protocolDef.tavi.form.${field.key}.label`)) || field.key; } fieldDescription(field) { return (field.description ?? this.translate.instant(`protocolDef.tavi.form.${field.key}.description`)) || undefined; } fieldOptions(field) { if (field.valueType === 'text' && field.representation === 'select' || field.valueType === 'multi-text') { return field.options.map(option => ({ description: option.description ?? this.translate.instant(`protocolDef.tavi.form.${field.key}.options.${option.value}.description`), label: option.label ?? this.translate.instant(`protocolDef.tavi.form.${field.key}.options.${option.value}.label`), value: option.value })); } return []; } isFieldVisible(field, values = this.values()) { return field.visibleWhen === undefined || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_11__.isPass)((0,_tomoverse_validators__WEBPACK_IMPORTED_MODULE_13__.validateProtocolFormField)(field.visibleWhen, field.key, values)); } setFieldValue(field, value) { this.values.update(previous => this.enforceExclusiveOptions(this.clearHiddenFields({ ...previous, [field.key]: value }))); } /** True while a different, exclusive option is selected on this field. */ isOptionDisabled(field, optionValue) { const exclusive = this.exclusiveValues(field); if (exclusive.length === 0) return false; const selected = this.values()[field.key]; if (!Array.isArray(selected)) return false; return selected.some(value => value !== optionValue && exclusive.includes(value)); } exclusiveValues(field) { if (!('options' in field)) return []; return field.options.filter(option => option.exclusive === true).map(o => o.value); } /** Collapses a multi-select field to a selected exclusive option, dropping anything it was * combined with - covers checking it last, and values persisted before the rule existed. */ enforceExclusiveOptions(values) { const nextValues = { ...values }; for (const field of this.formDefinition().fields) { const exclusive = this.exclusiveValues(field); if (exclusive.length === 0) continue; const selected = nextValues[field.key]; if (!Array.isArray(selected) || selected.length <= 1) continue; const chosen = selected.find(value => exclusive.includes(value)); if (chosen !== undefined) nextValues[field.key] = [chosen]; } return nextValues; } fieldError(field) { return this.validation().errors[field.key]; } clearHiddenFields(values) { const nextValues = { ...values }; for (const field of this.formDefinition().fields) { if (field.visibleWhen !== undefined && !this.isFieldVisible(field, nextValues)) { delete nextValues[field.key]; } } return nextValues; } static ɵfac = function ProtocolFormComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProtocolFormComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵdefineComponent"]({ type: ProtocolFormComponent, selectors: [["lib-protocol-form"]], inputs: { formDefinition: [1, "formDefinition"], formValues: [1, "formValues"] }, decls: 3, vars: 0, consts: [[1, "flex", "flex-col", "gap-4"], [3, "legend"], [1, "mb-2", "text-xs"], [1, "mb-2", "text-xs", "text-(--p-app-status-danger)"], [1, "flex", "flex-wrap", "gap-4"], [1, "flex", "items-center", "gap-1"], ["inputId", "yes", 3, "ngModelChange", "ngModel", "name", "value"], ["for", "yes"], ["inputId", "no", 3, "ngModelChange", "ngModel", "name", "value"], ["for", "no"], [3, "ngModelChange", "ngModel", "name", "inputId", "value", "disabled", "ngModelOptions"], [3, "pTooltip", "for"], ["optionLabel", "label", "optionValue", "value", 1, "min-w-48", 3, "name", "ngModel", "options"], ["pTextarea", "", "fluid", "", 3, "name", "ngModel"], ["optionLabel", "label", "optionValue", "value", 1, "min-w-48", 3, "ngModelChange", "name", "ngModel", "options"], ["pTextarea", "", "fluid", "", 3, "ngModelChange", "name", "ngModel"]], template: function ProtocolFormComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "form", 0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeaterCreate"](1, ProtocolFormComponent_For_2_Template, 1, 1, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeater"](ctx.formDefinition().fields); } }, dependencies: [primeng_checkbox__WEBPACK_IMPORTED_MODULE_5__.CheckboxModule, primeng_checkbox__WEBPACK_IMPORTED_MODULE_5__.Checkbox, primeng_fieldset__WEBPACK_IMPORTED_MODULE_6__.FieldsetModule, primeng_fieldset__WEBPACK_IMPORTED_MODULE_6__.Fieldset, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_3__["ɵNgNoValidate"], _angular_forms__WEBPACK_IMPORTED_MODULE_3__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgControlStatusGroup, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgModel, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgForm, primeng_radiobutton__WEBPACK_IMPORTED_MODULE_7__.RadioButtonModule, primeng_radiobutton__WEBPACK_IMPORTED_MODULE_7__.RadioButton, primeng_select__WEBPACK_IMPORTED_MODULE_8__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_8__.Select, primeng_textarea__WEBPACK_IMPORTED_MODULE_9__.TextareaModule, primeng_textarea__WEBPACK_IMPORTED_MODULE_9__.Textarea, primeng_tooltip__WEBPACK_IMPORTED_MODULE_10__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_10__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 52569 /*!*************************************************************************************************************************!*\ !*** ./libs/feature/src/lib/relative-measurements/relative-measurement-dialog/relative-measurement-dialog.component.ts ***! \*************************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RelativeMeasurementDialogComponent: () => (/* binding */ RelativeMeasurementDialogComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _relative_measurements_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../relative-measurements.service */ 79408); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = a0 => ({ color: a0 }); const _c1 = a0 => ({ $implicit: a0 }); function RelativeMeasurementDialogComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelement"](1, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](2, "span", 11); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()(); } if (rf & 2) { const annotation_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("icon", annotation_r2.type)("iconStyle", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpureFunction1"](3, _c0, annotation_r2.color)); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtextInterpolate1"](" ", annotation_r2.name, " "); } } function RelativeMeasurementDialogComponent_Conditional_3_ng_template_1_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementContainer"](0); } } function RelativeMeasurementDialogComponent_Conditional_3_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](0, RelativeMeasurementDialogComponent_Conditional_3_ng_template_1_ng_container_0_Template, 1, 0, "ng-container", 13); } if (rf & 2) { const item_r5 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const itemTemplate_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("ngTemplateOutlet", itemTemplate_r6)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpureFunction1"](2, _c1, item_r5)); } } function RelativeMeasurementDialogComponent_Conditional_3_ng_template_3_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementContainer"](0); } } function RelativeMeasurementDialogComponent_Conditional_3_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](0, RelativeMeasurementDialogComponent_Conditional_3_ng_template_3_ng_container_0_Template, 1, 0, "ng-container", 13); } if (rf & 2) { const item_r7 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const itemTemplate_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("ngTemplateOutlet", itemTemplate_r6)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpureFunction1"](2, _c1, item_r7)); } } function RelativeMeasurementDialogComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p-select", 12); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function RelativeMeasurementDialogComponent_Conditional_3_Template_p_select_ngModelChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r3.target1, $event) || (ctx_r3.target1 = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](1, RelativeMeasurementDialogComponent_Conditional_3_ng_template_1_Template, 1, 4, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"])(3, RelativeMeasurementDialogComponent_Conditional_3_ng_template_3_Template, 1, 4, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r3.target1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("options", ctx_r3.target1Items()); } } function RelativeMeasurementDialogComponent_Conditional_4_ng_template_1_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementContainer"](0); } } function RelativeMeasurementDialogComponent_Conditional_4_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](0, RelativeMeasurementDialogComponent_Conditional_4_ng_template_1_ng_container_0_Template, 1, 0, "ng-container", 13); } if (rf & 2) { const item_r9 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const itemTemplate_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("ngTemplateOutlet", itemTemplate_r6)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpureFunction1"](2, _c1, item_r9)); } } function RelativeMeasurementDialogComponent_Conditional_4_ng_template_3_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementContainer"](0); } } function RelativeMeasurementDialogComponent_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](0, RelativeMeasurementDialogComponent_Conditional_4_ng_template_3_ng_container_0_Template, 1, 0, "ng-container", 13); } if (rf & 2) { const item_r10 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](2); const itemTemplate_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("ngTemplateOutlet", itemTemplate_r6)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpureFunction1"](2, _c1, item_r10)); } } function RelativeMeasurementDialogComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](0, "p-select", 14); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayListener"]("ngModelChange", function RelativeMeasurementDialogComponent_Conditional_4_Template_p_select_ngModelChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayBindingSet"](ctx_r3.target2, $event) || (ctx_r3.target2 = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](1, RelativeMeasurementDialogComponent_Conditional_4_ng_template_1_Template, 1, 4, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"])(3, RelativeMeasurementDialogComponent_Conditional_4_ng_template_3_Template, 1, 4, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtwoWayProperty"]("ngModel", ctx_r3.target2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("options", ctx_r3.target2Items()); } } const anyAnnotation = () => true; function not(filter) { return annotation => filter(annotation) === false; } function or(...filters) { return annotation => filters.some(filter => filter(annotation)); } const RELATIONSHIP_FILTERS = { 'angle-between-spline-axes': [_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsClosedSpline, _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsClosedSpline], 'angle-between-splines': [_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsClosedSpline, _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsClosedSpline], 'attached-distance': [not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsPoint)], 'attached-point': [not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsPoint)], 'attached-spline': [not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsPoint)], 'center-distance': [not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsPoint)], chord: [or(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsSpline, _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsAngle)], 'closest-distance-between-annotations': [not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsObject3D), not(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsObject3D)], 'closest-distance-to-one-annotation': [anyAnnotation], 'curvature-point': [_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsSpline], 'distance-between': [anyAnnotation, anyAnnotation], 'projected-distance': [_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsSpline], 'projected-distance-from-point': [_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsSpline, _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_9__.annotationIsPoint] }; class RelativeMeasurementDialogComponent { dialogReference = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_7__.DynamicDialogRef); relativeMeasurementsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_relative_measurements_service__WEBPACK_IMPORTED_MODULE_11__.RelativeMeasurementsService); annotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)([], ...(ngDevMode ? [{ debugName: "annotations" }] : [])); relationshipType = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)('angle-between-spline-axes', ...(ngDevMode ? [{ debugName: "relationshipType" }] : [])); filters = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const relationshipType = this.relationshipType(); return RELATIONSHIP_FILTERS[relationshipType] ?? []; }, ...(ngDevMode ? [{ debugName: "filters" }] : [])); target1Items = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const annotations = this.annotations(); const [filter] = this.filters(); if (!filter) return; return annotations.filter(annotation => filter(annotation)); }, ...(ngDevMode ? [{ debugName: "target1Items" }] : [])); target2Items = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const annotations = this.annotations(); const target1 = this.target1(); const [, filter] = this.filters(); if (!filter) return; return annotations.filter(annotation => filter(annotation) && annotation !== target1); }, ...(ngDevMode ? [{ debugName: "target2Items" }] : [])); target1 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.linkedSignal)(() => this.target1Items()?.[0], ...(ngDevMode ? [{ debugName: "target1" }] : [])); target2 = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.linkedSignal)(() => this.target2Items()?.[0], ...(ngDevMode ? [{ debugName: "target2" }] : [])); isValid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const [a, b] = this.filters(); const [target1, target2] = [this.target1(), this.target2()]; if (a !== undefined && target1 === undefined) return false; if (b !== undefined && target2 === undefined) return false; return true; }, ...(ngDevMode ? [{ debugName: "isValid" }] : [])); cancel() { this.dialogReference.close(); } confirm() { const sources = [this.target1(), this.target2()].filter(annotation => annotation !== undefined); this.relativeMeasurementsService.create(this.relationshipType(), sources); this.dialogReference.close(); } static ɵfac = function RelativeMeasurementDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RelativeMeasurementDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵdefineComponent"]({ type: RelativeMeasurementDialogComponent, selectors: [["lib-relative-measurement-dialog"]], inputs: { annotations: [1, "annotations"], relationshipType: [1, "relationshipType"] }, decls: 10, vars: 9, consts: [["itemTemplate", ""], ["item", ""], ["selectedItem", ""], [1, "flex", "flex-col", "gap-4", "p-4"], ["appendTo", "body", "optionLabel", "name", "data-test-id", "relative-measurement-dialog-p-select-target1", 3, "ngModel", "options"], ["appendTo", "body", "optionLabel", "name", "data-test-id", "relative-measurement-dialog-p-select-target2", 3, "ngModel", "options"], [1, "flex", "justify-end", "gap-2"], ["severity", "secondary", "variant", "text", "data-test-id", "relative-measurement-dialog-p-button-cancel", 3, "click", "label"], ["data-test-id", "relative-measurement-dialog-p-button-confirm", 3, "click", "label", "disabled"], [1, "flex", "items-center", "gap-2"], [1, "size-(--p-app-icon-size-xs)", 3, "icon", "iconStyle"], [1, "max-w-64", "overflow-hidden", "text-ellipsis", "whitespace-nowrap"], ["appendTo", "body", "optionLabel", "name", "data-test-id", "relative-measurement-dialog-p-select-target1", 3, "ngModelChange", "ngModel", "options"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], ["appendTo", "body", "optionLabel", "name", "data-test-id", "relative-measurement-dialog-p-select-target2", 3, "ngModelChange", "ngModel", "options"]], template: function RelativeMeasurementDialogComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplate"](0, RelativeMeasurementDialogComponent_ng_template_0_Template, 4, 5, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](2, "div", 3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](3, RelativeMeasurementDialogComponent_Conditional_3_Template, 5, 2, "p-select", 4); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditionalCreate"](4, RelativeMeasurementDialogComponent_Conditional_4_Template, 5, 2, "p-select", 5); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](5, "div", 6)(6, "p-button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function RelativeMeasurementDialogComponent_Template_p_button_click_6_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.cancel()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementStart"](8, "p-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipe"](9, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵlistener"]("click", function RelativeMeasurementDialogComponent_Template_p_button_click_8_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.confirm()); }); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.target1Items() ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵconditional"](ctx.target2Items() ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](7, 5, "common.cancel")); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_12__["ɵɵpipeBind1"](9, 7, "common.create"))("disabled", !ctx.isValid()); } }, dependencies: [_angular_common__WEBPACK_IMPORTED_MODULE_0__.NgTemplateOutlet, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_10__.IconComponent, primeng_button__WEBPACK_IMPORTED_MODULE_6__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_6__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_4__.NgModel, primeng_select__WEBPACK_IMPORTED_MODULE_8__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_8__.Select, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslateModule, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 79408 /*!*************************************************************************************!*\ !*** ./libs/feature/src/lib/relative-measurements/relative-measurements.service.ts ***! \*************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RelativeMeasurementsService: () => (/* binding */ RelativeMeasurementsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../colors/colors.service */ 39298); class RelativeMeasurementsService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.AnnotationFacade); colorsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_5__.ColorsService); INVALID_SOURCES = 'Invalid sources provided'; // eslint-disable-next-line sonarjs/cognitive-complexity, sonarjs/cyclomatic-complexity create(type, sources) { switch (type) { case 'angle-between-spline-axes': { const [a, b] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(a) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(b)) { console.warn(this.INVALID_SOURCES); return; } this.angleBetweenSplineAxes(a, b); break; } case 'angle-between-splines': { const [a, b] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(a) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(b)) { console.warn(this.INVALID_SOURCES); return; } this.angleBetweenSplines(a, b); break; } case 'attached-distance': { const [source] = sources; if (source === undefined || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsPoint)(source)) { console.warn(this.INVALID_SOURCES); return; } this.attachedDistance(source); break; } case 'attached-point': { const [source] = sources; if (source === undefined || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsPoint)(source)) { console.warn(this.INVALID_SOURCES); return; } this.attachedPoint(source); break; } case 'attached-spline': { const [source] = sources; if (source === undefined || (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsPoint)(source)) { console.warn(this.INVALID_SOURCES); return; } this.attachedSpline(source); break; } case 'center-distance': { const [source] = sources; if (source === undefined) { console.warn(this.INVALID_SOURCES); return; } this.centerDistance(source); break; } case 'chord': { const [source] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsSpline)(source) && !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsAngle)(source)) { console.warn(this.INVALID_SOURCES); return; } this.chord(source); break; } case 'closest-distance-between-annotations': { const [a, b] = sources; if (a === undefined || b === undefined) { console.warn(this.INVALID_SOURCES); return; } this.closestDistanceBetween(a, b); break; } case 'closest-distance-to-one-annotation': { const [source] = sources; if (source === undefined) { console.warn(this.INVALID_SOURCES); return; } this.closestDistance(source); break; } case 'curvature-point': { const [source] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsSpline)(source)) { console.warn(this.INVALID_SOURCES); return; } this.curvaturePoint(source); break; } case 'distance-between': { // Unsupported break; } case 'projected-distance': { const [source] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsSpline)(source)) { console.warn(this.INVALID_SOURCES); return; } this.projectedDistance(source); break; } case 'projected-distance-from-point': { const [a, b] = sources; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsSpline)(a) || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsPoint)(b)) { console.warn(this.INVALID_SOURCES); return; } this.projectedDistanceFromPoint(a, b); break; } } } angleBetweenSplineAxes(target, to) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.angle)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Angle Between Spline Axes', this.annotationNames()), points: [[0, 0, 0], [0, 0, 0], [0, 0, 0]], relationship: { sourceIds: [target.id, to.id], type: 'angle-between-spline-axes' } })); this.annotationFacade.annotationCreationComplete(); } angleBetweenSplines(target, to) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.angle)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Angle Between Splines', this.annotationNames()), points: [[0, 0, 0], [0, 0, 0], [0, 0, 0]], relationship: { sourceIds: [target.id, to.id], type: 'angle-between-splines' } })); this.annotationFacade.annotationCreationComplete(); } attachedDistance(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Attached Distance', this.annotationNames()), points: [], relationship: { sourceIds: [target.id], type: 'attached-distance' } })); } attachedPoint(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.point)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Attached Point', this.annotationNames()), position: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.ORIGIN, relationship: { sourceIds: [target.id], type: 'attached-point' } })); } attachedSpline(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.openSpline)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Attached Spline', this.annotationNames()), points: [], relationship: { sourceIds: [target.id], type: 'attached-spline' } })); } centerDistance(target) { const centroid = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(target); this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Center Distance', this.annotationNames()), points: [centroid], relationship: { sourceIds: [target.id], type: 'center-distance' } })); } chord(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Chord', this.annotationNames()), points: [], relationship: { sourceIds: [target.id], type: 'chord' } })); } closestDistance(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Closest Distance', this.annotationNames()), points: [[0, 0, 0]], relationship: { sourceIds: [target.id], type: 'closest-distance-to-one-annotation' } })); } closestDistanceBetween(target, to) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Distance Between Annotations', this.annotationNames()), points: [[0, 0, 0], [0, 0, 0]], relationship: { sourceIds: [target.id, to.id], type: 'closest-distance-between-annotations' } })); this.annotationFacade.annotationCreationComplete(); } curvaturePoint(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.point)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Curvature Point', this.annotationNames()), position: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.ORIGIN, relationship: { sourceIds: [target.id], type: 'curvature-point' } })); } projectedDistance(target) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Projected Distance', this.annotationNames()), points: [(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(target)], relationship: { sourceIds: [target.id], type: 'projected-distance' } })); } projectedDistanceFromPoint(target, targetPoint) { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.distance)({ color: this.colorsService.currentColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.incrementName)('Projected Distance From Point', this.annotationNames()), points: [(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_2__.getCentroid)(target), [...targetPoint.position]], relationship: { sourceIds: [target.id, targetPoint.id], type: 'projected-distance-from-point' } })); this.annotationFacade.annotationCreationComplete(); } annotationNames() { return this.annotationFacade.annotations().map(ann => ann.name); } static ɵfac = function RelativeMeasurementsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RelativeMeasurementsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: RelativeMeasurementsService, factory: RelativeMeasurementsService.ɵfac }); } /***/ }, /***/ 31982 /*!*********************************************************************!*\ !*** ./libs/feature/src/lib/s-curve-card/s-curve-card.component.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurveCardComponent: () => (/* binding */ SCurveCardComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../annotation-menu/directives/annotation-menu-trigger.directive */ 12564); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../card-theme/card-theme */ 92147); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["nameInput"]; const _c1 = () => ({ root: "size-6" }); const _c2 = () => ({ color: "var(--p-accordion-header-toggle-icon-color)" }); const _c3 = a0 => ({ secondary: a0 }); const _c4 = a0 => ({ outlined: a0 }); const _c5 = () => ({ root: "py-1 px-0" }); const _forTrack0 = ($index, $item) => $item.name; const _forTrack1 = ($index, $item) => $item.icon; function SCurveCardComponent_ng_container_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_Conditional_5_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](0, SCurveCardComponent_Conditional_5_ng_container_0_Template, 1, 0, "ng-container", 14); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); const dragHandle_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](27); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", dragHandle_r2); } } function SCurveCardComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 22); } if (rf & 2) { const active_r3 = ctx.active; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵclassMap"](ctx_r3.cn("p-accordionheader-toggle-icon size-(--p-app-icon-size-xxs) text-(length:--p-app-icon-size-xxs)", !ctx_r3.cdkDrag() && "ml-2.5")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("icon", active_r3 ? "chevron-down" : "chevron-right"); } } function SCurveCardComponent_ng_container_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_ng_container_11_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_Conditional_12_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](0, SCurveCardComponent_Conditional_12_ng_container_0_Template, 1, 0, "ng-container", 14); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); const moreMenuBtn_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](31); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", moreMenuBtn_r5); } } function SCurveCardComponent_ng_container_14_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 20)(1, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](2, "Spline:"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](3, "span", 24); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", ctx_r3.sCurve().name, " "); } } function SCurveCardComponent_For_19_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 20)(1, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](3, "span", 24); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const view_r6 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"]("", view_r6.name, ":"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", view_r6.angulation, " "); } } function SCurveCardComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 21)(1, "lib-slider", 25); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("sliderChanged", function SCurveCardComponent_Conditional_20_Template_lib_slider_sliderChanged_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.onSliderChange($event)); })("slideEnd", function SCurveCardComponent_Conditional_20_Template_lib_slider_slideEnd_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r7); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.onSlideEnd()); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("sliderClassName", "flex w-full flex-grow pointer-events-auto")("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.001)("sliderValue", ctx_r3.curvePosition()); } } function SCurveCardComponent_ng_container_21_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 33); } } function SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r9 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "p-button", 32); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("mousedown", function SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_Template_p_button_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r9); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.preventDefault()); })("click", function SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r9); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.clearName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](3, SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_ng_template_3_Template, 1, 0, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](1, 3, "common.clearName"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](2, 5, "common.clearName"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction0"](7, _c1)); } } function SCurveCardComponent_ng_template_22_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 27)(1, "input", 30, 9); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("click", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_click_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keydown.space", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keydown_space_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keyup.space", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keyup_space_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keydown.enter", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keydown_enter_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation()($event)); })("keyup.enter", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keyup_enter_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.commitEditName)($event)); })("keydown.escape", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keydown_escape_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation()($event)); })("keyup.escape", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_keyup_escape_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.cancelEditName)($event)); })("blur", function SCurveCardComponent_ng_template_22_Conditional_1_Template_input_blur_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.commitEditName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](4, SCurveCardComponent_ng_template_22_Conditional_1_Conditional_4_Template, 5, 8, "p-button", 31); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("formControl", ctx_r3.sCurveName); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵattribute"]("data-test-id", "s-curve-card-input-" + ctx_r3.sCurve().id + "-name")("maxlength", ctx_r3.nameMaxLength)("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](3, 5, "common.name")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx_r3.sCurveName.value ? 4 : -1); } } function SCurveCardComponent_ng_template_22_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r10 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "button", 34); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("click", function SCurveCardComponent_ng_template_22_Conditional_2_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r10); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.onEditName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](1, "span", 29); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵattribute"]("data-test-id", "s-curve-card-button-" + ctx_r3.sCurve().id + "-name-trigger"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate"](ctx_r3.sCurve().name); } } function SCurveCardComponent_ng_template_22_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "span", 29); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtextInterpolate1"](" ", ctx_r3.sCurve().name, " "); } } function SCurveCardComponent_ng_template_22_Conditional_4_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementContainer"](0); } } function SCurveCardComponent_ng_template_22_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](0, SCurveCardComponent_ng_template_22_Conditional_4_ng_container_0_Template, 1, 0, "ng-container", 14); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); const visibilityBtn_r11 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](29); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", visibilityBtn_r11); } } function SCurveCardComponent_ng_template_22_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 26); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](1, SCurveCardComponent_ng_template_22_Conditional_1_Template, 5, 7, "div", 27)(2, SCurveCardComponent_ng_template_22_Conditional_2_Template, 3, 2, "button", 28)(3, SCurveCardComponent_ng_template_22_Conditional_3_Template, 2, 1, "span", 29); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](4, SCurveCardComponent_ng_template_22_Conditional_4_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx_r3.isEditingName() ? 1 : ctx_r3.canRenameInline() ? 2 : 3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](!ctx_r3.isEditingName() ? 4 : -1); } } function SCurveCardComponent_ng_template_24_Template(rf, ctx) { if (rf & 1) { const _r12 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 35); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("dblclick", function SCurveCardComponent_ng_template_24_Template_div_dblclick_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r12); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.goTo.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](1, "lib-icon", 36); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵclassMap"](ctx_r3.cn("bg-surface-900 flex size-7.5 shrink-0 items-center justify-center rounded-full", ctx_r3.sCurve().hidden && "opacity-80")); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵstyleProp"]("color", ctx_r3.accentColor()); } } function SCurveCardComponent_ng_template_26_div_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "div", 39); } } function SCurveCardComponent_ng_template_26_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 37); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](2, SCurveCardComponent_ng_template_26_div_2_Template, 1, 0, "div", 38); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](1, 1, "annotationCard.dragToReorder")); } } function SCurveCardComponent_ng_template_28_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 41); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("icon", ctx_r3.sCurve().hidden ? "eye" : "eye-off"); } } function SCurveCardComponent_ng_template_28_Template(rf, ctx) { if (rf & 1) { const _r13 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "p-button", 40); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("click", function SCurveCardComponent_ng_template_28_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r13); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.sCurve().hidden ? ctx_r3.show.emit() : ctx_r3.hide.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](2, SCurveCardComponent_ng_template_28_ng_template_2_Template, 1, 1, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](7, _c4, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](5, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction0"](4, _c2))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](1, 2, ctx_r3.sCurve().hidden ? "common.show" : "common.hide")); } } function SCurveCardComponent_ng_template_30_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 43); } } function SCurveCardComponent_ng_template_30_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "p-button", 42); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](2, SCurveCardComponent_ng_template_30_ng_template_2_Template, 1, 0, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](9, _c4, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction1"](7, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction0"](6, _c2))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpipeBind1"](1, 4, "common.moreActions"))("libMenuTrigger", ctx_r3.menuTrigger())("libMenuActions", ctx_r3.actions()); } } function SCurveCardComponent_ng_template_32_For_2_Conditional_0_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "lib-icon", 47); } if (rf & 2) { const action_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("icon", action_r15.icon)("pTooltip", action_r15.label); } } function SCurveCardComponent_ng_template_32_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r14 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "p-button", 46); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("click", function SCurveCardComponent_ng_template_32_For_2_Conditional_0_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r14); const action_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"]().$implicit; $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](action_r15.command == null ? null : action_r15.command($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](1, SCurveCardComponent_ng_template_32_For_2_Conditional_0_ng_template_1_Template, 1, 2, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const action_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵpureFunction0"](2, _c5))("disabled", action_r15.disabled); } } function SCurveCardComponent_ng_template_32_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](0, SCurveCardComponent_ng_template_32_For_2_Conditional_0_Template, 3, 3, "p-button", 45); } if (rf & 2) { const action_r15 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](action_r15.icon ? 0 : -1); } } function SCurveCardComponent_ng_template_32_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 44); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵrepeaterCreate"](1, SCurveCardComponent_ng_template_32_For_2_Template, 1, 1, null, null, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵrepeater"](ctx_r3.cardActions()); } } function SCurveCardComponent_ng_template_34_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelement"](0, "div", 48); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵstyleProp"]("background-color", ctx_r3.selected() ? ctx_r3.accentColor() : ""); } } class SCurveCardComponent { actions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)([], ...(ngDevMode ? [{ debugName: "actions" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); sCurve = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "sCurve" }] : [])); selected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "selected" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); menuTrigger = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(...(ngDevMode ? [undefined, { debugName: "menuTrigger" }] : [])); cdkDrag = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "cdkDrag" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_15__.AnnotationFacade); renderSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_15__.renderSettingsStore); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_15__.viewportStore); sliding = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "sliding" }] : [])); show = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); hide = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); goTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); clicked = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); updateName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); cancelClick = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__.CancelClickDirective, ...(ngDevMode ? [{ debugName: "cancelClick" }] : [])); nameInput = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameInput', ...(ngDevMode ? [{ debugName: "nameInput" }] : [])); isEditingName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isEditingName" }] : [])); sCurveName = new _angular_forms__WEBPACK_IMPORTED_MODULE_5__.FormControl(''); nameMaxLength = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.ANNOTATION_NAME_MAX_LENGTH; // Spline-derived s-curves inherit their name from the spline annotation — // only control-point (manually-authored) curves can be renamed here. canRenameInline = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_12__.sCurveIsControlPoint)(this.sCurve()), ...(ngDevMode ? [{ debugName: "canRenameInline" }] : [])); // protected readonly curvePosition = model(0.5); curvePosition = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.linkedSignal)(() => { const { cc, rl } = this.viewportStore.angulations.coronal(); const path = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_14__.getSCurvePath)(this.sCurve()); const path3D = path.map(([x, y]) => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.position)(x, y, 0)); const distance = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.calculateDistanceOnPath)(path3D, [rl, cc, 0]); const length = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.calculatePathDistance)(path3D, false); return distance / length; }, ...(ngDevMode ? [{ debugName: "curvePosition" }] : [])); ngAfterViewInit() { this.cancelClick()?.filteredClick.subscribe(event => this.clicked.emit(event)); } mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_19__.buildCardPt)(this.pt(), this.cardState()), ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_19__.buildCardDt)(_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_19__.DARK_CARD_THEME[this.cardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); accentColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.sCurve().hidden ? 'var(--p-text-muted-color)' : this.sCurve().color, ...(ngDevMode ? [{ debugName: "accentColor" }] : [])); cardActions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.actions().filter(action => action.includeInCard), ...(ngDevMode ? [{ debugName: "cardActions" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_19__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.cn; contextMenu(event) { // NOTE: On Mac, ctrl+click triggers the contextmenu event, // but that conflicts with our multiselect functionality. // We must re-emit this as a click now if (event.ctrlKey) { event.preventDefault(); this.clicked.emit(event); return; } const trigger = this.menuTrigger(); if (!trigger) return; trigger.model.set(this.actions()); trigger.toggle(event); } views = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const sCurve = this.sCurve(); switch (sCurve.type) { case 'control-point': { const single = sCurve.controlPoints.length === 1; return sCurve.controlPoints.map(([rl, cc], index) => ({ angulation: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.formatAngulationtxt)({ ax: 0, cc, rl }, false), name: single ? 'On-curve view' : `On-curve view ${index + 1}` })); } case 'spline': { return [{ angulation: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.formatAngulationtxt)((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_14__.getSCurveEnFaceAngle)(sCurve), false), name: 'En-face view' }]; } } }, ...(ngDevMode ? [{ debugName: "views" }] : [])); cardState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const isHidden = this.sCurve().hidden; const isSelected = this.selected(); if (isHidden) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DISABLED; if (isSelected) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.SELECTED; return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_13__.CardState.DEFAULT; }, ...(ngDevMode ? [{ debugName: "cardState" }] : [])); onSliderChange(value) { this.renderSettings.lowQualityWithTimeout(); const curve = this.sCurve(); if (!this.sliding()) { // Control-point curves have no backing annotation to center the camera // on — only spline-derived curves do. if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_12__.sCurveIsSpline)(curve)) { this.annotationFacade.goToAnnotation(curve.id, true); } this.sliding.set(true); } const path = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_14__.getSCurvePath)(curve); const point = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.getPointAtDistance)(path, value); if (point) { const [rl, cc] = point; const newPosVec = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.angulationToVector)({ ax: 0, cc, rl }); const enFace = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_14__.getSCurveEnFaceAngle)(curve); const enFaceVec = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.angulationToVector)(enFace); const cross = gl_matrix__WEBPACK_IMPORTED_MODULE_7__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_7__.create(), newPosVec, enFaceVec); this.viewportStore.updateAngulationsForAllAxes({ ax: 0, cc, rl }, enFace, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.vectorToAngulation)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_17__.vec3ToPosition)(cross))); } } onSlideEnd() { this.renderSettings.setLowQuality(false); this.sliding.set(false); } onEditName = () => { if (this.isEditingName() || !this.canRenameInline()) return; this.sCurveName.setValue(this.sCurve().name); this.menuTrigger()?.hide(); this.isEditingName.set(true); setTimeout(() => this.nameInput()?.nativeElement.focus()); }; cancelEditName = () => { this.isEditingName.set(false); }; /** Clears the field's current text (without saving), letting the name be retyped or * re-entered with the mouse alone, no backspacing required. */ clearName = () => { this.sCurveName.setValue(''); this.nameInput()?.nativeElement.focus(); }; commitEditName = () => { const value = this.sCurveName.value ?? ''; if (value.trim().length === 0) { this.cancelEditName(); return; } this.isEditingName.set(false); this.updateName.emit(value.trim()); }; handleNameEventPropagation(callback) { return event => { event.stopPropagation(); event.preventDefault(); callback?.(); }; } static ɵfac = function SCurveCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurveCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵdefineComponent"]({ type: SCurveCardComponent, selectors: [["lib-s-curve-card"]], viewQuery: function SCurveCardComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵviewQuerySignal"](ctx.cancelClick, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__.CancelClickDirective, 5)(ctx.nameInput, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵqueryAdvance"](2); } }, inputs: { actions: [1, "actions"], pt: [1, "pt"], sCurve: [1, "sCurve"], selected: [1, "selected"], menuTrigger: [1, "menuTrigger"], cdkDrag: [1, "cdkDrag"] }, outputs: { show: "show", hide: "hide", goTo: "goTo", clicked: "clicked", updateName: "updateName" }, decls: 36, vars: 18, consts: [["panel", ""], ["toggleicon", ""], ["headerTitle", ""], ["cardIcon", ""], ["dragHandle", ""], ["visibilityBtn", ""], ["moreMenuBtn", ""], ["contentActions", ""], ["accentBar", ""], ["nameInput", ""], ["icon", ""], [3, "click", "contextmenu"], [1, "grow", 3, "pt", "dt", "value"], ["libCancelClick", "", 1, "relative", 3, "pt"], [4, "ngTemplateOutlet"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-3", "py-0.5"], [1, "relative", 3, "pt"], [1, "flex", "gap-3"], [1, "flex", "grow", "flex-col", "gap-1", "py-1", "text-xs"], [1, "flex", "gap-1"], [1, "flex", "gap-1", "p-2"], ["data-propagate-click", "", 3, "icon"], [1, "text-color", "font-bold"], [1, "flex", "grow", "justify-end", "text-(--p-accordion-content-muted-color)"], ["dataTestIdOverride", "s-curve-card-slider-position", "name", "s-curve-card-position", 1, "min-w-0", "flex-1", 3, "sliderChanged", "slideEnd", "sliderClassName", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], [1, "flex", "min-w-0", "flex-1", "items-center", "gap-1"], ["type", "button", "data-propagate-click", "", 1, "min-w-0", "flex-1", "cursor-pointer", "text-left"], [1, "line-clamp-2", "wrap-anywhere"], ["pInputText", "", "data-propagate-click", "", 1, "border-primary-400", "bg-transparent", "py-0.5", "text-sm", "text-inherit", 3, "click", "keydown.space", "keyup.space", "keydown.enter", "keyup.enter", "keydown.escape", "keyup.escape", "blur", "formControl"], ["type", "button", "data-propagate-click", "", "data-test-id", "s-curve-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "pTooltip", "ariaLabel", "pt"], ["type", "button", "data-propagate-click", "", "data-test-id", "s-curve-card-p-button-clear-name", "severity", "secondary", "text", "", "rounded", "", "size", "small", 3, "mousedown", "click", "pTooltip", "ariaLabel", "pt"], ["icon", "times", 1, "size-3"], ["type", "button", "data-propagate-click", "", 1, "min-w-0", "flex-1", "cursor-pointer", "text-left", 3, "click"], [3, "dblclick"], ["icon", "s-curve", 1, "size-(--p-app-icon-size-sm)"], ["cdkDragHandle", "", "icon", "drag-handle", 1, "order-first", "size-3", "cursor-grab", "px-1.5", "py-3", "text-(--p-accordion-header-toggle-icon-hover-color)", "opacity-0", "transition-opacity", "delay-100", "group-hover:opacity-100", "active:cursor-grabbing"], ["class", "h-11 rounded-sm bg-(--p-app-dark-surface-base)", 4, "cdkDragPlaceholder"], [1, "h-11", "rounded-sm", "bg-(--p-app-dark-surface-base)"], ["data-test-id", "s-curve-card-p-button-visibility", "data-propagate-click", "", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "dt", "pTooltip"], [1, "size-(--p-app-icon-size-xs)", 3, "icon"], ["data-test-id", "s-curve-card-p-button-more-actions", "data-propagate-click", "", "severity", "secondary", "outlined", "", "size", "small", 3, "dt", "pTooltip", "libMenuTrigger", "libMenuActions"], ["icon", "ellipsis-v", 1, "size-(--p-app-icon-size-xxxs)", "text-(length:--p-app-icon-size-xxxs)"], [1, "flex", "flex-col", "items-center"], ["data-test-id", "s-curve-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "pt", "disabled"], ["data-test-id", "s-curve-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "pt", "disabled"], [1, "size-(--p-app-icon-size-sm)", 3, "icon", "pTooltip"], [1, "absolute", "top-0", "left-0", "h-full", "w-1"]], template: function SCurveCardComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](0, "div", 11); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵlistener"]("click", function SCurveCardComponent_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.clicked.emit($event)); })("contextmenu", function SCurveCardComponent_Template_div_contextmenu_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.contextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](1, "p-accordion-panel", 12, 0)(3, "p-accordion-header", 13); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](4, SCurveCardComponent_ng_container_4_Template, 1, 0, "ng-container", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](5, SCurveCardComponent_Conditional_5_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](6, SCurveCardComponent_ng_template_6_Template, 1, 3, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](8, "div", 15)(9, "div", 16); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](10, SCurveCardComponent_ng_container_10_Template, 1, 0, "ng-container", 14)(11, SCurveCardComponent_ng_container_11_Template, 1, 0, "ng-container", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](12, SCurveCardComponent_Conditional_12_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](13, "p-accordion-content", 17); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](14, SCurveCardComponent_ng_container_14_Template, 1, 0, "ng-container", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementStart"](15, "div", 18)(16, "div", 19); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](17, SCurveCardComponent_Conditional_17_Template, 5, 1, "div", 20); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵrepeaterCreate"](18, SCurveCardComponent_For_19_Template, 5, 2, "div", 20, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditionalCreate"](20, SCurveCardComponent_Conditional_20_Template, 2, 5, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](21, SCurveCardComponent_ng_container_21_Template, 1, 0, "ng-container", 14); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplate"](22, SCurveCardComponent_ng_template_22_Template, 5, 2, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(24, SCurveCardComponent_ng_template_24_Template, 2, 4, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(26, SCurveCardComponent_ng_template_26_Template, 3, 3, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(28, SCurveCardComponent_ng_template_28_Template, 4, 9, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(30, SCurveCardComponent_ng_template_30_Template, 4, 11, "ng-template", null, 6, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(32, SCurveCardComponent_ng_template_32_Template, 3, 0, "ng-template", null, 7, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"])(34, SCurveCardComponent_ng_template_34_Template, 1, 2, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { const headerTitle_r16 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](23); const cardIcon_r17 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](25); const contentActions_r18 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](33); const accentBar_r19 = _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵreference"](35); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵclassMap"](ctx.cn("group flex w-full overflow-hidden border-b border-(--p-app-border-subtle)", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", ctx.sCurve().id); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r19); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx.cdkDrag() ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r17); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", headerTitle_r16); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx.menuTrigger() && ctx.actions().length && !ctx.isEditingName() ? 12 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("pt", ctx.mergedPt().content); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r19); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx.sCurve().type === "spline" ? 17 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵrepeater"](ctx.views()); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵconditional"](ctx.cardState() === "selected" ? 20 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_20__["ɵɵproperty"]("ngTemplateOutlet", contentActions_r18); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionContent, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_8__.AccordionPanel, _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_18__.AnnotationMenuTriggerDirective, primeng_button__WEBPACK_IMPORTED_MODULE_9__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__.CancelClickDirective, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragHandle, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragPlaceholder, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__.IconComponent, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_10__.InputText, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_16__.SliderComponent, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.FormControlDirective, primeng_tooltip__WEBPACK_IMPORTED_MODULE_11__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 1336 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/s-curve-graph/s-curve-graph.component.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurveGraphComponent: () => (/* binding */ SCurveGraphComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../annotation-menu/annotation-menu-item.service */ 39860); /* harmony import */ var _annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../annotation-menu/components/annotation-menu-item.component */ 45731); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["ctxMenu"]; const _c1 = () => ({ "--p-button-text-primary-color": "var(--p-app-graph-label)", "--p-button-text-primary-hover-background": "color-mix(in srgb, var(--p-app-graph-label) 10%, transparent)" }); function SCurveGraphComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "lib-viewport-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("click", function SCurveGraphComponent_Conditional_3_Template_lib_viewport_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.toggleMaximize.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipeBind1"](1, 3, ctx_r2.isMaximized() ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipeBind1"](2, 5, ctx_r2.isMaximized() ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel"))("icon", ctx_r2.isMaximized() ? "arrow-down-left-and-arrow-up-right-to-center" : "arrow-up-right-and-arrow-down-left-from-center"); } } function SCurveGraphComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "p-button", 9); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("click", function SCurveGraphComponent_Conditional_4_Template_p_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.toggleDetach()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵstyleMap"](_angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](11, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("icon", ctx_r2.isDetached() ? "pi pi-window-minimize" : "pi pi-window-maximize")("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipeBind1"](1, 7, "viewportButton.sCurveToViewport"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipeBind1"](2, 9, "viewportButton.sCurveToViewport"))("rounded", true)("text", true); } } function SCurveGraphComponent_ng_template_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelement"](0, "lib-annotation-menu-item", 10); } if (rf & 2) { const item_r5 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("item", item_r5); } } const VIEWPORT_COLORS = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.AXIAL]: 'var(--p-app-viewport-axis-axial)', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.CORONAL]: 'var(--p-app-viewport-axis-coronal)', [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.SAGITTAL]: 'var(--p-app-viewport-axis-sagittal)' }; const NUM_ROTATIONS = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.AXIAL]: 2, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.CORONAL]: 0, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportAxis.SAGITTAL]: 1 }; const CONTROL_POINT_ID_PREFIX = 'cp:'; const INTERSECTION_POINT_ID_PREFIX = 'ix:'; const CHAMBER_POINT_ID_PREFIX = 'chamber:'; function intersectionPointId(measurementId) { return `${INTERSECTION_POINT_ID_PREFIX}${measurementId}`; } function chamberPointId(chamberId) { return `${CHAMBER_POINT_ID_PREFIX}${chamberId}`; } /** A control-point curve's own points can't reuse the ViewportAxis string keys * (a curveId is a uuid, so this can never collide with them). */ function controlPointId(curveId, index) { return `${CONTROL_POINT_ID_PREFIX}${curveId}:${index}`; } /** Parses a controlPointId back into its curveId/index, or undefined if pointId * isn't one (e.g. a ViewportAxis key). */ function parseControlPointId(pointId) { if (!pointId.startsWith(CONTROL_POINT_ID_PREFIX)) return undefined; const [curveId, indexText] = pointId.slice(CONTROL_POINT_ID_PREFIX.length).split(':'); const index = Number(indexText); if (!curveId || Number.isNaN(index)) return undefined; return { curveId, index }; } class SCurveGraphComponent { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.AnnotationFacade); chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.ChamberFacade); renderSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.renderSettingsStore); sCurveFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.SCurveFacade); uiFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.UiFacade); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_11__.viewportStore); menuItemService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_14__.AnnotationMenuItemService); menuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "menuItems" }] : [])); contextMenu = _angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild.required('ctxMenu'); interacting = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "interacting" }] : [])); isDetached = this.uiFacade.sCurveGraphDetached; hoveredCurveId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "hoveredCurveId" }] : [])); hoveredPointId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "hoveredPointId" }] : [])); backgroundMenuItems = this.menuItemService.menuItemsForPanelSCurves(); toggleDetach() { if (this.isDetached()) { this.uiFacade.attachSCurveGraph(); } else { this.uiFacade.detachSCurveGraph(); } } showDetachButton = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(true, ...(ngDevMode ? [{ debugName: "showDetachButton" }] : [])); // Opt-in: the grid-tile/maximized viewport rendering already has its own dedicated // maximize/minimize control, so this only needs to be enabled where the graph is docked // in the sidebar drawer and has no other way to jump straight to fullscreen. showMaximizeButton = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(false, ...(ngDevMode ? [{ debugName: "showMaximizeButton" }] : [])); // Whether the s-curve view is *currently* the fullscreen maximized panel - flips the // button's icon/tooltip between maximize and minimize, matching the toggle already used // by the dedicated maximize button shown when the graph is a grid/fullscreen viewport. isMaximized = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(false, ...(ngDevMode ? [{ debugName: "isMaximized" }] : [])); toggleMaximize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); points = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const angulations = this.viewportStore.angulations(); const hoveredId = this.hoveredPointId(); // The MPR viewports aren't visible while the s-curve is maximized to fullscreen, so their // live angle dots would be both pointless clutter and misleadingly draggable for views the // user can't see. They come back as soon as the graph leaves fullscreen (minimized or // moved back to the sidebar). const axisPoints = this.isMaximized() ? [] : Object.entries(angulations).map(([key, angulation]) => ({ color: (0,_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.isViewportAxis)(key) ? VIEWPORT_COLORS[key] : 'var(--p-app-graph-label)', hovered: hoveredId === key, id: key, position: [angulation.rl, angulation.cc] })); const chamberPoints = this.renderSettings.sCurveShowChamberPoints() ? this.chamberFacade.chambers().filter(({ hidden }) => !hidden).map(chamber => { const id = chamberPointId(chamber.id); return { color: chamber.color, draggable: false, hovered: hoveredId === id, id, label: chamber.name, position: [chamber.cameraOrientation.rl, chamber.cameraOrientation.cc], snappable: false }; }) : []; const sCurvesById = new Map(this.sCurveFacade.sCurves().map(sCurve => [sCurve.id, sCurve])); const intersectionPoints = this.sCurveFacade.relativeMeasurements().filter(measurement => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.sCurveMeasurementIsIntersection)(measurement)).filter(({ hidden }) => !hidden).map(measurement => { const [a, b] = measurement.sourceIds.map(id => sCurvesById.get(id)); if (!a || !b) return undefined; if (a.hidden || b.hidden) return undefined; const position = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__.getSCurveIntersectionPosition)(a, b); if (!position) return undefined; const id = intersectionPointId(measurement.id); return { color: measurement.color, draggable: false, hovered: hoveredId === id, id, position, snappable: false }; }).filter(point => point !== undefined); // Only the single selected control-point curve's own points render as // draggable, so the graph doesn't show every curve's points at once. const selectedIds = this.sCurveFacade.selectedIds(); if (selectedIds.length !== 1) { return [...axisPoints, ...intersectionPoints, ...chamberPoints]; } const selectedCurve = this.sCurveFacade.sCurves().find(sCurve => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.sCurveIsControlPoint)(sCurve) && sCurve.id === selectedIds[0]); if (!selectedCurve) { return [...axisPoints, ...intersectionPoints, ...chamberPoints]; } const controlPointDots = selectedCurve.controlPoints.map((position, index) => { const id = controlPointId(selectedCurve.id, index); return { color: selectedCurve.color, hovered: hoveredId === id, id, position, snappable: false }; }); return [...axisPoints, ...intersectionPoints, ...chamberPoints, ...controlPointDots]; }, ...(ngDevMode ? [{ debugName: "points" }] : [])); curves = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const sCurves = this.sCurveFacade.sCurves(); const selectedIds = this.sCurveFacade.selectedIds(); const hoveredId = this.hoveredCurveId(); return sCurves.filter(({ hidden }) => !hidden).map(sCurve => ({ color: sCurve.color, curve: sCurve, hovered: sCurve.id === hoveredId, id: sCurve.id, path: (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__.getSCurvePath)(sCurve), selected: selectedIds.includes(sCurve.id) })); }, ...(ngDevMode ? [{ debugName: "curves" }] : [])); handleGraphPointMove(event) { this.renderSettings.lowQualityWithTimeout(); const controlPoint = parseControlPointId(event.pointId); if (controlPoint) { const curve = this.sCurveFacade.sCurves().find(sCurve => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.sCurveIsControlPoint)(sCurve) && sCurve.id === controlPoint.curveId); if (curve) { const controlPoints = curve.controlPoints.map((point, index) => index === controlPoint.index ? event.newPosition : point); this.sCurveFacade.updateSCurve({ controlPoints, id: curve.id }); } return; } if ((0,_tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.isViewportAxis)(event.pointId)) { const [rl, cc] = event.newPosition; if (event.curveId !== undefined) { const curve = this.curves().find(({ id }) => id === event.curveId); if (curve) { const newPosVec = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.angulationToVector)({ ax: 0, cc, rl }); const enFace = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__.getSCurveEnFaceAngle)(curve.curve); const enFaceVec = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.angulationToVector)(enFace); const cross = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(), newPosVec, enFaceVec); // Depending on which point is dragged, we will rotate the angulations // so the proper points are updated in the viewportStore. const rotations = NUM_ROTATIONS[event.pointId]; const angulations = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.rotateArray)([{ ax: 0, cc, rl }, enFace, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.vectorToAngulation)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_13__.vec3ToPosition)(cross))], rotations); this.viewportStore.updateAngulationsForAllAxes(...angulations); return; } } this.viewportStore.updateAngulationsForAxis({ ax: 0, cc, rl }, event.pointId); } } handlePointSnappedToCurve(event) { // NOTE: When we handle non-spline s-curves, we will need to alter this logic this.annotationFacade.goToAnnotation(event.curveId, true); } handleCurveSelected(event) { if (event.additive) { this.sCurveFacade.toggleSelectSCurve(event.curveId); } else { this.sCurveFacade.selectSCurves([event.curveId]); } } handleMouseDown() { if (!this.interacting()) { const mouseUpHandler = () => { this.interacting.set(false); document.removeEventListener('mouseup', mouseUpHandler); }; document.addEventListener('mouseup', mouseUpHandler); this.interacting.set(true); } } handleCurveContextMenu(event) { const sCurves = this.sCurveFacade.sCurves(); const curve = sCurves.find(({ id }) => id === event.curveId); if (curve) { this.menuItems.set(this.menuItemService.menuItemsForSCurve(curve)); this.contextMenu().show(event.event); } } handleCurveHover(event) { this.hoveredCurveId.set(event.curveId); } handlePointHover(event) { this.hoveredPointId.set(event.pointId); } handleBackgroundClick() { this.sCurveFacade.selectSCurves([]); } handleBackgroundContextMenu({ event }) { this.menuItems.set(this.backgroundMenuItems()); this.contextMenu().show(event); } static ɵfac = function SCurveGraphComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurveGraphComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵdefineComponent"]({ type: SCurveGraphComponent, selectors: [["lib-s-curve-graph"]], viewQuery: function SCurveGraphComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵviewQuerySignal"](ctx.contextMenu, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵqueryAdvance"](); } }, inputs: { showDetachButton: [1, "showDetachButton"], showMaximizeButton: [1, "showMaximizeButton"], isMaximized: [1, "isMaximized"] }, outputs: { toggleMaximize: "toggleMaximize" }, decls: 9, vars: 8, consts: [["ctxMenu", ""], ["item", ""], [1, "aspect-square", "overflow-hidden"], [3, "backgroundClicked", "backgroundContextMenu", "pointMoved", "pointSnappedToCurve", "curveContextMenu", "curveHovered", "curveSelected", "pointHovered", "mousedown", "curves", "points", "fontSize", "lineWidth"], [1, "relative", "bottom-[44px]", "flex", "items-center", "justify-end", "gap-1"], ["data-test-id", "s-curve-graph-lib-viewport-button-maximize", "tooltipPosition", "top", "iconType", "prime", 3, "tooltip", "ariaLabel", "icon"], ["tooltipPosition", "top", "data-test-id", "s-curve-graph-p-button-toggle-detach", "size", "small", 3, "icon", "style", "pTooltip", "ariaLabel", "rounded", "text"], [3, "appendTo", "model"], ["data-test-id", "s-curve-graph-lib-viewport-button-maximize", "tooltipPosition", "top", "iconType", "prime", 3, "click", "tooltip", "ariaLabel", "icon"], ["tooltipPosition", "top", "data-test-id", "s-curve-graph-p-button-toggle-detach", "size", "small", 3, "click", "icon", "pTooltip", "ariaLabel", "rounded", "text"], [3, "item"]], template: function SCurveGraphComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "div", 2)(1, "lib-s-curve-graph-base", 3); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("backgroundClicked", function SCurveGraphComponent_Template_lib_s_curve_graph_base_backgroundClicked_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleBackgroundClick()); })("backgroundContextMenu", function SCurveGraphComponent_Template_lib_s_curve_graph_base_backgroundContextMenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleBackgroundContextMenu($event)); })("pointMoved", function SCurveGraphComponent_Template_lib_s_curve_graph_base_pointMoved_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleGraphPointMove($event)); })("pointSnappedToCurve", function SCurveGraphComponent_Template_lib_s_curve_graph_base_pointSnappedToCurve_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handlePointSnappedToCurve($event)); })("curveContextMenu", function SCurveGraphComponent_Template_lib_s_curve_graph_base_curveContextMenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleCurveContextMenu($event)); })("curveHovered", function SCurveGraphComponent_Template_lib_s_curve_graph_base_curveHovered_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleCurveHover($event)); })("curveSelected", function SCurveGraphComponent_Template_lib_s_curve_graph_base_curveSelected_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleCurveSelected($event)); })("pointHovered", function SCurveGraphComponent_Template_lib_s_curve_graph_base_pointHovered_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handlePointHover($event)); })("mousedown", function SCurveGraphComponent_Template_lib_s_curve_graph_base_mousedown_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.handleMouseDown()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](2, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditionalCreate"](3, SCurveGraphComponent_Conditional_3_Template, 3, 7, "lib-viewport-button", 5); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditionalCreate"](4, SCurveGraphComponent_Conditional_4_Template, 3, 12, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](5, "p-contextmenu", 7, 0); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtemplate"](7, SCurveGraphComponent_ng_template_7_Template, 1, 1, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("curves", ctx.curves())("points", ctx.points())("fontSize", ctx.renderSettings.sCurveGraphFontSize())("lineWidth", ctx.renderSettings.sCurveLineWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditional"](ctx.showMaximizeButton() && !ctx.interacting() ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditional"](ctx.showDetachButton() && !ctx.interacting() ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("appendTo", "body")("model", ctx.menuItems()); } }, dependencies: [_annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_15__.AnnotationMenuItemComponent, primeng_button__WEBPACK_IMPORTED_MODULE_5__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_5__.Button, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_6__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_6__.ContextMenu, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_12__.SCurveGraphBaseComponent, primeng_tooltip__WEBPACK_IMPORTED_MODULE_7__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_7__.Tooltip, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_12__.ViewportButtonComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 8452 /*!***************************************************************************************************************!*\ !*** ./libs/feature/src/lib/s-curve-relative-measurement-card/s-curve-relative-measurement-card.component.ts ***! \***************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurveRelativeMeasurementCardComponent: () => (/* binding */ SCurveRelativeMeasurementCardComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../annotation-menu/directives/annotation-menu-trigger.directive */ 12564); /* harmony import */ var _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../card-theme/card-theme */ 92147); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["nameInput"]; const _c1 = () => ({ color: "var(--p-accordion-header-toggle-icon-color)" }); const _c2 = a0 => ({ secondary: a0 }); const _c3 = a0 => ({ outlined: a0 }); const _c4 = () => ({ root: "py-1 px-0" }); const _forTrack0 = ($index, $item) => $item.icon; function SCurveRelativeMeasurementCardComponent_ng_container_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_4_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](0, SCurveRelativeMeasurementCardComponent_Conditional_4_ng_container_0_Template, 1, 0, "ng-container", 12); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); const dragHandle_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](41); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", dragHandle_r2); } } function SCurveRelativeMeasurementCardComponent_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "lib-icon", 24); } if (rf & 2) { const active_r3 = ctx.active; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵclassMap"](ctx_r3.cn("p-accordionheader-toggle-icon size-(--p-app-icon-size-xxs) text-(length:--p-app-icon-size-xxs)", !ctx_r3.cdkDrag() && "ml-2.5")); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("icon", active_r3 ? "chevron-down" : "chevron-right"); } } function SCurveRelativeMeasurementCardComponent_ng_container_9_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "input", 25, 7); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("click", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keydown.space", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keydown_space_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keyup.space", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keyup_space_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("keydown.enter", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keydown_enter_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation()($event)); })("keyup.enter", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keyup_enter_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.commitEditName)($event)); })("keydown.escape", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keydown_escape_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation()($event)); })("keyup.escape", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_keyup_escape_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.cancelEditName)($event)); })("blur", function SCurveRelativeMeasurementCardComponent_Conditional_11_Template_input_blur_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.commitEditName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("formControl", ctx_r3.measurementName); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵattribute"]("data-test-id", "s-curve-relative-measurement-card-input-" + ctx_r3.measurement().id + "-name")("maxlength", ctx_r3.nameMaxLength)("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](2, 4, "common.name")); } } function SCurveRelativeMeasurementCardComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "button", 26); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("click", function SCurveRelativeMeasurementCardComponent_Conditional_12_Template_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.handleNameEventPropagation(ctx_r3.onEditName)($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](1, "span", 27); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵattribute"]("data-test-id", "s-curve-relative-measurement-card-button-" + ctx_r3.measurement().id + "-name-trigger"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate"](ctx_r3.measurement().name); } } function SCurveRelativeMeasurementCardComponent_Conditional_13_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](0, SCurveRelativeMeasurementCardComponent_Conditional_13_ng_container_0_Template, 1, 0, "ng-container", 12); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); const visibilityBtn_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](45); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", visibilityBtn_r7); } } function SCurveRelativeMeasurementCardComponent_Conditional_14_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](0, SCurveRelativeMeasurementCardComponent_Conditional_14_ng_container_0_Template, 1, 0, "ng-container", 12); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); const moreMenuBtn_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](47); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", moreMenuBtn_r8); } } function SCurveRelativeMeasurementCardComponent_ng_container_16_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_Conditional_31_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "div", 21)(1, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](4, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"]("", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](3, 2, "annotationMenu.position"), ":"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", ctx_r3.positionText() ?? "\u2014", " "); } } function SCurveRelativeMeasurementCardComponent_ng_container_39_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementContainer"](0); } } function SCurveRelativeMeasurementCardComponent_ng_template_40_div_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "div", 30); } } function SCurveRelativeMeasurementCardComponent_ng_template_40_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "lib-icon", 28); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](2, SCurveRelativeMeasurementCardComponent_ng_template_40_div_2_Template, 1, 0, "div", 29); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵattribute"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](1, 1, "annotationCard.dragToReorder")); } } function SCurveRelativeMeasurementCardComponent_ng_template_42_Template(rf, ctx) { if (rf & 1) { const _r9 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "div", 31); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("dblclick", function SCurveRelativeMeasurementCardComponent_ng_template_42_Template_div_dblclick_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r9); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.goTo.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](1, "lib-icon", 32); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵclassMap"](ctx_r3.cn("bg-surface-900 flex size-7.5 shrink-0 items-center justify-center rounded-full", ctx_r3.measurement().hidden && "opacity-80")); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵstyleProp"]("color", ctx_r3.accentColor()); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("icon", ctx_r3.isIntersection() ? "point" : "angle"); } } function SCurveRelativeMeasurementCardComponent_ng_template_44_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "lib-icon", 34); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("icon", ctx_r3.measurement().hidden ? "eye" : "eye-off"); } } function SCurveRelativeMeasurementCardComponent_ng_template_44_Template(rf, ctx) { if (rf & 1) { const _r10 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "p-button", 33); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("click", function SCurveRelativeMeasurementCardComponent_ng_template_44_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r10); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r3.measurement().hidden ? ctx_r3.show.emit() : ctx_r3.hide.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](2, SCurveRelativeMeasurementCardComponent_ng_template_44_ng_template_2_Template, 1, 1, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction1"](7, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction1"](5, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction0"](4, _c1))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](1, 2, ctx_r3.measurement().hidden ? "common.show" : "common.hide")); } } function SCurveRelativeMeasurementCardComponent_ng_template_46_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "lib-icon", 36); } } function SCurveRelativeMeasurementCardComponent_ng_template_46_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "p-button", 35); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](2, SCurveRelativeMeasurementCardComponent_ng_template_46_ng_template_2_Template, 1, 0, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction1"](9, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction1"](7, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction0"](6, _c1))))("pTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](1, 4, "common.moreActions"))("libMenuTrigger", ctx_r3.menuTrigger())("libMenuActions", ctx_r3.actions()); } } function SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Conditional_0_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "lib-icon", 40); } if (rf & 2) { const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](2).$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("icon", action_r12.icon)("pTooltip", action_r12.label); } } function SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r11 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "p-button", 39); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("click", function SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Conditional_0_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r11); const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"]().$implicit; $event.stopPropagation(); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](action_r12.command == null ? null : action_r12.command($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](1, SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Conditional_0_ng_template_1_Template, 1, 2, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const action_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpureFunction0"](2, _c4))("disabled", action_r12.disabled); } } function SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](0, SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Conditional_0_Template, 3, 3, "p-button", 38); } if (rf & 2) { const action_r12 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](action_r12.icon ? 0 : -1); } } function SCurveRelativeMeasurementCardComponent_ng_template_48_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "div", 37); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵrepeaterCreate"](1, SCurveRelativeMeasurementCardComponent_ng_template_48_For_2_Template, 1, 1, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵrepeater"](ctx_r3.cardActions()); } } function SCurveRelativeMeasurementCardComponent_ng_template_50_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](0, "div", 41); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵstyleProp"]("background-color", ctx_r3.selected() ? ctx_r3.accentColor() : ""); } } class SCurveRelativeMeasurementCardComponent { actions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)([], ...(ngDevMode ? [{ debugName: "actions" }] : [])); pt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)({}, ...(ngDevMode ? [{ debugName: "pt" }] : [])); measurement = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "measurement" }] : [])); selected = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "selected" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); menuTrigger = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(...(ngDevMode ? [undefined, { debugName: "menuTrigger" }] : [])); cdkDrag = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(false, { ...(ngDevMode ? { debugName: "cdkDrag" } : {}), transform: _angular_core__WEBPACK_IMPORTED_MODULE_2__.booleanAttribute }); sCurveFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_14__.SCurveFacade); show = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); hide = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); goTo = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); clicked = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); updateName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); cancelClick = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_15__.CancelClickDirective, ...(ngDevMode ? [{ debugName: "cancelClick" }] : [])); nameInput = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('nameInput', ...(ngDevMode ? [{ debugName: "nameInput" }] : [])); isEditingName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isEditingName" }] : [])); measurementName = new _angular_forms__WEBPACK_IMPORTED_MODULE_5__.FormControl(''); nameMaxLength = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_16__.ANNOTATION_NAME_MAX_LENGTH; ngAfterViewInit() { this.cancelClick()?.filteredClick.subscribe(event => this.clicked.emit(event)); } mergedPt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.buildCardPt)(this.pt(), this.cardState()), ...(ngDevMode ? [{ debugName: "mergedPt" }] : [])); dt = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.buildCardDt)(_card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.DARK_CARD_THEME[this.cardState()]), ...(ngDevMode ? [{ debugName: "dt" }] : [])); accentColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.measurement().hidden ? 'var(--p-text-muted-color)' : this.measurement().color, ...(ngDevMode ? [{ debugName: "accentColor" }] : [])); cardActions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.actions().filter(action => action.includeInCard), ...(ngDevMode ? [{ debugName: "cardActions" }] : [])); isIntersection = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_11__.sCurveMeasurementIsIntersection)(this.measurement()), ...(ngDevMode ? [{ debugName: "isIntersection" }] : [])); cardButtonStyle = _card_theme_card_theme__WEBPACK_IMPORTED_MODULE_18__.CARD_BUTTON_STYLE; cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_16__.cn; cardState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { if (this.measurement().hidden) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.CardState.DISABLED; if (this.selected()) return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.CardState.SELECTED; return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.CardState.DEFAULT; }, ...(ngDevMode ? [{ debugName: "cardState" }] : [])); sources = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const sourcesById = new Map(this.sCurveFacade.sCurves().map(sCurve => [sCurve.id, sCurve])); const [a, b] = this.measurement().sourceIds.map(id => sourcesById.get(id)); return a && b ? [a, b] : undefined; }, ...(ngDevMode ? [{ debugName: "sources" }] : [])); angleDegrees = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const sources = this.sources(); return sources ? (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.getSCurveAngleDegrees)(sources[0], sources[1]) : undefined; }, ...(ngDevMode ? [{ debugName: "angleDegrees" }] : [])); sourceNames = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const sources = this.sources(); return sources ? [sources[0].name, sources[1].name] : undefined; }, ...(ngDevMode ? [{ debugName: "sourceNames" }] : [])); positionText = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const sources = this.sources(); if (!sources) return; const angulation = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.getSCurveIntersectionAngulation)(sources[0], sources[1]); if (!angulation) return; return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_16__.formatAngulationtxt)(angulation, false); }, ...(ngDevMode ? [{ debugName: "positionText" }] : [])); contextMenu(event) { if (event.ctrlKey) { event.preventDefault(); this.clicked.emit(event); return; } const trigger = this.menuTrigger(); if (!trigger) return; trigger.model.set(this.actions()); trigger.toggle(event); } onEditName = () => { if (this.isEditingName()) return; this.measurementName.setValue(this.measurement().name); this.menuTrigger()?.hide(); this.isEditingName.set(true); setTimeout(() => this.nameInput()?.nativeElement.focus()); }; cancelEditName = () => { this.isEditingName.set(false); }; commitEditName = () => { const value = this.measurementName.value ?? ''; if (value.trim().length === 0) { this.cancelEditName(); return; } this.isEditingName.set(false); this.updateName.emit(value.trim()); }; handleNameEventPropagation(callback) { return event => { event.stopPropagation(); event.preventDefault(); callback?.(); }; } static ɵfac = function SCurveRelativeMeasurementCardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurveRelativeMeasurementCardComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵdefineComponent"]({ type: SCurveRelativeMeasurementCardComponent, selectors: [["lib-s-curve-relative-measurement-card"]], viewQuery: function SCurveRelativeMeasurementCardComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵviewQuerySignal"](ctx.cancelClick, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_15__.CancelClickDirective, 5)(ctx.nameInput, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵqueryAdvance"](2); } }, inputs: { actions: [1, "actions"], pt: [1, "pt"], measurement: [1, "measurement"], selected: [1, "selected"], menuTrigger: [1, "menuTrigger"], cdkDrag: [1, "cdkDrag"] }, outputs: { show: "show", hide: "hide", goTo: "goTo", clicked: "clicked", updateName: "updateName" }, decls: 52, vars: 33, consts: [["toggleicon", ""], ["dragHandle", ""], ["cardIcon", ""], ["visibilityBtn", ""], ["moreMenuBtn", ""], ["contentActions", ""], ["accentBar", ""], ["nameInput", ""], ["icon", ""], [3, "click", "contextmenu"], [1, "grow", 3, "pt", "dt", "value"], ["libCancelClick", "", 1, "relative", 3, "pt"], [4, "ngTemplateOutlet"], [1, "order-last", "flex", "w-full", "min-w-0", "items-center", "justify-between", "gap-1"], [1, "flex", "w-full", "min-w-0", "grow", "items-center", "gap-3", "py-0.5"], [1, "flex", "min-w-0", "grow", "items-center", "justify-between", "text-sm"], ["pInputText", "", "data-propagate-click", "", 1, "border-primary-400", "bg-transparent", "py-0.5", "text-sm", "text-inherit", 3, "formControl"], ["type", "button", "data-propagate-click", "", 1, "min-w-0", "flex-1", "cursor-pointer", "text-left"], [1, "relative", 3, "pt"], [1, "flex", "gap-3"], [1, "flex", "grow", "flex-col", "gap-1", "py-1", "text-xs"], [1, "flex", "gap-1"], [1, "text-color", "font-bold"], [1, "flex", "grow", "justify-end", "text-(--p-accordion-content-muted-color)"], ["data-propagate-click", "", 3, "icon"], ["pInputText", "", "data-propagate-click", "", 1, "border-primary-400", "bg-transparent", "py-0.5", "text-sm", "text-inherit", 3, "click", "keydown.space", "keyup.space", "keydown.enter", "keyup.enter", "keydown.escape", "keyup.escape", "blur", "formControl"], ["type", "button", "data-propagate-click", "", 1, "min-w-0", "flex-1", "cursor-pointer", "text-left", 3, "click"], [1, "line-clamp-2", "wrap-anywhere"], ["cdkDragHandle", "", "icon", "drag-handle", 1, "order-first", "size-3", "cursor-grab", "px-1.5", "py-3", "text-(--p-accordion-header-toggle-icon-hover-color)", "opacity-0", "transition-opacity", "delay-100", "group-hover:opacity-100", "active:cursor-grabbing"], ["class", "h-11 rounded-sm bg-(--p-app-dark-surface-base)", 4, "cdkDragPlaceholder"], [1, "h-11", "rounded-sm", "bg-(--p-app-dark-surface-base)"], [3, "dblclick"], [1, "size-(--p-app-icon-size-sm)", 3, "icon"], ["data-test-id", "s-curve-relative-measurement-card-p-button-visibility", "data-propagate-click", "", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "dt", "pTooltip"], [1, "size-(--p-app-icon-size-xs)", 3, "icon"], ["data-test-id", "s-curve-relative-measurement-card-p-button-more-actions", "data-propagate-click", "", "severity", "secondary", "outlined", "", "size", "small", 3, "dt", "pTooltip", "libMenuTrigger", "libMenuActions"], ["icon", "ellipsis-v", 1, "size-(--p-app-icon-size-xxxs)", "text-(length:--p-app-icon-size-xxxs)"], [1, "flex", "flex-col", "items-center"], ["data-test-id", "s-curve-relative-measurement-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "pt", "disabled"], ["data-test-id", "s-curve-relative-measurement-card-p-button-action", "severity", "secondary", "outlined", "", "size", "small", 3, "click", "pt", "disabled"], [1, "size-(--p-app-icon-size-sm)", 3, "icon", "pTooltip"], [1, "absolute", "top-0", "left-0", "h-full", "w-1"]], template: function SCurveRelativeMeasurementCardComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("click", function SCurveRelativeMeasurementCardComponent_Template_div_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.clicked.emit($event)); })("contextmenu", function SCurveRelativeMeasurementCardComponent_Template_div_contextmenu_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx.contextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](1, "p-accordion-panel", 10)(2, "p-accordion-header", 11); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](3, SCurveRelativeMeasurementCardComponent_ng_container_3_Template, 1, 0, "ng-container", 12); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](4, SCurveRelativeMeasurementCardComponent_Conditional_4_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](5, SCurveRelativeMeasurementCardComponent_ng_template_5_Template, 1, 3, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](7, "div", 13)(8, "div", 14); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](9, SCurveRelativeMeasurementCardComponent_ng_container_9_Template, 1, 0, "ng-container", 12); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](10, "div", 15); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](11, SCurveRelativeMeasurementCardComponent_Conditional_11_Template, 3, 6, "input", 16)(12, SCurveRelativeMeasurementCardComponent_Conditional_12_Template, 3, 2, "button", 17); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](13, SCurveRelativeMeasurementCardComponent_Conditional_13_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](14, SCurveRelativeMeasurementCardComponent_Conditional_14_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](15, "p-accordion-content", 18); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](16, SCurveRelativeMeasurementCardComponent_ng_container_16_Template, 1, 0, "ng-container", 12); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](17, "div", 19)(18, "div", 20)(19, "div", 21)(20, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](21); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](22, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](23, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](24); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](25, "div", 21)(26, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](27); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](28, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](29, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](30); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditionalCreate"](31, SCurveRelativeMeasurementCardComponent_Conditional_31_Template, 6, 4, "div", 21); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](32, "div", 21)(33, "span", 22); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](34); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](35, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](36, "span", 23); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtext"](37); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipe"](38, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](39, SCurveRelativeMeasurementCardComponent_ng_container_39_Template, 1, 0, "ng-container", 12); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplate"](40, SCurveRelativeMeasurementCardComponent_ng_template_40_Template, 3, 3, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"])(42, SCurveRelativeMeasurementCardComponent_ng_template_42_Template, 2, 5, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"])(44, SCurveRelativeMeasurementCardComponent_ng_template_44_Template, 4, 9, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"])(46, SCurveRelativeMeasurementCardComponent_ng_template_46_Template, 4, 11, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"])(48, SCurveRelativeMeasurementCardComponent_ng_template_48_Template, 3, 0, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"])(50, SCurveRelativeMeasurementCardComponent_ng_template_50_Template, 1, 2, "ng-template", null, 6, _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { let tmp_22_0; let tmp_24_0; const cardIcon_r13 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](43); const contentActions_r14 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](49); const accentBar_r15 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵreference"](51); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵclassMap"](ctx.cn("group flex w-full overflow-hidden border-b border-(--p-app-border-subtle)", ctx.mergedPt().wrapper)); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵstyleMap"](ctx.cardButtonStyle); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("pt", ctx.mergedPt().panel)("dt", ctx.dt())("value", ctx.measurement().id); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("pt", ctx.mergedPt().header); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r15); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](ctx.cdkDrag() ? 4 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", cardIcon_r13); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](ctx.isEditingName() ? 11 : 12); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](!ctx.isEditingName() ? 13 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](ctx.menuTrigger() && ctx.actions().length && !ctx.isEditingName() ? 14 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("pt", ctx.mergedPt().content); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", accentBar_r15); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](22, 24, "annotationMenu.sCurveRelativeMeasurements.sCurve1"), ": "); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", ((tmp_22_0 = ctx.sourceNames()) == null ? null : tmp_22_0[0]) ?? "\u2014", " "); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](28, 26, "annotationMenu.sCurveRelativeMeasurements.sCurve2"), ": "); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", ((tmp_24_0 = ctx.sourceNames()) == null ? null : tmp_24_0[1]) ?? "\u2014", " "); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵconditional"](ctx.isIntersection() ? 31 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"]("", _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind1"](35, 28, "annotationMenu.angle"), ":"); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵtextInterpolate1"](" ", ctx.angleDegrees() !== undefined ? _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵpipeBind2"](38, 30, ctx.angleDegrees(), "1.0-1") + "\u00B0" : "\u2014", " "); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("ngTemplateOutlet", contentActions_r14); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_7__.AccordionContent, primeng_accordion__WEBPACK_IMPORTED_MODULE_7__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_7__.AccordionPanel, _annotation_menu_directives_annotation_menu_trigger_directive__WEBPACK_IMPORTED_MODULE_17__.AnnotationMenuTriggerDirective, primeng_button__WEBPACK_IMPORTED_MODULE_8__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_15__.CancelClickDirective, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragHandle, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDragPlaceholder, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.NgControlStatus, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_15__.IconComponent, primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_9__.InputText, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_5__.FormControlDirective, primeng_tooltip__WEBPACK_IMPORTED_MODULE_10__.Tooltip, _angular_common__WEBPACK_IMPORTED_MODULE_1__.DecimalPipe, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_6__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 17464 /*!*****************************************************************************************************!*\ !*** ./libs/feature/src/lib/s-curve-relative-measurements/s-curve-relative-measurements.service.ts ***! \*****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurveRelativeMeasurementsService: () => (/* binding */ SCurveRelativeMeasurementsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../colors/colors.service */ 39298); class SCurveRelativeMeasurementsService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.AnnotationFacade); sCurveFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.SCurveFacade); colorsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_6__.ColorsService); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore); createAngle(a, b) { const measurement = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.sCurveAngleMeasurement)({ color: this.nextColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.incrementName)('Angle', this.measurementNames(), _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.ANNOTATION_NAME_MAX_LENGTH), sourceIds: [a.id, b.id] }); this.sCurveFacade.addRelativeMeasurement(measurement); } createIntersection(a, b) { const measurement = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.sCurveIntersectionMeasurement)({ color: this.nextColor(), hidden: false, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.incrementName)('Intersection', this.measurementNames(), _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.ANNOTATION_NAME_MAX_LENGTH), sourceIds: [a.id, b.id] }); this.sCurveFacade.addRelativeMeasurement(measurement); } // Rotates the viewports to the angulation where the two source curves cross. // That view has both source planes edge-on, and is also the projection in // which the angle between them appears at true size — so it serves both // measurement types. goTo(measurement) { const sources = this.resolveSources(measurement); if (!sources) return; const angulation = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__.getSCurveIntersectionAngulation)(...sources); if (!angulation) return; // Center on a spline source's annotation when one exists; control-point // curves have no backing annotation. const splineSource = sources.find(source => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.sCurveIsSpline)(source)); if (splineSource) this.annotationFacade.goToAnnotation(splineSource.id, true); const enFace = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__.getSCurveEnFaceAngle)(sources[0]); const cross = gl_matrix__WEBPACK_IMPORTED_MODULE_1__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_1__.create(), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.angulationToVector)(angulation), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.angulationToVector)(enFace)); this.viewportStore.updateAngulationsForAllAxes(angulation, enFace, (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.vectorToAngulation)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.vec3ToPosition)(cross))); } hasGoToTarget(measurement) { const sources = this.resolveSources(measurement); return !!sources && !!(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__.getSCurveIntersectionAngulation)(...sources); } resolveSources(measurement) { const sourcesById = new Map(this.sCurveFacade.sCurves().map(sCurve => [sCurve.id, sCurve])); const [a, b] = measurement.sourceIds.map(id => sourcesById.get(id)); return a && b ? [a, b] : undefined; } nextColor() { const usedColors = new Set([...this.sCurveFacade.relativeMeasurements().map(({ color }) => color), ...this.sCurveFacade.sCurves().map(({ color }) => color)]); const available = this.colorsService.colors.find(color => !usedColors.has(color)); return available ?? this.colorsService.currentColor(); } measurementNames() { return this.sCurveFacade.relativeMeasurements().map(({ name }) => name); } static ɵfac = function SCurveRelativeMeasurementsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurveRelativeMeasurementsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: SCurveRelativeMeasurementsService, factory: SCurveRelativeMeasurementsService.ɵfac }); } /***/ }, /***/ 9610 /*!****************************************************************************!*\ !*** ./libs/feature/src/lib/services/submenu-flip/submenu-flip.service.ts ***! \****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SubmenuFlipService: () => (/* binding */ SubmenuFlipService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); const CONTEXT_MENU_SUB = 'p-contextmenu-sub'; const SUBMENU_LIST_SELECTOR = 'ul.p-contextmenu-submenu'; const BOTTOM_MARGIN = 8; const CONTEXT_MENU_ITEM_ACTIVE = 'p-contextmenu-item-active'; class SubmenuFlipService { observer; positioningSubmenus = new WeakSet(); start(root = document.body) { this.stop(); this.observer = new MutationObserver(mutations => { for (const mutation of mutations) { this.handleAddedNodes(mutation); this.handleClassChange(mutation); } }); this.observer.observe(root, { attributeFilter: ['class'], attributes: true, childList: true, subtree: true }); } stop() { this.observer?.disconnect(); this.observer = undefined; } ngOnDestroy() { this.stop(); } handleAddedNodes(mutation) { for (const node of mutation.addedNodes) { if (!(node instanceof HTMLElement)) continue; if (node.tagName?.toLowerCase() === CONTEXT_MENU_SUB) { this.positionSubmenu(node); } const nestedSubmenus = node.querySelectorAll?.(CONTEXT_MENU_SUB) ?? []; for (const element of nestedSubmenus) { this.positionSubmenu(element); } } } handleClassChange(mutation) { if (mutation.type !== 'attributes' || mutation.attributeName !== 'class') return; const target = mutation.target; const isActive = target.classList.contains(CONTEXT_MENU_ITEM_ACTIVE); if (!isActive) return; const submenu = target.querySelector(`:scope > ${CONTEXT_MENU_SUB}`); if (submenu) this.positionSubmenu(submenu); } positionSubmenu(hostElement) { const submenu = hostElement.querySelector(SUBMENU_LIST_SELECTOR) ?? hostElement.closest(`${CONTEXT_MENU_SUB}`)?.querySelector(SUBMENU_LIST_SELECTOR) ?? hostElement; if (this.positioningSubmenus.has(submenu)) return; this.positioningSubmenus.add(submenu); requestAnimationFrame(() => { this.positioningSubmenus.delete(submenu); const previousTransform = submenu.style.transform; submenu.style.transform = ''; const rect = submenu.getBoundingClientRect(); const overflow = rect.bottom - (window.innerHeight - BOTTOM_MARGIN); if (overflow > 0) { submenu.style.setProperty('transform', `translateY(-${overflow}px)`, 'important'); } if (previousTransform) { submenu.style.transform = previousTransform; } }); } static ɵfac = function SubmenuFlipService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SubmenuFlipService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: SubmenuFlipService, factory: SubmenuFlipService.ɵfac }); } /***/ }, /***/ 3879 /*!********************************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/annotation-panel/annotation-panel.component.ts ***! \********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationPanelComponent: () => (/* binding */ AnnotationPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_message__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/message */ 60134); /* harmony import */ var primeng_tag__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/tag */ 37587); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../annotation-card/annotation-card.component */ 86628); /* harmony import */ var _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _work_session_work_session_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../work-session/work-session.service */ 82757); /* harmony import */ var _services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../services/annotation-panel.service */ 56105); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({}); const _c1 = () => []; const _c2 = () => ({ root: "flex h-[18px] items-center rounded-sm bg-(--p-app-phase-active-item-background)! px-2 text-[10px] leading-none font-normal text-(--p-app-neutral-400)!" }); const _c3 = () => ({ content: "pt-2 pb-4 ml-12" }); const _c4 = () => ({ root: "min-h-11 gap-2 py-0 pl-1.5 text-sm font-normal" }); const _c5 = (a0, a1) => ({ content: a0, header: a1 }); const _forTrack0 = ($index, $item) => $item.phaseId; const _forTrack1 = ($index, $item) => $item.annotation.id; function AnnotationPanelComponent_Conditional_2_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "lib-icon", 4); } } function AnnotationPanelComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "p-message", 2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtemplate"](1, AnnotationPanelComponent_Conditional_2_ng_template_1_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](3, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](4, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipeBind1"](5, 2, "volumeViewer.drawer.content.noAnnotationsFound")); } } function AnnotationPanelComponent_Conditional_3_For_2_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "p-tag", 9); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("value", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipeBind1"](1, 2, "multiphase.inFocus"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](4, _c2)); } } function AnnotationPanelComponent_Conditional_3_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div")(1, "span", 8); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](3, AnnotationPanelComponent_Conditional_3_For_2_Conditional_1_Conditional_3_Template, 2, 5, "p-tag", 9); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("flex h-[32px] items-center justify-between gap-2 px-3 text-xs font-normal uppercase", group_r4.isActive ? "bg-(--p-app-phase-active-background) text-(--p-app-phase-active-color)" : "text-(--p-app-neutral-500)")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtextInterpolate"](group_r4.headerLabel); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](group_r4.isActive ? 3 : -1); } } function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "lib-annotation-card", 10); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("show", function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template_lib_annotation_card_show_0_listener() { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.onShowAnnotation(item_r6.annotation.id)); })("hide", function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template_lib_annotation_card_hide_0_listener() { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.onHideAnnotation(item_r6.annotation.id)); })("updateName", function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template_lib_annotation_card_updateName_0_listener($event) { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.onUpdateAnnotationName($event, item_r6.annotation.id)); })("goTo", function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template_lib_annotation_card_goTo_0_listener() { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.panel.onGoToAnnotation(item_r6.annotation.id) : ctx_r1.revealInPhase(group_r4.phaseId, item_r6.annotation.id)); })("clicked", function AnnotationPanelComponent_Conditional_3_For_2_For_4_Template_lib_annotation_card_clicked_0_listener($event) { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.panel.handleAnnotationCardClick($event, item_r6.annotation.id) : ctx_r1.revealInPhase(group_r4.phaseId, item_r6.annotation.id)); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const item_r6 = ctx.$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); const moreActionsMenu_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("cdkDragDisabled", !group_r4.isActive)("readOnly", !group_r4.isActive)("annotation", item_r6.annotation)("actions", item_r6.moreActions)("selected", item_r6.selected)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction2"](9, _c5, _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](7, _c3), _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](8, _c4)))("menuTrigger", moreActionsMenu_r7); } } function AnnotationPanelComponent_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](1, AnnotationPanelComponent_Conditional_3_For_2_Conditional_1_Template, 4, 4, "div", 3); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](2, "p-accordion", 6); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("cdkDropListDropped", function AnnotationPanelComponent_Conditional_3_For_2_Template_p_accordion_cdkDropListDropped_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.handleAnnotationDrop($event)); })("valueChange", function AnnotationPanelComponent_Conditional_3_For_2_Template_p_accordion_valueChange_2_listener($event) { const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.onAccordionValueChange($event) : ctx_r1.expandOnSwitch(group_r4, $event)); })("click", function AnnotationPanelComponent_Conditional_3_For_2_Template_p_accordion_click_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); $event.preventDefault(); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeaterCreate"](3, AnnotationPanelComponent_Conditional_3_For_2_For_4_Template, 1, 12, "lib-annotation-card", 7, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"]()(); } if (rf & 2) { const group_r4 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn(ctx_r1.showPhaseLabels() && "overflow-hidden rounded-md bg-(--p-app-surface-card)")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](ctx_r1.showPhaseLabels() ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("block", !group_r4.isActive && "opacity-50")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("multiple", true)("cdkDropListDisabled", !group_r4.isActive)("value", group_r4.isActive ? ctx_r1.expandedDrawerPanelIds() : _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](8, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeater"](group_r4.cards); } } function AnnotationPanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div", 5); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("click", function AnnotationPanelComponent_Conditional_3_Template_div_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.deselectAnnotations()); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeaterCreate"](1, AnnotationPanelComponent_Conditional_3_For_2_Template, 5, 9, "div", 3, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("min-h-full", ctx_r1.showPhaseLabels() && "flex flex-col gap-2.5 px-[9px] py-2")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeater"](ctx_r1.displayGroups()); } } class AnnotationPanelComponent { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.AnnotationFacade); panel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_14__.AnnotationPanelService); workSessionService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_work_session_work_session_service__WEBPACK_IMPORTED_MODULE_13__.WorkSessionService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslateService); cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.cn; expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); focusedPhaseId; pendingExpandId; annotations = this.panel.annotations; langChange = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)(this.translate.onLangChange); groups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this.langChange(); const groups = this.workSessionService.annotationGroups(); const gated = groups.some(group => group.identification !== undefined); const word = this.translate.instant(gated ? 'multiphase.phase' : 'multiphase.volume'); const triggerUnit = this.translate.instant('multiphase.triggerUnit'); return groups.map(group => { const detail = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.formatPhaseIdentification)(group.identification, { triggerUnit }); const base = `${word} ${group.label}`; return { ...group, headerLabel: detail ? `${base}: ${detail}` : base }; }); }, ...(ngDevMode ? [{ debugName: "groups" }] : [])); nonEmptyGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.groups().filter(group => group.annotations.length > 0), ...(ngDevMode ? [{ debugName: "nonEmptyGroups" }] : [])); displayGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().map(group => { const cards = group.isActive ? this.annotations() : group.annotations.map(annotation => ({ annotation: { ...annotation, measurements: [] }, contentMenuItems: [], moreActions: [], selected: false })); return { ...group, cards }; }), ...(ngDevMode ? [{ debugName: "displayGroups" }] : [])); hasAnyAnnotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().length > 0, ...(ngDevMode ? [{ debugName: "hasAnyAnnotations" }] : [])); // A single-phase (or single-volume) series has nothing to disambiguate - the phase // header only earns its place once there's more than one group to tell apart. showPhaseLabels = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().length > 1, ...(ngDevMode ? [{ debugName: "showPhaseLabels" }] : [])); constructor() { // Reset expand state on every phase switch, except the card whose chevron triggered it. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const groups = this.nonEmptyGroups(); const focusedPhaseId = groups.find(group => group.isActive)?.phaseId; if (focusedPhaseId === this.focusedPhaseId) return; this.focusedPhaseId = focusedPhaseId; const pending = this.pendingExpandId; this.pendingExpandId = undefined; const expandPending = pending !== undefined && groups.some(group => group.isActive && group.annotations.some(({ id }) => id === pending)); this.expandedDrawerPanelIds.set(expandPending ? [pending] : []); }); } revealInPhase(phaseId, annotationId) { this.workSessionService.requestActiveVolume(phaseId, annotationId); } expandOnSwitch(group, value) { const id = (Array.isArray(value) ? value : []).at(-1); if (id === undefined) return; this.pendingExpandId = id; this.workSessionService.requestActiveVolume(group.phaseId, id); } onAccordionValueChange(value) { this.expandedDrawerPanelIds.set(Array.isArray(value) ? value : []); } handleAnnotationDrop(event) { const currentAnnotations = [...this.annotationFacade.annotations()]; (0,_angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.moveItemInArray)(currentAnnotations, event.previousIndex, event.currentIndex); this.annotationFacade.loadAnnotations(currentAnnotations); } static ɵfac = function AnnotationPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵdefineComponent"]({ type: AnnotationPanelComponent, selectors: [["lib-annotation-panel"]], hostAttrs: [1, "block", "h-full", "overflow-y-auto"], decls: 4, vars: 1, consts: [["moreActionsMenu", ""], ["icon", ""], ["severity", "secondary", "variant", "simple", 1, "p-4", 3, "pt"], [3, "class"], ["icon", "info-circle"], [3, "click"], ["cdkDropList", "", 3, "cdkDropListDropped", "valueChange", "click", "multiple", "cdkDropListDisabled", "value"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "cdkDragDisabled", "readOnly", "annotation", "actions", "selected", "pt", "menuTrigger"], [1, "min-w-0", "truncate"], [3, "value", "pt"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "show", "hide", "updateName", "goTo", "clicked", "cdkDragDisabled", "readOnly", "annotation", "actions", "selected", "pt", "menuTrigger"]], template: function AnnotationPanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "lib-annotation-menu", null, 0); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](2, AnnotationPanelComponent_Conditional_2_Template, 6, 5, "p-message", 2)(3, AnnotationPanelComponent_Conditional_3_Template, 3, 2, "div", 3); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](!ctx.hasAnyAnnotations() ? 2 : 3); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_5__.Accordion, _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_11__.AnnotationCardComponent, _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_12__.AnnotationMenuComponent, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDropList, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDrag, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.IconComponent, primeng_message__WEBPACK_IMPORTED_MODULE_6__.Message, primeng_tag__WEBPACK_IMPORTED_MODULE_7__.Tag, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 40737 /*!**************************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/chamber-panel/chamber-panel.component.ts ***! \**************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberPanelComponent: () => (/* binding */ ChamberPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_message__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/message */ 60134); /* harmony import */ var primeng_tag__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/tag */ 37587); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _chamber_chamber_card_chamber_card_component__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../chamber/chamber-card/chamber-card.component */ 69605); /* harmony import */ var _chamber_chamber_menu_components_chamber_menu_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../chamber/chamber-menu/components/chamber-menu.component */ 23204); /* harmony import */ var _work_session_work_session_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../work-session/work-session.service */ 82757); /* harmony import */ var _services_chamber_panel_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../services/chamber-panel.service */ 38164); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({}); const _c1 = () => []; const _c2 = () => ({ root: "flex h-[18px] items-center rounded-sm bg-(--p-app-phase-active-item-background)! px-2 text-[10px] leading-none font-normal text-(--p-app-neutral-400)!" }); const _c3 = () => ({ content: "pt-2 pb-4 ml-12" }); const _c4 = () => ({ root: "min-h-11 gap-2 py-0 pl-1.5 text-sm font-normal" }); const _c5 = (a0, a1) => ({ content: a0, header: a1 }); const _forTrack0 = ($index, $item) => $item.phaseId; const _forTrack1 = ($index, $item) => $item.chamber.id; function ChamberPanelComponent_Conditional_2_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "lib-icon", 4); } } function ChamberPanelComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "p-message", 2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtemplate"](1, ChamberPanelComponent_Conditional_2_ng_template_1_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](3, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](4, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipeBind1"](5, 2, "volumeViewer.drawer.content.noChambersFound")); } } function ChamberPanelComponent_Conditional_3_For_2_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "p-tag", 9); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipe"](1, "translate"); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("value", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpipeBind1"](1, 2, "multiphase.inFocus"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](4, _c2)); } } function ChamberPanelComponent_Conditional_3_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div")(1, "span", 8); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](3, ChamberPanelComponent_Conditional_3_For_2_Conditional_1_Conditional_3_Template, 2, 5, "p-tag", 9); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("flex h-[32px] items-center justify-between gap-2 px-3 text-xs font-normal uppercase", group_r4.isActive ? "bg-(--p-app-phase-active-background) text-(--p-app-phase-active-color)" : "text-(--p-app-neutral-500)")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵtextInterpolate"](group_r4.headerLabel); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](group_r4.isActive ? 3 : -1); } } function ChamberPanelComponent_Conditional_3_For_2_For_4_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "lib-chamber-card", 10); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("clicked", function ChamberPanelComponent_Conditional_3_For_2_For_4_Template_lib_chamber_card_clicked_0_listener($event) { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.panel.handleChamberCardClick($event, item_r6.chamber.id) : ctx_r1.revealInPhase(group_r4.phaseId, item_r6.chamber.id)); })("updateName", function ChamberPanelComponent_Conditional_3_For_2_For_4_Template_lib_chamber_card_updateName_0_listener($event) { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.onUpdateChamberName($event, item_r6.chamber.id)); })("goTo", function ChamberPanelComponent_Conditional_3_For_2_For_4_Template_lib_chamber_card_goTo_0_listener() { const item_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5).$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.panel.onGoToChamber(item_r6.chamber) : ctx_r1.revealInPhase(group_r4.phaseId, item_r6.chamber.id)); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const item_r6 = ctx.$implicit; const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); const moreActionsMenu_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("cdkDragDisabled", !group_r4.isActive)("readOnly", !group_r4.isActive)("chamber", item_r6.chamber)("actions", item_r6.moreActions)("selected", item_r6.selected)("menuTrigger", moreActionsMenu_r7)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction2"](9, _c5, _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](7, _c3), _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](8, _c4))); } } function ChamberPanelComponent_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div"); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](1, ChamberPanelComponent_Conditional_3_For_2_Conditional_1_Template, 4, 4, "div", 3); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](2, "p-accordion", 6); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("cdkDropListDropped", function ChamberPanelComponent_Conditional_3_For_2_Template_p_accordion_cdkDropListDropped_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.handleAnnotationDrop($event)); })("valueChange", function ChamberPanelComponent_Conditional_3_For_2_Template_p_accordion_valueChange_2_listener($event) { const group_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](group_r4.isActive ? ctx_r1.onAccordionValueChange($event) : ctx_r1.expandOnSwitch(group_r4, $event)); })("click", function ChamberPanelComponent_Conditional_3_For_2_Template_p_accordion_click_2_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); $event.preventDefault(); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeaterCreate"](3, ChamberPanelComponent_Conditional_3_For_2_For_4_Template, 1, 12, "lib-chamber-card", 7, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"]()(); } if (rf & 2) { const group_r4 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn(ctx_r1.showPhaseLabels() && "overflow-hidden rounded-md bg-(--p-app-surface-card)")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](ctx_r1.showPhaseLabels() ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("block", !group_r4.isActive && "opacity-50")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵproperty"]("multiple", true)("cdkDropListDisabled", !group_r4.isActive)("value", group_r4.isActive ? ctx_r1.expandedDrawerPanelIds() : _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵpureFunction0"](8, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeater"](group_r4.cards); } } function ChamberPanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementStart"](0, "div", 5); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵlistener"]("click", function ChamberPanelComponent_Conditional_3_Template_div_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.panel.deselectChambers()); }); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeaterCreate"](1, ChamberPanelComponent_Conditional_3_For_2_Template, 5, 9, "div", 3, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵclassMap"](ctx_r1.cn("min-h-full", ctx_r1.showPhaseLabels() && "flex flex-col gap-2.5 px-[9px] py-2")); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵrepeater"](ctx_r1.displayGroups()); } } class ChamberPanelComponent { chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.ChamberFacade); workSessionService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_work_session_work_session_service__WEBPACK_IMPORTED_MODULE_13__.WorkSessionService); panel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_chamber_panel_service__WEBPACK_IMPORTED_MODULE_14__.ChamberPanelService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslateService); cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.cn; expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); chambers = this.panel.chambers; pendingExpandId; focusedPhaseId; langChange = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toSignal)(this.translate.onLangChange); groups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this.langChange(); const chamberGroups = this.workSessionService.chamberGroups(); const gated = chamberGroups.some(group => group.identification !== undefined); const word = this.translate.instant(gated ? 'multiphase.phase' : 'multiphase.volume'); const triggerUnit = this.translate.instant('multiphase.triggerUnit'); return chamberGroups.map(group => { const detail = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.formatPhaseIdentification)(group.identification, { triggerUnit }); const base = `${word} ${group.label}`; return { ...group, headerLabel: detail ? `${base}: ${detail}` : base }; }); }, ...(ngDevMode ? [{ debugName: "groups" }] : [])); nonEmptyGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.groups().filter(group => group.chambers.length > 0), ...(ngDevMode ? [{ debugName: "nonEmptyGroups" }] : [])); displayGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().map(group => { const cards = group.isActive ? this.chambers() : group.chambers.map(chamber => ({ chamber: { ...chamber }, contentMenuItems: [], moreActions: [], selected: false })); return { ...group, cards }; }), ...(ngDevMode ? [{ debugName: "displayGroups" }] : [])); hasAnyChambers = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().length > 0, ...(ngDevMode ? [{ debugName: "hasAnyChambers" }] : [])); // A single-phase (or single-volume) series has nothing to disambiguate - the phase // header only earns its place once there's more than one group to tell apart. showPhaseLabels = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.nonEmptyGroups().length > 1, ...(ngDevMode ? [{ debugName: "showPhaseLabels" }] : [])); onAccordionValueChange(value) { this.panel.expandedDrawerPanelIds.set(Array.isArray(value) ? value : []); } expandOnSwitch(group, value) { const id = (Array.isArray(value) ? value : []).at(-1); if (id === undefined) return; this.pendingExpandId = id; this.workSessionService.requestActiveChamberVolume(group.phaseId, id); } revealInPhase(phaseId, chamberId) { if (chamberId) { this.workSessionService.requestActiveChamberVolume(phaseId, chamberId); } } handleAnnotationDrop(event) { const currentChambers = [...this.chamberFacade.chambers()]; (0,_angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.moveItemInArray)(currentChambers, event.previousIndex, event.currentIndex); this.chamberFacade.loadChambers(currentChambers); } static ɵfac = function ChamberPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵdefineComponent"]({ type: ChamberPanelComponent, selectors: [["lib-chamber-panel"]], hostAttrs: [1, "block", "h-full", "overflow-y-auto"], decls: 4, vars: 1, consts: [["moreActionsMenu", ""], ["icon", ""], ["severity", "secondary", "variant", "simple", 1, "p-4", 3, "pt"], [3, "class"], ["icon", "info-circle"], [3, "click"], ["cdkDropList", "", 3, "cdkDropListDropped", "valueChange", "click", "multiple", "cdkDropListDisabled", "value"], ["cdkDrag", "true", "cdkDragPreviewContainer", "parent", 1, "block", 3, "cdkDragDisabled", "readOnly", "chamber", "actions", "selected", "menuTrigger", "pt"], [1, "min-w-0", "truncate"], [3, "value", "pt"], ["cdkDrag", "true", "cdkDragPreviewContainer", "parent", 1, "block", 3, "clicked", "updateName", "goTo", "cdkDragDisabled", "readOnly", "chamber", "actions", "selected", "menuTrigger", "pt"]], template: function ChamberPanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵelement"](0, "lib-chamber-menu", null, 0); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditionalCreate"](2, ChamberPanelComponent_Conditional_2_Template, 6, 5, "p-message", 2)(3, ChamberPanelComponent_Conditional_3_Template, 3, 2, "div", 3); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_15__["ɵɵconditional"](!ctx.hasAnyChambers() ? 2 : 3); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_5__.Accordion, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDropList, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDrag, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.IconComponent, primeng_message__WEBPACK_IMPORTED_MODULE_6__.Message, primeng_tag__WEBPACK_IMPORTED_MODULE_7__.Tag, _chamber_chamber_card_chamber_card_component__WEBPACK_IMPORTED_MODULE_11__.ChamberCardComponent, _chamber_chamber_menu_components_chamber_menu_component__WEBPACK_IMPORTED_MODULE_12__.ChamberMenuComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 77391 /*!******************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/index.ts ***! \******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationPanelComponent: () => (/* reexport safe */ _annotation_panel_annotation_panel_component__WEBPACK_IMPORTED_MODULE_0__.AnnotationPanelComponent), /* harmony export */ ChamberPanelComponent: () => (/* reexport safe */ _chamber_panel_chamber_panel_component__WEBPACK_IMPORTED_MODULE_4__.ChamberPanelComponent), /* harmony export */ PlanarReformationPanelComponent: () => (/* reexport safe */ _planar_reformation_panel_planar_reformation_panel_component__WEBPACK_IMPORTED_MODULE_1__.PlanarReformationPanelComponent), /* harmony export */ ProtocolPanelComponent: () => (/* reexport safe */ _protocol_panel_protocol_panel_component__WEBPACK_IMPORTED_MODULE_2__.ProtocolPanelComponent), /* harmony export */ SCurvePanelComponent: () => (/* reexport safe */ _s_curve_panel_s_curve_panel_component__WEBPACK_IMPORTED_MODULE_3__.SCurvePanelComponent) /* harmony export */ }); /* harmony import */ var _annotation_panel_annotation_panel_component__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./annotation-panel/annotation-panel.component */ 3879); /* harmony import */ var _planar_reformation_panel_planar_reformation_panel_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./planar-reformation-panel/planar-reformation-panel.component */ 50075); /* harmony import */ var _protocol_panel_protocol_panel_component__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./protocol-panel/protocol-panel.component */ 94401); /* harmony import */ var _s_curve_panel_s_curve_panel_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./s-curve-panel/s-curve-panel.component */ 30038); /* harmony import */ var _chamber_panel_chamber_panel_component__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./chamber-panel/chamber-panel.component */ 40737); /***/ }, /***/ 50075 /*!************************************************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/planar-reformation-panel/planar-reformation-panel.component.ts ***! \************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PlanarReformationPanelComponent: () => (/* binding */ PlanarReformationPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_message__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/message */ 60134); /* harmony import */ var primeng_selectbutton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/selectbutton */ 50857); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../annotation-card/annotation-card.component */ 86628); /* harmony import */ var _volume_viewer_cpr_cpr_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../volume-viewer/cpr/cpr.service */ 26144); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @angular/core */ 14975); /** * Planar-reformation drawer: the splines a reformation can be opened on, and the session * options for the one currently open. Entering from here is the alternative to the spline's * context menu, and selecting a different spline switches the workspace to it. */ const _c0 = () => ({}); const _c1 = () => ({ content: "pt-0 pb-1 ml-8" }); const _c2 = () => ({ root: "py-1 font-normal" }); const _c3 = (a0, a1) => ({ content: a0, header: a1 }); const _forTrack0 = ($index, $item) => $item.id; function PlanarReformationPanelComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](1, "translate"); } if (rf & 2) { const option_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](1, 1, option_r2.label)); } } function PlanarReformationPanelComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 5)(1, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("onClick", function PlanarReformationPanelComponent_Conditional_8_Template_p_button_onClick_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r3); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r3.confirmEdit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "p-button", 11); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("onClick", function PlanarReformationPanelComponent_Conditional_8_Template_p_button_onClick_3_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r3); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r3.cancelEdit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](2, 2, ctx_r3.confirmLabelKey())); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](4, 4, "planarReformation.cancel")); } } function PlanarReformationPanelComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-button", 12); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("onClick", function PlanarReformationPanelComponent_Conditional_9_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r5); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r3.editCenterline()); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("label", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](1, 2, ctx_r3.editLabelKey()))("disabled", !ctx_r3.workspaceOpen()); } } function PlanarReformationPanelComponent_Conditional_13_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelement"](0, "lib-icon", 13); } } function PlanarReformationPanelComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-message", 8); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtemplate"](1, PlanarReformationPanelComponent_Conditional_13_ng_template_1_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](3, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction0"](4, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](5, 2, "planarReformation.noSplines")); } } function PlanarReformationPanelComponent_Conditional_14_For_2_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "lib-annotation-card", 16); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("clicked", function PlanarReformationPanelComponent_Conditional_14_For_2_Template_lib_annotation_card_clicked_0_listener() { const spline_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r7).$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r3.openReformation(spline_r8)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const spline_r8 = ctx.$implicit; const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("annotation", spline_r8)("selected", spline_r8.id === ctx_r3.activeSplineId())("pt", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction2"](5, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction0"](3, _c1), _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpureFunction0"](4, _c2))); } } function PlanarReformationPanelComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "p-accordion", 14); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("valueChange", function PlanarReformationPanelComponent_Conditional_14_Template_p_accordion_valueChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r6); const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r3.onExpandedChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeaterCreate"](1, PlanarReformationPanelComponent_Conditional_14_For_2_Template, 1, 8, "lib-annotation-card", 15, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("multiple", true)("value", ctx_r3.expandedIds()); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵrepeater"](ctx_r3.splines()); } } const ORIENTATION_OPTIONS = [{ label: 'planarReformation.vertical', value: 'vertical' }, { label: 'planarReformation.horizontal', value: 'horizontal' }]; class PlanarReformationPanelComponent { orientationOptions = ORIENTATION_OPTIONS; session = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.cprSessionStore); // Held here, not inline in the template: a fresh array every change detection // pass would reset the accordion's expanded cards. expandedIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "expandedIds" }] : [])); onExpandedChange(value) { if (Array.isArray(value)) { this.expandedIds.set(value.map(String)); } else if (value === undefined || value === null) { this.expandedIds.set([]); } else { this.expandedIds.set([String(value)]); } } annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.AnnotationFacade); cprService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_volume_viewer_cpr_cpr_service__WEBPACK_IMPORTED_MODULE_13__.CprService); /** Every spline is eligible — the same predicate that gates the annotation-menu entry. */ splines = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.annotationFacade.annotationsWithMeasurements().filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsSpline)(annotation)), ...(ngDevMode ? [{ debugName: "splines" }] : [])); activeSplineId = this.cprService.activeSplineId; workspaceOpen = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.cprService.desiredLayout() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.LayoutType.CPR, ...(ngDevMode ? [{ debugName: "workspaceOpen" }] : [])); editing = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.session.editState() === 'editing', ...(ngDevMode ? [{ debugName: "editing" }] : [])); editLabelKey = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.cprService.activeSplineIsClosed() ? 'planarReformation.editControlPoints' : 'planarReformation.editCenterline', ...(ngDevMode ? [{ debugName: "editLabelKey" }] : [])); confirmLabelKey = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => this.cprService.activeSplineIsClosed() ? 'planarReformation.confirmControlPoints' : 'planarReformation.confirmCenterline', ...(ngDevMode ? [{ debugName: "confirmLabelKey" }] : [])); /** Opens the workspace, or switches it to another spline when one is already open. */ openReformation(spline) { this.cprService.start(spline); } editCenterline() { this.cprService.beginEdit(); } confirmEdit() { this.cprService.confirmEdit(); } cancelEdit() { this.cprService.cancelEdit(); } exitReformation() { this.cprService.cancel(); } setOrientation(orientation) { this.session.setOrientation(orientation); } static ɵfac = function PlanarReformationPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PlanarReformationPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵdefineComponent"]({ type: PlanarReformationPanelComponent, selectors: [["lib-planar-reformation-panel"]], decls: 15, vars: 12, consts: [["item", ""], ["icon", ""], [1, "space-y-3", "border-b", "border-(--p-app-border-subtle)", "p-4"], [1, "text-muted-color", "mb-2", "text-xs", "tracking-wide", "uppercase"], ["data-test-id", "planar-reformation-panel-p-selectbutton-orientation", "optionLabel", "label", "optionValue", "value", "size", "small", "fluid", "", 3, "ngModelChange", "options", "ngModel", "allowEmpty"], [1, "flex", "w-full", "gap-1"], ["data-test-id", "planar-reformation-panel-p-button-edit-centerline", "icon", "pi pi-pencil", "size", "small", "styleClass", "w-full", 1, "block", "w-full", 3, "label", "disabled"], ["type", "button", "data-test-id", "planar-reformation-panel-button-exit", 1, "hover:bg-surface-600", "w-full", "rounded", "border", "border-(--p-app-border-subtle)", "px-2", "py-1", "text-xs", "disabled:cursor-not-allowed", "disabled:opacity-40", "disabled:hover:bg-transparent", 3, "click", "disabled"], ["severity", "secondary", "variant", "simple", 1, "p-4", 3, "pt"], [3, "multiple", "value"], ["data-test-id", "planar-reformation-panel-p-button-confirm-edit", "icon", "pi pi-check", "size", "small", "styleClass", "w-full", 1, "min-w-0", "flex-1", 3, "onClick", "label"], ["data-test-id", "planar-reformation-panel-p-button-cancel-edit", "icon", "pi pi-times", "size", "small", "severity", "secondary", "outlined", "", 3, "onClick", "label"], ["data-test-id", "planar-reformation-panel-p-button-edit-centerline", "icon", "pi pi-pencil", "size", "small", "styleClass", "w-full", 1, "block", "w-full", 3, "onClick", "label", "disabled"], ["icon", "info-circle"], [3, "valueChange", "multiple", "value"], ["readOnly", "", 1, "block", 3, "annotation", "selected", "pt"], ["readOnly", "", 1, "block", 3, "clicked", "annotation", "selected", "pt"]], template: function PlanarReformationPanelComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](0, "div", 2)(1, "fieldset")(2, "legend", 3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](5, "p-selectbutton", 4); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("ngModelChange", function PlanarReformationPanelComponent_Template_p_selectbutton_ngModelChange_5_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx.setOrientation($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtemplate"](6, PlanarReformationPanelComponent_ng_template_6_Template, 2, 3, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](8, PlanarReformationPanelComponent_Conditional_8_Template, 5, 6, "div", 5)(9, PlanarReformationPanelComponent_Conditional_9_Template, 2, 4, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementStart"](10, "button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵlistener"]("click", function PlanarReformationPanelComponent_Template_button_click_10_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx.exitReformation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtext"](11); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipe"](12, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditionalCreate"](13, PlanarReformationPanelComponent_Conditional_13_Template, 6, 5, "p-message", 8)(14, PlanarReformationPanelComponent_Conditional_14_Template, 3, 2, "p-accordion", 9); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](4, 8, "planarReformation.orientation"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("options", ctx.orientationOptions)("ngModel", ctx.session.orientation())("allowEmpty", false); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx.editing() ? 8 : 9); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵproperty"]("disabled", !ctx.workspaceOpen()); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵpipeBind1"](12, 10, "planarReformation.exit"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_14__["ɵɵconditional"](ctx.splines().length === 0 ? 13 : 14); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_4__.Accordion, _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_12__.AnnotationCardComponent, primeng_button__WEBPACK_IMPORTED_MODULE_5__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_5__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_2__.NgModel, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.IconComponent, primeng_message__WEBPACK_IMPORTED_MODULE_6__.Message, primeng_selectbutton__WEBPACK_IMPORTED_MODULE_7__.SelectButtonModule, primeng_selectbutton__WEBPACK_IMPORTED_MODULE_7__.SelectButton, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 94401 /*!****************************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/protocol-panel/protocol-panel.component.ts ***! \****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ProtocolPanelComponent: () => (/* binding */ ProtocolPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 13329); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../annotation-card/annotation-card.component */ 86628); /* harmony import */ var _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _dicom_importer_components_review_dialog_review_dialog_component__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../../dicom-importer/components/review-dialog/review-dialog.component */ 80325); /* harmony import */ var _dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../dicom-importer/services/annotation-export-bridge.service */ 68674); /* harmony import */ var _protocols__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../../protocols */ 61632); /* harmony import */ var _protocols_protocol_form_card_protocol_form_card_component__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../../protocols/protocol-form-card/protocol-form-card.component */ 47716); /* harmony import */ var _services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../services/annotation-panel.service */ 56105); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["placeholder"]; const _c1 = () => ({ root: "py-1 font-normal" }); const _c2 = a0 => ({ header: a0 }); const _c3 = () => ({ content: "pt-0 pb-1 ml-8" }); const _c4 = (a0, a1) => ({ content: a0, header: a1 }); const _forTrack0 = ($index, $item) => $item.placeholder.id; function ProtocolPanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](0, "div", 4)(1, "p-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("click", function ProtocolPanelComponent_Conditional_4_Template_p_button_click_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.onStartClicked()); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](4, "p-button", 9); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("click", function ProtocolPanelComponent_Conditional_4_Template_p_button_click_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.onClearClicked()); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("disabled", ctx_r2.startDisabled()); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipeBind1"](3, 4, ctx_r2.isEmpty() ? "protocols.start" : "protocols.resume"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("disabled", ctx_r2.clearDisabled()); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipeBind1"](6, 6, "protocols.clear"), " "); } } function ProtocolPanelComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](0, "div", 4)(1, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("click", function ProtocolPanelComponent_Conditional_5_Template_p_button_click_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.openReview()); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("disabled", !ctx_r2.canReview())("pTooltip", ctx_r2.canReview() ? "" : _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipeBind1"](2, 3, "protocols.review.disabledHint")); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpipeBind1"](4, 5, "protocols.review.cta"), " "); } } function ProtocolPanelComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](0, "lib-protocol-form-card", 11); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("click", function ProtocolPanelComponent_Conditional_9_Template_lib_protocol_form_card_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r5); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.openForm()); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("formDefinition", ctx)("blocked", ctx_r2.formValid() === true && !ctx_r2.canProceed())("complete", ctx_r2.formValid() === true)("invalid", ctx_r2.formValid() === false)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction1"](6, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction0"](5, _c1))); } } function ProtocolPanelComponent_For_11_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](0, "lib-annotation-card", 14); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("show", function ProtocolPanelComponent_For_11_Conditional_0_Template_lib_annotation_card_show_0_listener() { const annotation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.onShowAnnotation(annotation_r7.id)); })("hide", function ProtocolPanelComponent_For_11_Conditional_0_Template_lib_annotation_card_hide_0_listener() { const annotation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.onHideAnnotation(annotation_r7.id)); })("goTo", function ProtocolPanelComponent_For_11_Conditional_0_Template_lib_annotation_card_goTo_0_listener() { const annotation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.onGoToAnnotation(annotation_r7.id)); })("updateName", function ProtocolPanelComponent_For_11_Conditional_0_Template_lib_annotation_card_updateName_0_listener($event) { const annotation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.onUpdateAnnotationName($event, annotation_r7.id)); })("clicked", function ProtocolPanelComponent_For_11_Conditional_0_Template_lib_annotation_card_clicked_0_listener($event) { const annotation_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r6); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.handleAnnotationCardClick($event, annotation_r7.id)); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"](); } if (rf & 2) { const item_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"]().$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); const annotationActionsMenu_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("annotation", ctx)("actions", item_r8.moreActions)("selected", item_r8.annotationSelected)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction2"](7, _c4, _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction0"](5, _c3), _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction0"](6, _c1)))("menuTrigger", annotationActionsMenu_r9); } } function ProtocolPanelComponent_For_11_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r10 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](0, "lib-placeholder-card", 15, 1); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("click", function ProtocolPanelComponent_For_11_Conditional_1_Template_lib_placeholder_card_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r10); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r2.panel.deselectAnnotations()); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"](); } if (rf & 2) { const item_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"]().$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("placeholder", item_r8.placeholder)("active", ctx_r2.canProceed() && ctx_r2.isPlaceholderActive(item_r8.placeholder))("disabled", !ctx_r2.canProceed())("pt", _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction1"](5, _c2, _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵpureFunction0"](4, _c1))); } } function ProtocolPanelComponent_For_11_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditionalCreate"](0, ProtocolPanelComponent_For_11_Conditional_0_Template, 1, 10, "lib-annotation-card", 12)(1, ProtocolPanelComponent_For_11_Conditional_1_Template, 2, 7, "lib-placeholder-card", 13); } if (rf & 2) { let tmp_11_0; const item_r8 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditional"]((tmp_11_0 = item_r8.annotation) ? 0 : 1, tmp_11_0); } } class ProtocolPanelComponent { confirmationService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_7__.ConfirmationService); panel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_20__.AnnotationPanelService); protocolCreation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_protocols__WEBPACK_IMPORTED_MODULE_18__.ProtocolCreationService); protocolFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_13__.ProtocolFacade); placeholderCards = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChildren)('placeholder', ...(ngDevMode ? [{ debugName: "placeholderCards" }] : [])); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslateService); exportBridge = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_dicom_importer_services_annotation_export_bridge_service__WEBPACK_IMPORTED_MODULE_17__.AnnotationExportBridge); dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_9__.DialogService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_7__.MessageService); reviewContext = this.exportBridge.reviewContext; canReview = this.exportBridge.canReview; // Don't use `panel.expandedPanelIds` because we want to keep new annotations minimized. expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); protocols = this.protocolFacade.protocolDefinitions; activeProtocol = this.protocolFacade.activeProtocol; isEmpty = this.protocolCreation.isEmpty; isStarted = this.protocolCreation.isBeingCreated; _focusOnPlaceholder = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const active = this.protocolCreation.activePlaceholder(); const cards = this.placeholderCards(); if (active) { const card = cards.find(card => card.placeholder() === active); card?.scrollTo(); } }, ...(ngDevMode ? [{ debugName: "_focusOnPlaceholder" }] : [])); startDisabled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const isStarted = this.isStarted(); const { definition, instance } = this.activeProtocol(); // Can't start if already in-progress / finished, or if there's no active protocol return isStarted || !definition || (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.isProtocolComplete)(definition, instance); }, ...(ngDevMode ? [{ debugName: "startDisabled" }] : [])); clearDisabled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const isStarted = this.isStarted(); const { definition, instance } = this.activeProtocol(); const noFormValues = Object.keys(instance?.formValues ?? {}).length === 0; // Can't clear if creation in-progress, empty, or if there's no active protocol return isStarted || !definition || (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.isProtocolEmpty)(instance) && noFormValues; }, ...(ngDevMode ? [{ debugName: "clearDisabled" }] : [])); protocolItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const annotations = this.panel.annotations(); const { definition, instance } = this.activeProtocol(); if (!definition) { return []; } return definition.placeholders.map(placeholder => { const annotation = annotations.find(({ annotation: { id } }) => id === instance?.placeholderMappings[placeholder.id]); return { annotation: annotation?.annotation, annotationSelected: annotation?.selected ?? false, menuItems: annotation?.contentMenuItems ?? [], moreActions: annotation?.moreActions ?? [], placeholder }; }); }, ...(ngDevMode ? [{ debugName: "protocolItems" }] : [])); onProtocolSelect(event) { this.protocolFacade.setActiveProtocol(event.value); } onStartClicked() { this.protocolCreation.start(); } onClearClicked() { const { instance } = this.activeProtocol(); if (instance !== undefined) { this.confirmationService.confirm({ accept: () => { this.protocolCreation.clear(); }, acceptButtonProps: { label: this.translate.instant('protocols.confirmClear.cta.accept'), severity: 'danger' }, acceptLabel: this.translate.instant('protocols.confirmClear.cta.accept'), header: this.translate.instant('protocols.confirmClear.title'), message: this.translate.instant('protocols.confirmClear.message'), rejectButtonProps: { label: this.translate.instant('common.cancel'), outlined: true, severity: 'secondary' } }); } } isPlaceholderActive(placeholder) { return this.protocolCreation.activePlaceholder()?.id === placeholder.id; } onAccordionValueChange(value) { this.expandedDrawerPanelIds.set(Array.isArray(value) ? value : []); } formDefinition = this.protocolCreation.activeProtocolForm; formValid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { instance } = this.activeProtocol(); const formDefinition = this.formDefinition(); if (formDefinition === undefined) { return; } if (instance?.formValues === undefined) { return; } return (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.isProtocolFormValid)(formDefinition, instance.formValues); }, ...(ngDevMode ? [{ debugName: "formValid" }] : [])); canProceed = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const { instance } = this.activeProtocol(); const formDefinition = this.formDefinition(); // No form to check if (formDefinition === undefined) { return true; } return (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_12__.canProceedFromProtocolForm)(formDefinition, instance?.formValues); }, ...(ngDevMode ? [{ debugName: "canProceed" }] : [])); openForm() { this.protocolCreation.openProtocolForm(); } openReview() { const reference = this.dialogService.open(_dicom_importer_components_review_dialog_review_dialog_component__WEBPACK_IMPORTED_MODULE_16__.ReviewDialogComponent, { closable: true, header: this.translate.instant('dicomImporter.reviewDialog.title'), width: '28rem' }); reference?.onClose.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_4__.take)(1)).subscribe(outcome => { if (!outcome) return; this.messageService.add({ ...(outcome.detail ? { detail: outcome.detail } : {}), severity: outcome.severity, summary: this.translate.instant(outcome.messageKey) }); }); } static ɵfac = function ProtocolPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ProtocolPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵdefineComponent"]({ type: ProtocolPanelComponent, selectors: [["lib-protocol-panel"]], viewQuery: function ProtocolPanelComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵviewQuerySignal"](ctx.placeholderCards, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵqueryAdvance"](); } }, decls: 12, vars: 7, consts: [["annotationActionsMenu", ""], ["placeholder", ""], [1, "flex", "h-full", "flex-col"], ["data-test-id", "protocol-panel-p-select-active-protocol", "optionLabel", "name", "optionValue", "id", 1, "m-2", "mb-0", 3, "onChange", "ngModel", "options"], [1, "border-surface-800", "flex", "h-16", "w-full", "items-center", "justify-center", "gap-4", "border-b"], [1, "flex", "h-full", "flex-col", "overflow-x-clip", "overflow-y-auto"], [3, "valueChange", "multiple", "value"], [3, "formDefinition", "blocked", "complete", "invalid", "pt"], ["data-test-id", "protocol-panel-p-button-start", 3, "click", "disabled"], ["data-test-id", "protocol-panel-p-button-clear", 3, "click", "disabled"], ["data-test-id", "protocol-panel-p-button-review", 3, "click", "disabled", "pTooltip"], [3, "click", "formDefinition", "blocked", "complete", "invalid", "pt"], [1, "block", 3, "annotation", "actions", "selected", "pt", "menuTrigger"], [3, "placeholder", "active", "disabled", "pt"], [1, "block", 3, "show", "hide", "goTo", "updateName", "clicked", "annotation", "actions", "selected", "pt", "menuTrigger"], [3, "click", "placeholder", "active", "disabled", "pt"]], template: function ProtocolPanelComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelement"](0, "lib-annotation-menu", null, 0); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](2, "div", 2)(3, "p-select", 3); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("onChange", function ProtocolPanelComponent_Template_p_select_onChange_3_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.onProtocolSelect($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditionalCreate"](4, ProtocolPanelComponent_Conditional_4_Template, 7, 8, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditionalCreate"](5, ProtocolPanelComponent_Conditional_5_Template, 5, 7, "div", 4); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](6, "div", 5)(7, "p-accordion", 6); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵlistener"]("valueChange", function ProtocolPanelComponent_Template_p_accordion_valueChange_7_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx.onAccordionValueChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementStart"](8, "ul"); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditionalCreate"](9, ProtocolPanelComponent_Conditional_9_Template, 1, 8, "lib-protocol-form-card", 7); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrepeaterCreate"](10, ProtocolPanelComponent_For_11_Template, 2, 1, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵelementEnd"]()()()(); } if (rf & 2) { let tmp_1_0; let tmp_3_0; let tmp_7_0; _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("ngModel", (tmp_1_0 = ctx.activeProtocol().definition) == null ? null : tmp_1_0.id)("options", ctx.protocols()); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditional"]((tmp_3_0 = ctx.activeProtocol().definition) ? 4 : -1, tmp_3_0); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditional"](ctx.reviewContext() ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵproperty"]("multiple", true)("value", ctx.expandedDrawerPanelIds()); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵconditional"]((tmp_7_0 = ctx.formDefinition()) ? 9 : -1, tmp_7_0); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrepeater"](ctx.protocolItems()); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_6__.Accordion, _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_14__.AnnotationCardComponent, _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_15__.AnnotationMenuComponent, primeng_button__WEBPACK_IMPORTED_MODULE_8__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_8__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_3__.NgModel, _protocols__WEBPACK_IMPORTED_MODULE_18__.PlaceholderCardComponent, _protocols_protocol_form_card_protocol_form_card_component__WEBPACK_IMPORTED_MODULE_19__.ProtocolFormCardComponent, primeng_select__WEBPACK_IMPORTED_MODULE_10__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_10__.Select, primeng_tooltip__WEBPACK_IMPORTED_MODULE_11__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_11__.Tooltip, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 30038 /*!**************************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/s-curve-panel/s-curve-panel.component.ts ***! \**************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurvePanelComponent: () => (/* binding */ SCurvePanelComponent) /* harmony export */ }); /* harmony import */ var _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/cdk/drag-drop */ 94355); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_message__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/message */ 60134); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../annotation-menu/annotation-menu-item.service */ 39860); /* harmony import */ var _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _s_curve_card_s_curve_card_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../s-curve-card/s-curve-card.component */ 31982); /* harmony import */ var _s_curve_graph_s_curve_graph_component__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../s-curve-graph/s-curve-graph.component */ 1336); /* harmony import */ var _s_curve_relative_measurement_card_s_curve_relative_measurement_card_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../s-curve-relative-measurement-card/s-curve-relative-measurement-card.component */ 8452); /* harmony import */ var _s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../s-curve-relative-measurements/s-curve-relative-measurements.service */ 17464); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({}); const _c1 = () => ({ content: "pt-0 pb-1 ml-8" }); const _c2 = () => ({ root: "py-1 font-normal" }); const _c3 = (a0, a1) => ({ content: a0, header: a1 }); const _forTrack0 = ($index, $item) => $item.id; function SCurvePanelComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "lib-s-curve-graph", 5); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("toggleMaximize", function SCurvePanelComponent_Conditional_3_Template_lib_s_curve_graph_toggleMaximize_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.toggleMaximizeSCurveGraph.emit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("showMaximizeButton", true)("isMaximized", ctx_r1.isMaximized()); } } function SCurvePanelComponent_Conditional_4_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelement"](0, "lib-icon", 6); } } function SCurvePanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "p-message", 4); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtemplate"](1, SCurvePanelComponent_Conditional_4_ng_template_1_Template, 1, 0, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](3, "span"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](4, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpipeBind1"](5, 2, "volumeViewer.drawer.content.noSCurvesFound")); } } function SCurvePanelComponent_Conditional_5_For_3_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "lib-s-curve-card", 12); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("show", function SCurvePanelComponent_Conditional_5_For_3_Template_lib_s_curve_card_show_0_listener() { const sCurve_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSetSCurveVisibility(sCurve_r5, true)); })("hide", function SCurvePanelComponent_Conditional_5_For_3_Template_lib_s_curve_card_hide_0_listener() { const sCurve_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSetSCurveVisibility(sCurve_r5, false)); })("goTo", function SCurvePanelComponent_Conditional_5_For_3_Template_lib_s_curve_card_goTo_0_listener() { const sCurve_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleGoToSCurve(sCurve_r5)); })("clicked", function SCurvePanelComponent_Conditional_5_For_3_Template_lib_s_curve_card_clicked_0_listener($event) { const sCurve_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSCurveCardClick($event, sCurve_r5)); })("updateName", function SCurvePanelComponent_Conditional_5_For_3_Template_lib_s_curve_card_updateName_0_listener($event) { const sCurve_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleUpdateSCurveName(sCurve_r5, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const sCurve_r5 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); const moreActionsMenu_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("menuTrigger", moreActionsMenu_r6)("actions", sCurve_r5.menuItems)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction2"](7, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](5, _c1), _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](6, _c2)))("sCurve", sCurve_r5)("selected", sCurve_r5.selected); } } function SCurvePanelComponent_Conditional_5_For_6_Template(rf, ctx) { if (rf & 1) { const _r7 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "lib-s-curve-relative-measurement-card", 13); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("show", function SCurvePanelComponent_Conditional_5_For_6_Template_lib_s_curve_relative_measurement_card_show_0_listener() { const measurement_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSetMeasurementVisibility(measurement_r8, true)); })("hide", function SCurvePanelComponent_Conditional_5_For_6_Template_lib_s_curve_relative_measurement_card_hide_0_listener() { const measurement_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSetMeasurementVisibility(measurement_r8, false)); })("goTo", function SCurvePanelComponent_Conditional_5_For_6_Template_lib_s_curve_relative_measurement_card_goTo_0_listener() { const measurement_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleGoToMeasurement(measurement_r8)); })("clicked", function SCurvePanelComponent_Conditional_5_For_6_Template_lib_s_curve_relative_measurement_card_clicked_0_listener($event) { const measurement_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleMeasurementCardClick($event, measurement_r8)); })("updateName", function SCurvePanelComponent_Conditional_5_For_6_Template_lib_s_curve_relative_measurement_card_updateName_0_listener($event) { const measurement_r8 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r7).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleUpdateMeasurementName(measurement_r8, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const measurement_r8 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](2); const moreActionsMenu_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵreference"](1); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("menuTrigger", moreActionsMenu_r6)("actions", measurement_r8.menuItems)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction2"](7, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](5, _c1), _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵpureFunction0"](6, _c2)))("measurement", measurement_r8)("selected", measurement_r8.selected); } } function SCurvePanelComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](0, "p-accordion", 7); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("click", function SCurvePanelComponent_Conditional_5_Template_p_accordion_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); $event.preventDefault(); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](1, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("cdkDropListDropped", function SCurvePanelComponent_Conditional_5_Template_div_cdkDropListDropped_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleSCurveDrop($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵrepeaterCreate"](2, SCurvePanelComponent_Conditional_5_For_3_Template, 1, 10, "lib-s-curve-card", 9, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](4, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("cdkDropListDropped", function SCurvePanelComponent_Conditional_5_Template_div_cdkDropListDropped_4_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleMeasurementDrop($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵrepeaterCreate"](5, SCurvePanelComponent_Conditional_5_For_6_Template, 1, 10, "lib-s-curve-relative-measurement-card", 10, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](7, "div", 11); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵlistener"]("click", function SCurvePanelComponent_Conditional_5_Template_div_click_7_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r1.handleBackgroundClick()); }); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵproperty"]("multiple", true)("value", ctx_r1.expandedDrawerPanelIds()); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵrepeater"](ctx_r1.sCurves()); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵrepeater"](ctx_r1.relativeMeasurements()); } } class SCurvePanelComponent { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.AnnotationFacade); annotationMenuItemService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_10__.AnnotationMenuItemService); sCurveFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.SCurveFacade); sCurveRelativeMeasurements = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_15__.SCurveRelativeMeasurementsService); uiFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.UiFacade); expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); // Whether the s-curve view is currently the fullscreen maximized panel - passed down from // whichever ancestor owns the viewport layout state, so the button's icon reflects it. isMaximized = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "isMaximized" }] : [])); // The drawer has no other way to reach the fullscreen s-curve view - forwarded up to // whichever ancestor owns the viewport layout state. toggleMaximizeSCurveGraph = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.output)(); // Maximized and detached are independent states (TVC-1238) - hide the sidebar copy while // either is true, but neither toggle should ever flip the other. Without the isMaximized // check, maximizing (which the page enters without first detaching, as a shortcut - see // toggleSCurveMaximizeFromSidebar) would show the sidebar copy at the same time as the // fullscreen view. showGraph = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => !this.uiFacade.sCurveGraphDetached() && !this.isMaximized(), ...(ngDevMode ? [{ debugName: "showGraph" }] : [])); sCurves = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const selectedIds = this.sCurveFacade.selectedIds(); const sCurves = this.sCurveFacade.sCurves(); return sCurves.map(sCurve => ({ ...sCurve, menuItems: this.annotationMenuItemService.menuItemsForSCurve(sCurve), selected: selectedIds.includes(sCurve.id) })); }, ...(ngDevMode ? [{ debugName: "sCurves" }] : [])); relativeMeasurements = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const selectedIds = this.sCurveFacade.selectedIds(); const measurements = this.sCurveFacade.relativeMeasurements(); return measurements.map(measurement => ({ ...measurement, menuItems: this.annotationMenuItemService.menuItemsForSCurveRelativeMeasurement(measurement), selected: selectedIds.includes(measurement.id) })); }, ...(ngDevMode ? [{ debugName: "relativeMeasurements" }] : [])); handleSCurveDrop(event) { const sCurves = [...this.sCurveFacade.sCurves()]; (0,_angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.moveItemInArray)(sCurves, event.previousIndex, event.currentIndex); this.sCurveFacade.loadSCurves(sCurves); } handleMeasurementDrop(event) { const measurements = [...this.sCurveFacade.relativeMeasurements()]; (0,_angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.moveItemInArray)(measurements, event.previousIndex, event.currentIndex); this.sCurveFacade.reorderRelativeMeasurements(measurements); } handleSCurveCardClick(event, sCurve) { if (event.ctrlKey) { this.sCurveFacade.toggleSelectSCurve(sCurve.id); } else if (event.shiftKey) { this.sCurveFacade.selectSCurvesRange(sCurve.id); } else { this.sCurveFacade.selectSCurves([sCurve.id]); } } handleSetSCurveVisibility(sCurve, visible) { this.sCurveFacade.setSCurveVisibility([sCurve.id], visible); } handleGoToSCurve(sCurve) { // Control-point curves have no backing annotation to center the camera on. if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_7__.sCurveIsSpline)(sCurve)) { this.annotationFacade.goToAnnotation(sCurve.id, true); } } handleUpdateSCurveName(sCurve, name) { this.sCurveFacade.updateSCurve({ id: sCurve.id, name }); } handleMeasurementCardClick(event, measurement) { if (event.ctrlKey) { this.sCurveFacade.toggleSelectSCurve(measurement.id); } else if (event.shiftKey) { this.sCurveFacade.selectSCurvesRange(measurement.id); } else { this.sCurveFacade.selectSCurves([measurement.id]); } } handleSetMeasurementVisibility(measurement, visible) { this.sCurveFacade.setSCurveVisibility([measurement.id], visible); } handleGoToMeasurement(measurement) { this.sCurveRelativeMeasurements.goTo(measurement); } handleUpdateMeasurementName(measurement, name) { this.sCurveFacade.updateRelativeMeasurement({ id: measurement.id, name }); } handleBackgroundClick() { this.sCurveFacade.selectSCurves([]); } static ɵfac = function SCurvePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurvePanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵdefineComponent"]({ type: SCurvePanelComponent, selectors: [["lib-s-curve-panel"]], inputs: { isMaximized: [1, "isMaximized"] }, outputs: { toggleMaximizeSCurveGraph: "toggleMaximizeSCurveGraph" }, decls: 6, vars: 2, consts: [["moreActionsMenu", ""], ["icon", ""], [1, "flex", "h-full", "flex-col"], [3, "showMaximizeButton", "isMaximized"], ["severity", "secondary", "variant", "simple", 1, "p-4", 3, "pt"], [3, "toggleMaximize", "showMaximizeButton", "isMaximized"], ["icon", "info-circle"], [3, "click", "multiple", "value"], ["cdkDropList", "", 3, "cdkDropListDropped"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "menuTrigger", "actions", "pt", "sCurve", "selected"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "menuTrigger", "actions", "pt", "measurement", "selected"], [1, "flex-1", 3, "click"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "show", "hide", "goTo", "clicked", "updateName", "menuTrigger", "actions", "pt", "sCurve", "selected"], ["cdkDrag", "", "cdkDragPreviewContainer", "parent", 1, "block", 3, "show", "hide", "goTo", "clicked", "updateName", "menuTrigger", "actions", "pt", "measurement", "selected"]], template: function SCurvePanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelement"](0, "lib-annotation-menu", null, 0); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementStart"](2, "div", 2); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditionalCreate"](3, SCurvePanelComponent_Conditional_3_Template, 1, 2, "lib-s-curve-graph", 3); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditionalCreate"](4, SCurvePanelComponent_Conditional_4_Template, 6, 5, "p-message", 4)(5, SCurvePanelComponent_Conditional_5_Template, 8, 2); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditional"](ctx.showGraph() ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_16__["ɵɵconditional"](ctx.sCurves().length === 0 ? 4 : 5); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_5__.Accordion, _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_11__.AnnotationMenuComponent, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDropList, _angular_cdk_drag_drop__WEBPACK_IMPORTED_MODULE_0__.CdkDrag, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_9__.IconComponent, primeng_message__WEBPACK_IMPORTED_MODULE_6__.Message, _s_curve_card_s_curve_card_component__WEBPACK_IMPORTED_MODULE_12__.SCurveCardComponent, _s_curve_graph_s_curve_graph_component__WEBPACK_IMPORTED_MODULE_13__.SCurveGraphComponent, _s_curve_relative_measurement_card_s_curve_relative_measurement_card_component__WEBPACK_IMPORTED_MODULE_14__.SCurveRelativeMeasurementCardComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 56105 /*!**********************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/services/annotation-panel.service.ts ***! \**********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationPanelService: () => (/* binding */ AnnotationPanelService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../annotation-menu/annotation-menu-item.service */ 39860); /** * Common annotation-related functionality that is used from multiple sidebar panels * (eg. Annotation Panel, Protocol Panel) */ class AnnotationPanelService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_2__.AnnotationFacade); annotationMenuItemService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_3__.AnnotationMenuItemService); seenAnnotationIds = new Set(); expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const ids = this.annotations().map(a => a.annotation.id); const newIds = ids.filter(id => !this.seenAnnotationIds.has(id)); if (newIds.length > 0) { for (const id of newIds) this.seenAnnotationIds.add(id); this.expandedDrawerPanelIds.update(current => [...current, ...newIds]); } }); } annotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const selectedIds = this.annotationFacade.selectedIds(); return this.annotationFacade.annotationsWithMeasurements().map(annotation => { const menuItems = this.annotationMenuItemService.menuItemsForAnnotation(annotation); const contentMenuItems = menuItems.filter(({ includeInCard }) => includeInCard); return { annotation, contentMenuItems, moreActions: menuItems, selected: selectedIds.includes(annotation.id) }; }); }, ...(ngDevMode ? [{ debugName: "annotations" }] : [])); handleAnnotationCardClick(event, annotationId) { if (event.ctrlKey) { this.annotationFacade.toggleSelectAnnotation(annotationId); } else if (event.shiftKey) { this.annotationFacade.selectAnnotationRange(annotationId); } else { this.annotationFacade.selectAnnotations([annotationId]); } } onShowAnnotation(annotationId) { this.annotationMenuItemService.showAnnotation(annotationId); } onHideAnnotation(annotationId) { this.annotationMenuItemService.hideAnnotation(annotationId); } onGoToAnnotation(annotationId) { this.annotationMenuItemService.goToAnnotation(annotationId); } onUpdateAnnotationName(newName, annotationId) { this.annotationMenuItemService.updateAnnotationName(annotationId, newName); } onAccordionValueChange(value) { this.expandedDrawerPanelIds.set(Array.isArray(value) ? value : []); } deselectAnnotations() { this.annotationFacade.selectAnnotations([]); } static ɵfac = function AnnotationPanelService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationPanelService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: AnnotationPanelService, factory: AnnotationPanelService.ɵfac }); } /***/ }, /***/ 38164 /*!*******************************************************************************!*\ !*** ./libs/feature/src/lib/sidebar-panels/services/chamber-panel.service.ts ***! \*******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ChamberPanelService: () => (/* binding */ ChamberPanelService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../chamber/chamber-menu/chamber-menu-item.service */ 44189); class ChamberPanelService { chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_2__.ChamberFacade); chamberMenuItemService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_3__.ChamberMenuItemService); seenChambersIds = new Set(); expandedDrawerPanelIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([], ...(ngDevMode ? [{ debugName: "expandedDrawerPanelIds" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const ids = this.chambers().map(a => a.chamber.id); const newIds = ids.filter(id => !this.seenChambersIds.has(id)); if (newIds.length > 0) { for (const id of newIds) this.seenChambersIds.add(id); this.expandedDrawerPanelIds.update(current => [...current, ...newIds]); } }); } chambers = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const selectedIds = this.chamberFacade.selectedIds(); return this.chamberFacade.chambers().map(chamber => { const menuItems = this.chamberMenuItemService.menuItemsForChamber(chamber); const contentMenuItems = menuItems.filter(({ includeInCard }) => includeInCard); return { chamber, contentMenuItems, moreActions: menuItems, selected: selectedIds.includes(chamber.id) }; }); }, ...(ngDevMode ? [{ debugName: "chambers" }] : [])); deselectChambers() { this.chamberFacade.selectChambers([]); } handleChamberCardClick(event, chamberId) { if (event.ctrlKey) { this.chamberFacade.toggleSelectChamber(chamberId); } else if (event.shiftKey) { this.chamberFacade.selectChamberRange(chamberId); } else { this.chamberFacade.selectChambers([chamberId]); } } onUpdateChamberName(newName, chamberId) { this.chamberMenuItemService.updateChamberName(chamberId, newName); } onGoToChamber(chamber) { this.chamberMenuItemService.goToChamber(chamber); } static ɵfac = function ChamberPanelService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ChamberPanelService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: ChamberPanelService, factory: ChamberPanelService.ɵfac }); } /***/ }, /***/ 79428 /*!****************************************************************************!*\ !*** ./libs/feature/src/lib/theme-preview/theme-preview-page.component.ts ***! \****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ThemePreviewPageComponent: () => (/* binding */ ThemePreviewPageComponent) /* harmony export */ }); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_checkbox__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/checkbox */ 10026); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_datepicker__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/datepicker */ 83203); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_multiselect__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! primeng/multiselect */ 58612); /* harmony import */ var primeng_panel__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! primeng/panel */ 22949); /* harmony import */ var primeng_popover__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! primeng/popover */ 91124); /* harmony import */ var primeng_progressbar__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/progressbar */ 95932); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var primeng_skeleton__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/skeleton */ 65528); /* harmony import */ var primeng_slider__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! primeng/slider */ 31486); /* harmony import */ var primeng_splitter__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/splitter */ 592); /* harmony import */ var primeng_table__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/table */ 70213); /* harmony import */ var primeng_tabs__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! primeng/tabs */ 70021); /* harmony import */ var primeng_tag__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! primeng/tag */ 37587); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! primeng/api */ 62751); const _c0 = () => ({ height: "8rem" }); const _c1 = () => [60, 40]; const _forTrack0 = ($index, $item) => $item.name; function ThemePreviewPageComponent_For_13_For_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 71); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](1, "div", 72); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](2, "div", 73); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const token_r2 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵstyleProp"]("background", "var(" + token_r2 + ")"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("title", token_r2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", token_r2, " "); } } function ThemePreviewPageComponent_For_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "section")(1, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](3, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeaterCreate"](4, ThemePreviewPageComponent_For_13_For_5_Template, 4, 4, "div", 71, _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeaterTrackByIdentity"]); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const group_r3 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", group_r3.name, " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeater"](group_r3.tokens); } } function ThemePreviewPageComponent_For_19_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 8)(1, "div", 74); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](3, "div", 75); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const token_r4 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("title", token_r4.name); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate1"](" ", token_r4.name, " "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](token_r4.value || "\u2014"); } } function ThemePreviewPageComponent_ng_template_74_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "tr")(1, "th", 76); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2, " Name "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](3, "p-sortIcon", 77); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](4, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](5, "Modality"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](6, "th"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](7, "Series"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } } function ThemePreviewPageComponent_ng_template_75_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "tr", 78)(1, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](3, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](4, "p-tag", 79); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](5, "td"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); } if (rf & 2) { const row_r5 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("pSelectableRow", row_r5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](row_r5.name); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("value", row_r5.modality); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtextInterpolate"](row_r5.series); } } function ThemePreviewPageComponent_ng_template_128_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 80); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1, "Left panel"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } } function ThemePreviewPageComponent_ng_template_129_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 80); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](1, "Right panel"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); } } const scale = (prefix, shades) => shades.map(s => `${prefix}-${s}`); const SHADES = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; const flattenVariables = (group, prefix) => Object.entries(group).flatMap(([key, value]) => typeof value === 'object' ? flattenVariables(value, `${prefix}-${key}`) : [`${prefix}-${key}`]); const FIGMA_PRIMITIVE_GROUPS = new Set(['amber', 'blue', 'emerald', 'green', 'neutral', 'red', 'slate']); const figmaVariables = predicate => Object.entries(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.appColorTokens).filter(([group]) => predicate(group)).flatMap(([group, tokens]) => typeof tokens === 'object' ? flattenVariables(tokens, `--p-app-${group}`) : [`--p-app-${group}`]); /** * Dev-only gallery of every semantic and app design token plus one of each * commonly used PrimeNG component. This is the review surface for a future * light color scheme: toggle the `dark` class on and everything on * this page must remain legible. */ class ThemePreviewPageComponent { tokenGroups = [{ name: 'Primary', tokens: scale('--p-primary', SHADES) }, { name: 'Surface', tokens: ['--p-surface-0', ...scale('--p-surface', SHADES)] }, { name: 'Text', tokens: ['--p-text-color', '--p-text-hover-color', '--p-text-muted-color', '--p-text-hover-muted-color'] }, { name: 'Content', tokens: ['--p-content-background', '--p-content-hover-background', '--p-content-border-color'] }, { name: 'Form field', tokens: ['--p-form-field-background', '--p-form-field-border-color', '--p-form-field-color', '--p-form-field-disabled-background', '--p-form-field-placeholder-color'] }, { name: 'Highlight / focus / mask', tokens: ['--p-highlight-background', '--p-highlight-focus-background', '--p-focus-ring-color', '--p-mask-background'] }, { name: 'Overlays', tokens: ['--p-overlay-select-background', '--p-overlay-popover-background', '--p-overlay-modal-background'] }, { name: 'Figma: primitives', tokens: figmaVariables(group => FIGMA_PRIMITIVE_GROUPS.has(group)) }, { name: 'Figma: semantic + app aliases', tokens: figmaVariables(group => !FIGMA_PRIMITIVE_GROUPS.has(group) && group !== 'annotation' && group !== 'palette') }, { name: 'Figma: annotation (protocol-controlled, TVC-1003)', tokens: figmaVariables(group => group === 'annotation') }, { name: 'Figma: annotation picker palettes', tokens: figmaVariables(group => group === 'palette') }]; rootStyles = globalThis.getComputedStyle(globalThis.document.documentElement); figmaScales = flattenVariables(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.appScaleTokens, '--p-app').map(name => ({ name, value: this.rootStyles.getPropertyValue(name) })); text = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl('Filled value'); emptyText = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(''); disabledText = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl({ disabled: true, value: 'Disabled' }); checked = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(true); unchecked = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(false); slider = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(40); date = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(undefined); select = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl(undefined); multi = new _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControl([]); options = [{ label: 'Option A', value: 'a' }, { label: 'Option B', value: 'b' }, { label: 'Option C', value: 'c' }]; menuItems = [{ icon: 'pi pi-pencil', label: 'Edit' }, { icon: 'pi pi-copy', label: 'Duplicate' }, { disabled: true, icon: 'pi pi-lock', label: 'Disabled item' }, { separator: true }, (0,_tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.dangerMenuItem)({ icon: 'pi pi-trash', label: 'Delete' })]; rows = [{ modality: 'CT', name: 'Sample study', series: 3 }, { modality: 'CT', name: 'Another study', series: 5 }, { modality: 'OT', name: 'Annotated export', series: 1 }]; selectedRow = this.rows[0]; drawerOpen = false; static ɵfac = function ThemePreviewPageComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ThemePreviewPageComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵdefineComponent"]({ type: ThemePreviewPageComponent, selectors: [["lib-theme-preview-page"]], hostAttrs: [1, "block", "h-full", "overflow-y-auto", "bg-surface-950", "text-color"], decls: 150, vars: 31, consts: [["contextMenu", ""], ["popover", ""], [1, "mx-auto", "max-w-5xl", "space-y-10", "p-8"], [1, "text-xl", "font-semibold"], [1, "text-muted-color", "mt-1", "text-sm"], [1, "bg-surface-800", "rounded", "px-1"], [1, "text-muted-color", "mb-2", "text-xs", "font-semibold", "tracking-wide", "uppercase"], [1, "flex", "flex-wrap", "gap-2"], [1, "border-surface-700", "rounded-md", "border", "px-2", "py-1"], [1, "flex", "flex-wrap", "items-center", "gap-3"], ["data-test-id", "theme-preview-p-button-primary", "label", "Primary"], ["data-test-id", "theme-preview-p-button-secondary", "label", "Secondary", "severity", "secondary"], ["data-test-id", "theme-preview-p-button-outlined", "label", "Outlined", "variant", "outlined"], ["data-test-id", "theme-preview-p-button-text", "label", "Text", 3, "text"], ["data-test-id", "theme-preview-p-button-danger", "label", "Danger", "severity", "danger"], ["data-test-id", "theme-preview-p-button-danger-outlined", "label", "Danger outlined", "severity", "danger", "variant", "outlined"], ["data-test-id", "theme-preview-p-button-contrast-outlined", "label", "Contrast outlined", "severity", "contrast", "variant", "outlined"], ["data-test-id", "theme-preview-p-button-plain-text", "label", "Plain text", "severity", "contrast", "plain", "", 3, "text"], ["data-test-id", "theme-preview-p-button-disabled", "label", "Disabled", 3, "disabled"], ["data-test-id", "theme-preview-p-button-tooltip", "label", "With tooltip", "severity", "secondary", "pTooltip", "Tooltip colors", "tooltipPosition", "top"], [1, "grid", "max-w-3xl", "grid-cols-2", "gap-4"], ["data-test-id", "theme-preview-input-filled", "pInputText", "", "placeholder", "Placeholder", 3, "formControl"], ["data-test-id", "theme-preview-input-empty", "pInputText", "", "placeholder", "Placeholder only", 3, "formControl"], ["data-test-id", "theme-preview-input-disabled", "pInputText", "", 3, "formControl"], ["data-test-id", "theme-preview-input-invalid", "pInputText", "", "placeholder", "Invalid state", 1, "ng-invalid", "ng-dirty", 3, "formControl"], ["data-test-id", "theme-preview-p-select-basic", "placeholder", "Select an option", "appendTo", "body", 3, "formControl", "options"], ["data-test-id", "theme-preview-p-multiselect-basic", "placeholder", "Multi select", "appendTo", "body", 3, "formControl", "options"], ["data-test-id", "theme-preview-p-datepicker-basic", "placeholder", "Pick a date", "appendTo", "body", 3, "formControl", "showIcon"], [1, "flex", "items-center", "gap-6"], [1, "flex", "items-center", "gap-2", "text-sm"], ["data-test-id", "theme-preview-p-checkbox-checked", 3, "formControl", "binary"], ["data-test-id", "theme-preview-p-checkbox-unchecked", 3, "formControl", "binary"], [1, "col-span-2", "max-w-md", "pt-2"], ["data-test-id", "theme-preview-p-slider-basic", 3, "formControl"], ["value", "0"], ["data-test-id", "theme-preview-p-tab-first", "value", "0"], ["data-test-id", "theme-preview-p-tab-second", "value", "1"], [1, "text-sm"], ["value", "1"], ["selectionMode", "single", "styleClass", "text-sm", 3, "selectionChange", "value", "selection"], ["pTemplate", "header"], ["pTemplate", "body"], [1, "text-muted-color", "mb-2", "text-xs"], ["data-test-id", "theme-preview-p-menu-example", "styleClass", "w-56", 3, "model"], ["data-test-id", "theme-preview-div-contextmenu-target", 1, "border-surface-700", "text-muted-color", "rounded-md", "border", "border-dashed", "px-4", "py-2", "text-sm", "select-none", 3, "contextmenu"], ["popup", "", "appendTo", "body", 3, "model"], ["data-test-id", "theme-preview-p-button-open-popover", "label", "Open popover", "severity", "secondary", 3, "click"], ["appendTo", "body"], [1, "w-64", "p-1", "text-sm"], [1, "font-semibold"], [1, "text-muted-color", "mt-1"], ["data-test-id", "theme-preview-p-button-open-drawer", "label", "Open drawer", "severity", "secondary", 3, "click"], ["header", "Drawer", 3, "drawerVisibleChange", "drawerVisible"], [1, "p-4", "text-sm"], ["value", "0", "data-test-id", "theme-preview-p-accordion-example"], ["data-test-id", "theme-preview-p-panel-example", 3, "showHeader"], [3, "panelSizes"], ["pTemplate", ""], [1, "flex", "flex-wrap", "items-center", "gap-4"], ["value", "Default"], ["value", "Secondary", "severity", "secondary"], ["value", "Success", "severity", "success"], ["value", "Warn", "severity", "warn"], ["value", "Danger", "severity", "danger"], ["styleClass", "h-2 w-40", 3, "value", "showValue"], ["width", "10rem", "height", "2rem"], [1, "mt-4", "flex", "flex-wrap", "gap-4", "text-sm"], [1, "text-(--p-app-status-success)"], [1, "text-(--p-app-status-danger)"], [1, "rounded", "bg-(--p-app-status-danger-background)", "px-2", "py-1"], [1, "rounded", "bg-(--p-app-phase-active-background)", "px-2", "py-1", "text-(--p-app-phase-active-color)"], [1, "w-28"], [1, "border-surface-700", "h-10", "rounded-md", "border"], [1, "text-muted-color", "mt-1", "truncate", "font-mono", "text-[10px]", 3, "title"], [1, "text-muted-color", "truncate", "font-mono", "text-[10px]", 3, "title"], [1, "font-mono", "text-xs"], ["pSortableColumn", "name"], ["field", "name"], [3, "pSelectableRow"], ["severity", "secondary", 3, "value"], [1, "flex", "h-full", "w-full", "items-center", "justify-center", "text-sm"]], template: function ThemePreviewPageComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](0, "div", 2)(1, "header")(2, "h1", 3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](3, "Theme preview"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](4, "p", 4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](5, " Every color below comes from a design token. To review a scheme, toggle the "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](6, "code", 5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](7, "dark"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](8, " class on "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](9, "code", 5); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](10, ""); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](11, " \u2014 nothing on this page may become unreadable. "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeaterCreate"](12, ThemePreviewPageComponent_For_13_Template, 6, 1, "section", null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](14, "section")(15, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](16, " Figma: dimension, focus, font "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](17, "div", 7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeaterCreate"](18, ThemePreviewPageComponent_For_19_Template, 5, 3, "div", 8, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](20, "section")(21, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](22, "Buttons"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](23, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](24, "p-button", 10)(25, "p-button", 11)(26, "p-button", 12)(27, "p-button", 13)(28, "p-button", 14)(29, "p-button", 15)(30, "p-button", 16)(31, "p-button", 17)(32, "p-button", 18)(33, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](34, "section")(35, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](36, "Form fields"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](37, "div", 20); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](38, "input", 21)(39, "input", 22)(40, "input", 23)(41, "input", 24)(42, "p-select", 25)(43, "p-multiselect", 26)(44, "p-datepicker", 27); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](45, "div", 28)(46, "label", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](47, "p-checkbox", 30); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](48, " Checked "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](49, "label", 29); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](50, "p-checkbox", 31); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](51, " Unchecked "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](52, "div", 32); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](53, "p-slider", 33); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](54, "section")(55, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](56, "Tabs"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](57, "p-tabs", 34)(58, "p-tablist")(59, "p-tab", 35); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](60, "First tab"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](61, "p-tab", 36); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](62, "Second tab"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](63, "p-tabpanels")(64, "p-tabpanel", 34)(65, "p", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](66, "Tab panel content on the content background."); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](67, "p-tabpanel", 38)(68, "p", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](69, "Second panel."); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](70, "section")(71, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](72, "Table"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](73, "p-table", 39); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayListener"]("selectionChange", function ThemePreviewPageComponent_Template_p_table_selectionChange_73_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrestoreView"](_r1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayBindingSet"](ctx.selectedRow, $event) || (ctx.selectedRow = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplate"](74, ThemePreviewPageComponent_ng_template_74_Template, 8, 0, "ng-template", 40)(75, ThemePreviewPageComponent_ng_template_75_Template, 7, 4, "ng-template", 41); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](76, "section")(77, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](78, "Menu"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](79, "p", 42); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](80, " Hover/focus highlight must match every other openable overlay (context menus, selects): surface-800, selected options surface-700. "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](81, "p-menu", 43); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](82, "section")(83, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](84, " Context menu, popover, drawer "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](85, "div", 9)(86, "div", 44); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("contextmenu", function ThemePreviewPageComponent_Template_div_contextmenu_86_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrestoreView"](_r1); const contextMenu_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](89); return _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵresetView"](contextMenu_r6.show($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](87, " Right-click here for a context menu "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](88, "p-contextmenu", 45, 0); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](90, "p-button", 46); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ThemePreviewPageComponent_Template_p_button_click_90_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrestoreView"](_r1); const popover_r7 = _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵreference"](92); return _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵresetView"](popover_r7.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](91, "p-popover", 47, 1)(93, "div", 48)(94, "p", 49); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](95, "Popover"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](96, "p", 50); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](97, " Overlay background, border, radius and gutter come from the preset. "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](98, "p-button", 51); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵlistener"]("click", function ThemePreviewPageComponent_Template_p_button_click_98_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵresetView"](ctx.drawerOpen = true); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](99, "lib-drawer", 52); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayListener"]("drawerVisibleChange", function ThemePreviewPageComponent_Template_lib_drawer_drawerVisibleChange_99_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵrestoreView"](_r1); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayBindingSet"](ctx.drawerOpen, $event) || (ctx.drawerOpen = $event); return _angular_core__WEBPACK_IMPORTED_MODULE_21__["ɵɵresetView"]($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](100, "p", 53); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](101, "Drawer surface, border and text come from the preset."); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](102, "section")(103, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](104, "Accordion"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](105, "p-accordion", 54)(106, "p-accordion-panel", 34)(107, "p-accordion-header"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](108, "Expanded panel"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](109, "p-accordion-content")(110, "p", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](111, "Header, content and toggle-icon colors are stock Aura."); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](112, "p-accordion-panel", 38)(113, "p-accordion-header"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](114, "Collapsed panel"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](115, "p-accordion-content")(116, "p", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](117, "Second panel."); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](118, "section")(119, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](120, "Panel"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](121, "p-panel", 55)(122, "p", 37); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](123, " Headerless panel as used by the heading area: info-block background, subtle border, lg radius. "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](124, "section")(125, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](126, "Splitter"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](127, "p-splitter", 56); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtemplate"](128, ThemePreviewPageComponent_ng_template_128_Template, 2, 0, "ng-template", 57)(129, ThemePreviewPageComponent_ng_template_129_Template, 2, 0, "ng-template", 57); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](130, "section")(131, "h2", 6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](132, " Tags, progress, skeleton "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](133, "div", 58); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelement"](134, "p-tag", 59)(135, "p-tag", 60)(136, "p-tag", 61)(137, "p-tag", 62)(138, "p-tag", 63)(139, "p-progressbar", 64)(140, "p-skeleton", 65); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](141, "div", 66)(142, "span", 67); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](143, "Success text"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](144, "span", 68); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](145, "Danger text"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](146, "span", 69); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](147, "Danger surface"); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementStart"](148, "span", 70); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtext"](149, " Active phase "); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵelementEnd"]()()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeater"](ctx.tokenGroups); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵrepeater"](ctx.figmaScales); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](9); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("text", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("text", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("disabled", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.text); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.emptyText); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.disabledText); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.emptyText); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.select)("options", ctx.options); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.multi)("options", ctx.options); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.date)("showIcon", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.checked)("binary", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.unchecked)("binary", true); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("formControl", ctx.slider); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](20); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("value", ctx.rows); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayProperty"]("selection", ctx.selectedRow); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](8); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("model", ctx.menuItems); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("model", ctx.menuItems); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](11); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵtwoWayProperty"]("drawerVisible", ctx.drawerOpen); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](22); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("showHeader", false); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵstyleMap"](_angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction0"](29, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("panelSizes", _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵpureFunction0"](30, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵadvance"](12); _angular_core__WEBPACK_IMPORTED_MODULE_22__["ɵɵproperty"]("value", 60)("showValue", false); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_1__.AccordionModule, primeng_accordion__WEBPACK_IMPORTED_MODULE_1__.Accordion, primeng_api__WEBPACK_IMPORTED_MODULE_23__.PrimeTemplate, primeng_accordion__WEBPACK_IMPORTED_MODULE_1__.AccordionPanel, primeng_accordion__WEBPACK_IMPORTED_MODULE_1__.AccordionHeader, primeng_accordion__WEBPACK_IMPORTED_MODULE_1__.AccordionContent, primeng_button__WEBPACK_IMPORTED_MODULE_2__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_2__.Button, primeng_checkbox__WEBPACK_IMPORTED_MODULE_3__.CheckboxModule, primeng_checkbox__WEBPACK_IMPORTED_MODULE_3__.Checkbox, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_4__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_4__.ContextMenu, primeng_datepicker__WEBPACK_IMPORTED_MODULE_5__.DatePickerModule, primeng_datepicker__WEBPACK_IMPORTED_MODULE_5__.DatePicker, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.DrawerComponent, primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__.InputText, primeng_menu__WEBPACK_IMPORTED_MODULE_7__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_7__.Menu, primeng_multiselect__WEBPACK_IMPORTED_MODULE_8__.MultiSelectModule, primeng_multiselect__WEBPACK_IMPORTED_MODULE_8__.MultiSelect, primeng_panel__WEBPACK_IMPORTED_MODULE_9__.PanelModule, primeng_panel__WEBPACK_IMPORTED_MODULE_9__.Panel, primeng_popover__WEBPACK_IMPORTED_MODULE_10__.PopoverModule, primeng_popover__WEBPACK_IMPORTED_MODULE_10__.Popover, primeng_progressbar__WEBPACK_IMPORTED_MODULE_11__.ProgressBarModule, primeng_progressbar__WEBPACK_IMPORTED_MODULE_11__.ProgressBar, _angular_forms__WEBPACK_IMPORTED_MODULE_0__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_0__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_0__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_0__.FormControlDirective, primeng_select__WEBPACK_IMPORTED_MODULE_12__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_12__.Select, primeng_skeleton__WEBPACK_IMPORTED_MODULE_13__.SkeletonModule, primeng_skeleton__WEBPACK_IMPORTED_MODULE_13__.Skeleton, primeng_slider__WEBPACK_IMPORTED_MODULE_14__.SliderModule, primeng_slider__WEBPACK_IMPORTED_MODULE_14__.Slider, primeng_splitter__WEBPACK_IMPORTED_MODULE_15__.SplitterModule, primeng_splitter__WEBPACK_IMPORTED_MODULE_15__.Splitter, primeng_table__WEBPACK_IMPORTED_MODULE_16__.TableModule, primeng_table__WEBPACK_IMPORTED_MODULE_16__.Table, primeng_table__WEBPACK_IMPORTED_MODULE_16__.SortableColumn, primeng_table__WEBPACK_IMPORTED_MODULE_16__.SelectableRow, primeng_table__WEBPACK_IMPORTED_MODULE_16__.SortIcon, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.TabsModule, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.Tabs, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.TabPanels, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.TabPanel, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.TabList, primeng_tabs__WEBPACK_IMPORTED_MODULE_17__.Tab, primeng_tag__WEBPACK_IMPORTED_MODULE_18__.TagModule, primeng_tag__WEBPACK_IMPORTED_MODULE_18__.Tag, primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__.TooltipModule, primeng_tooltip__WEBPACK_IMPORTED_MODULE_19__.Tooltip], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 75048 /*!***************************************************************!*\ !*** ./libs/feature/src/lib/tool-menu/tool-menu.component.ts ***! \***************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ToolMenuComponent: () => (/* binding */ ToolMenuComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! gl-matrix */ 95329); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../colors/colors.service */ 39298); /* harmony import */ var _create_object3d_dialog_create_object3d_dialog_component__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../create-object3d-dialog/create-object3d-dialog.component */ 7110); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _protocols__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../protocols */ 61632); /* harmony import */ var _relative_measurements_relative_measurement_dialog_relative_measurement_dialog_component__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../relative-measurements/relative-measurement-dialog/relative-measurement-dialog.component */ 52569); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["relativeMenu"]; const _c1 = ["object3dMenu"]; /* eslint-disable perfectionist/sort-objects */ const RELATIONSHIP_SPECS = { 'attached-point': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.POINT, isActive(annotations) { return annotations.length > 0; } }, 'curvature-point': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.POINT, isActive(annotations) { return annotations.some(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsSpline)(annotation)); }, hasSeparator: true }, 'attached-distance': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.length > 0; } }, 'center-distance': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.length > 0; } }, chord: { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.some(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsSpline)(annotation) || annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.ANGLE); } }, 'closest-distance-between-annotations': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.filter(annotation => !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsObject3D)(annotation)).length >= 2; } }, 'closest-distance-to-one-annotation': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.some(annotation => !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsPoint)(annotation)); } }, 'projected-distance': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.some(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsSpline)(annotation)); } }, 'projected-distance-from-point': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE, isActive(annotations) { return annotations.some(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsSpline)(annotation)) && annotations.some(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsPoint)(annotation)); }, hasSeparator: true }, 'angle-between-spline-axes': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.ANGLE, isActive(annotations) { return annotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsClosedSpline)(annotation)).length >= 2; } }, 'angle-between-splines': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.ANGLE, isActive(annotations) { return annotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsClosedSpline)(annotation)).length >= 2; }, hasSeparator: true }, 'attached-spline': { annotationType: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.OPEN_SPLINE, isActive(annotations) { return annotations.length > 0; } } }; /* eslint-enable perfectionist/sort-objects */ class ToolMenuComponent { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.AnnotationFacade); colorsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_14__.ColorsService); protocolCreation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_protocols__WEBPACK_IMPORTED_MODULE_17__.ProtocolCreationService); dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_7__.DialogService); interactionModeService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_16__.InteractionModeService); object3DGeometryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.Object3DGeometryFacade); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_5__.TranslateService); viewportStoreInstance = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_10__.viewportStore); constructor() { // Plain DOM listener so unrelated keystrokes skip Angular change detection. globalThis.addEventListener('keydown', this.handleProtocolNavigation); (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_2__.DestroyRef).onDestroy(() => globalThis.removeEventListener('keydown', this.handleProtocolNavigation)); } relativeMenu = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('relativeMenu'); object3dMenu = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('object3dMenu'); currentLang = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)(this.translate.onLangChange, { initialValue: undefined }); object3dTypes = ['cylinder', 'hollow_cylinder', 'stl_file']; activeToolType = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const beingCreated = this.annotationFacade.annotationBeingCreated(); const beingAddedTo = this.interactionModeService.annotationAddingPointsTo(); return beingCreated?.type ?? beingAddedTo?.type; }, ...(ngDevMode ? [{ debugName: "activeToolType" }] : [])); protocolProgress = this.protocolCreation.progress; activePlaceholder = this.protocolCreation.activePlaceholder; activePlaceholderFilled = this.protocolCreation.activePlaceholderFilled; relativeMeasurementsMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const annotations = this.annotationFacade.annotations(); const items = Object.entries(RELATIONSHIP_SPECS).flatMap(([type, { annotationType, isActive }]) => { const menuItem = { command: () => { this.openRelativeMeasurementDialog(type); }, disabled: !isActive(annotations), icon: annotationType, label: this.relationshipLabel(type) }; if (RELATIONSHIP_SPECS[type]?.hasSeparator) { return [menuItem, { separator: true }]; } return [menuItem]; }); return items; }, ...(ngDevMode ? [{ debugName: "relativeMeasurementsMenuItems" }] : [])); object3dMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { this.currentLang(); return this.object3dTypes.flatMap(type => { const item = { command: () => this.openCreateObject3DDialog(type), icon: 'object-3d', label: this.object3dTypeLabel(type) }; return type === 'stl_file' ? [{ separator: true }, item] : [item]; }); }, ...(ngDevMode ? [{ debugName: "object3dMenuItems" }] : [])); openRelativeMeasurementDialog(type) { this.dialogService.open(_relative_measurements_relative_measurement_dialog_relative_measurement_dialog_component__WEBPACK_IMPORTED_MODULE_18__.RelativeMeasurementDialogComponent, { closeOnEscape: true, header: 'Create ' + this.relationshipLabel(type), inputValues: { annotations: this.annotationFacade.annotations(), relationshipType: type }, modal: true, width: '400px' }); } openCreateObject3DMenu(event) { this.relativeMenu().hide(); this.object3dMenu().show(event); } openCreateObject3DDialog(type) { this.annotationFacade.deselectAllAnnotations(); const label = this.object3dTypeLabel(type); const dialog = this.dialogService.open(_create_object3d_dialog_create_object3d_dialog_component__WEBPACK_IMPORTED_MODULE_15__.CreateObject3DDialogComponent, { closeOnEscape: true, header: type === 'stl_file' ? label : `${this.translate.instant('createObject3d.create')} ${label}`, inputValues: { object3DType: type }, modal: true, width: '400px' }); dialog?.onClose.subscribe(result => { if (!result) return; this.handleObject3DCreation(result); }); } openRelativeMeasurementsMenu(event) { this.object3dMenu().hide(); this.relativeMenu().show(event); } cancelProtocol() { this.protocolCreation.cancelCurrentStep(); } setActiveToolType(toolType) { const existingNames = this.annotationFacade.annotations().map(ann => ann.name); switch (toolType) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.ANGLE: { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.angle)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Angle', existingNames), points: [] })); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.CLOSED_SPLINE: { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.closedSpline)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Closed Spline', existingNames), points: [] })); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.DISTANCE: { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.distance)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Distance', existingNames), points: [] })); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.OPEN_SPLINE: { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.openSpline)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Open Spline', existingNames), points: [] })); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationSourceType.POINT: { this.annotationFacade.creatingAnnotation((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.point)({ color: this.colorsService.currentColor(), hidden: true, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Point', existingNames), position: [Infinity, Infinity, Infinity] })); break; } default: { // Once we handle more tool types, this will only happen when setting `undefined` this.annotationFacade.cancelAnnotationCreation(); } } } startPlaceholder() { this.protocolCreation.handleCurrentPlaceholder(); } nextPlaceholder() { this.protocolCreation.goToNextPlaceholder(); } restartStep() { this.protocolCreation.restartCurrentStep(); } undo() { this.protocolCreation.undo(); } handleObject3DCreation(result) { const existingNames = this.annotationFacade.annotations().map(a => a.name); const color = this.colorsService.currentColor(); const crosshairPosition = this.viewportStoreInstance.intersection(); switch (result.object3DType) { case 'cylinder': { const annotation = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.cylinder)({ color, diameter: result.diameter, height: result.height, hidden: false, locked: result.locked, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Cylinder', existingNames), orientation: [0, 0, 0, 1], position: crosshairPosition, sides: 100 }); this.annotationFacade.addAnnotations(annotation); this.annotationFacade.selectAnnotations([annotation.id]); break; } case 'hollow_cylinder': { const annotation = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.hollowCylinder)({ color, height: result.height, hidden: false, innerDiameter: result.innerDiameter, locked: result.locked, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)('Hollow Cylinder', existingNames), orientation: [0, 0, 0, 1], outerDiameter: result.outerDiameter, position: crosshairPosition, sides: 100 }); this.annotationFacade.addAnnotations(annotation); this.annotationFacade.selectAnnotations([annotation.id]); break; } case 'stl_file': { this.handleStlImport(result); break; } } this.colorsService.nextColor(); } // Matched on event.code so the WASD aliases work on any keyboard layout. handleProtocolNavigation = event => { switch (event.code) { case 'ArrowLeft': case 'KeyA': { if (!this.validateKeyboardEvent(event)) return; this.handleProtocolBack(); break; } case 'ArrowRight': case 'KeyD': { if (!this.validateKeyboardEvent(event)) return; this.handleProtocolForward(); break; } } }; handleProtocolBack() { // Skip if no active placeholder if (!this.protocolCreation.activePlaceholder()) { return; } // If in the confirmation phase, restart step if (this.protocolCreation.activePlaceholderFilled()) { this.restartStep(); return; } // If in the preparation phase, go back a step (undo) if (this.activeToolType() === undefined) { this.undo(); } } handleProtocolForward() { // Skip if no active placeholder if (!this.protocolCreation.activePlaceholder()) { return; } // If in the confirmation phase, complete step if (this.protocolCreation.activePlaceholderFilled()) { this.nextPlaceholder(); return; } // If in the preparation phase, start creation if (this.activeToolType() === undefined) { this.startPlaceholder(); } } relationshipLabel(type) { return this.translate.instant(`annotationMenu.relativeMeasurements.${(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.toCamelCase)(type)}`); } object3dTypeLabel(type) { return this.translate.instant(`createObject3d.types.${(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.toCamelCase)(type)}`); } handleStlImport(result) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!result.stlData) return; const existingNames = _this.annotationFacade.annotations().map(a => a.name); const color = _this.colorsService.currentColor(); const crosshairPosition = _this.viewportStoreInstance.intersection(); let { vertices } = result.stlData; const { centroid, fileName, normals } = result.stlData; let axisOfSymmetryRotation = [...gl_matrix__WEBPACK_IMPORTED_MODULE_6__.create()]; // A segmentation mesh is already in patient space: import it at its // embedded coordinates instead of dropping it at the crosshair, and lock // it so it cannot drift out of alignment with the volume. const isSegmentation = result.stlImportMode === 'segmentation'; if (!isSegmentation) { const aligned = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.autoAlignAxis)(vertices, centroid); vertices = aligned.alignedVertices; axisOfSymmetryRotation = aligned.rotationMatrix; } const baseName = fileName.replace(/\.stl$/i, ''); const geometry = { centroid: [...centroid], indices: new Uint32Array(0), normals, vertices }; const geometryId = `stl:${yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.hashObject3DGeometry)(geometry)}`; const annotation = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.stlObject3D)({ autoAlignAxis: !isSegmentation, axisOfSymmetryRotation, centerOfRotation: [...centroid], color, fileName, geometryId, hidden: false, locked: isSegmentation, name: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.incrementName)(baseName, existingNames, _tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.ANNOTATION_NAME_MAX_LENGTH), orientation: [0, 0, 0, 1], position: isSegmentation ? [...centroid] : crosshairPosition }); _this.object3DGeometryFacade.setStlGeometry(annotation.id, geometryId, geometry); _this.annotationFacade.addAnnotations(annotation); _this.annotationFacade.selectAnnotations([annotation.id]); })(); } validateKeyboardEvent(event) { if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) return false; if (event.repeat) return false; if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_12__.isEditableTarget)(event.target)) return false; return true; } static ɵfac = function ToolMenuComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ToolMenuComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵdefineComponent"]({ type: ToolMenuComponent, selectors: [["lib-tool-menu"]], viewQuery: function ToolMenuComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵviewQuerySignal"](ctx.relativeMenu, _c0, 5)(ctx.object3dMenu, _c1, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵqueryAdvance"](2); } }, decls: 5, vars: 6, consts: [["relativeMenu", ""], ["object3dMenu", ""], [3, "toolChanged", "createObject3DClicked", "openRelativeMeasurements", "startPlaceholder", "placeholderComplete", "protocolCancelled", "stepRestarted", "undoPlaceholder", "activeTool", "activePlaceholder", "activePlaceholderFilled", "protocolProgress"], [3, "model"]], template: function ToolMenuComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementStart"](0, "lib-toolbar", 2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵlistener"]("toolChanged", function ToolMenuComponent_Template_lib_toolbar_toolChanged_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.setActiveToolType($event)); })("createObject3DClicked", function ToolMenuComponent_Template_lib_toolbar_createObject3DClicked_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.openCreateObject3DMenu($event)); })("openRelativeMeasurements", function ToolMenuComponent_Template_lib_toolbar_openRelativeMeasurements_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.openRelativeMeasurementsMenu($event)); })("startPlaceholder", function ToolMenuComponent_Template_lib_toolbar_startPlaceholder_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.startPlaceholder()); })("placeholderComplete", function ToolMenuComponent_Template_lib_toolbar_placeholderComplete_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.nextPlaceholder()); })("protocolCancelled", function ToolMenuComponent_Template_lib_toolbar_protocolCancelled_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.cancelProtocol()); })("stepRestarted", function ToolMenuComponent_Template_lib_toolbar_stepRestarted_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.restartStep()); })("undoPlaceholder", function ToolMenuComponent_Template_lib_toolbar_undoPlaceholder_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.undo()); }); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵelement"](1, "lib-annotation-menu", 3, 0)(3, "lib-annotation-menu", 3, 1); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("activeTool", ctx.activeToolType())("activePlaceholder", ctx.activePlaceholder())("activePlaceholderFilled", ctx.activePlaceholderFilled())("protocolProgress", ctx.protocolProgress()); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("model", ctx.relativeMeasurementsMenuItems()); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_19__["ɵɵproperty"]("model", ctx.object3dMenuItems()); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_11__.ToolbarComponent, _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_13__.AnnotationMenuComponent], encapsulation: 2 }); } /***/ }, /***/ 71202 /*!*************************************************************************!*\ !*** ./libs/feature/src/lib/top-navigation/top-navigation.component.ts ***! \*************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TopNavigationComponent: () => (/* binding */ TopNavigationComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 13333); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 69042); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! rxjs */ 13329); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_avatar__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/avatar */ 30430); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _dicom_importer_components_export_to_store_dialog_export_to_store_dialog_component__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ../dicom-importer/components/export-to-store-dialog/export-to-store-dialog.component */ 26133); /* harmony import */ var _work_session_nav_work_session_nav_component__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../work-session-nav/work-session-nav.component */ 76774); /* harmony import */ var _work_session_work_session_import_service__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../work-session/work-session-import.service */ 50784); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ root: "gap-1.5 px-3.5 py-1.5" }); const _c1 = () => ({ root: "h-9 w-9 p-0" }); function TopNavigationComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "p-button", 21); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵlistener"]("click", function TopNavigationComponent_Conditional_10_Template_p_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r3); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); const navMenu_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreference"](32); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](navMenu_r4.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](3, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](4, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](2, 2, "topNavigation.navMenu.workSession"), " "); } } function TopNavigationComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-work-session-nav", 13); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); const workSessionUid_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreadContextLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("activeWorkSessionUid", workSessionUid_r5); } } function TopNavigationComponent_ng_template_17_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-icon", 22); } } function TopNavigationComponent_ng_template_21_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-icon", 23); } } function TopNavigationComponent_ng_template_25_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-icon", 24); } } function TopNavigationComponent_ng_template_29_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-menu-item", 25); } if (rf & 2) { const item_r7 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("item", item_r7); } } function TopNavigationComponent_ng_template_33_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-menu-item", 25); } if (rf & 2) { const item_r8 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("item", item_r8); } } function TopNavigationComponent_ng_template_37_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "lib-menu-item", 25); } if (rf & 2) { const item_r9 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("item", item_r9); } } // TODO: restore after the Montreal Imaging Symposium. const SHOW_ANALYSIS_FILE_IO = false; const LIFE_BY_SEVERITY = { error: 5000, info: 3000, success: 3000, warn: 4000 }; class TopNavigationComponent { authService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.AuthService); workSessionNavService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.WorkSessionNavigationService); dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_17__.DialogService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_14__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_13__.TranslateService); workSessionImportService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_work_session_work_session_import_service__WEBPACK_IMPORTED_MODULE_24__.WorkSessionImportService); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_5__.Router); db = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.DicomDatabaseService); preferences = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.PreferencesService); recentWorkSessions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.RecentWorkSessionsService); recentSessions = this.recentWorkSessions.sessions; constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.effect)(() => { const parameters = this.childParams(); const storeUid = parameters.get('storeUid'); const studyUid = parameters.get('studyUid'); const seriesUid = parameters.get('seriesUid'); const workSessionUid = parameters.get('workSessionUid'); if (!storeUid || !studyUid || !seriesUid || !workSessionUid) return; if (workSessionUid === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_21__.WORK_SESSION_NEW_KEY) return; this.recentWorkSessions.record({ seriesUid, storeUid, studyUid, workSessionUid }); }); } currentLang = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)((0,rxjs__WEBPACK_IMPORTED_MODULE_6__.merge)(this.translate.onLangChange, this.translate.onTranslationChange), { initialValue: undefined }); childParams = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)(this.router.events.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.filter)(event => event instanceof _angular_router__WEBPACK_IMPORTED_MODULE_5__.NavigationEnd), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(() => { let route = this.router.routerState.root; while (route.firstChild) { route = route.firstChild; } return route.snapshot.paramMap; })), { initialValue: (() => { let route = this.router.routerState.root; while (route.firstChild) { route = route.firstChild; } return route.snapshot?.paramMap ?? (0,_angular_router__WEBPACK_IMPORTED_MODULE_5__.convertToParamMap)({}); })() }); seriesFullyCached = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toObservable)(this.childParams).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(parameters => ({ seriesUid: parameters.get('seriesUid'), storeUid: parameters.get('storeUid') })), (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.switchMap)(({ seriesUid, storeUid }) => seriesUid && storeUid ? this.db.streamSeriesCacheProgress(seriesUid, storeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.isSeriesFullyCached), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.catchError)(() => (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.of)(false))) : (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.of)(false))), { initialValue: false }); currentUrl = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)(this.router.events.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.filter)(event => event instanceof _angular_router__WEBPACK_IMPORTED_MODULE_5__.NavigationEnd), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.map)(() => this.router.url)), { initialValue: this.router.url }); workspaceMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { this.currentLang(); const url = this.currentUrl(); const libraryClass = url.startsWith('/library') ? 'text-primary-400' : undefined; const analysesClass = url.startsWith('/analyses') ? 'text-primary-400' : undefined; return [{ command: () => this.router.navigate(['/library']), icon: 'images', iconClass: libraryClass, label: this.translate.instant('topNavigation.workspaceMenu.imagingLibrary'), labelClass: libraryClass }, { command: () => this.router.navigate(['/analyses']), icon: 'desktop', iconClass: analysesClass, label: this.translate.instant('topNavigation.workspaceMenu.liveAnalyses'), labelClass: analysesClass }]; }, ...(ngDevMode ? [{ debugName: "workspaceMenuItems" }] : [])); navMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { this.currentLang(); const hasWorkSession = !!this.childParams().get('workSessionUid'); return [...(SHOW_ANALYSIS_FILE_IO ? [{ command: () => this.workSessionImportService.import(), icon: 'folder-open', label: this.translate.instant('topNavigation.navMenu.openWorkSession') }] : []), { command: () => this.workSessionNavService.save(), disabled: !hasWorkSession, icon: 'save', label: this.translate.instant('topNavigation.navMenu.saveWorkSession') }, ...(SHOW_ANALYSIS_FILE_IO ? [{ command: () => this.workSessionNavService.export(), disabled: !hasWorkSession, icon: 'download', label: this.translate.instant('topNavigation.navMenu.exportWorkSession') }] : []), { command: () => this.openExportToDicomStore(), disabled: !this.childParams().get('seriesUid') || !this.seriesFullyCached(), icon: 'share', label: this.translate.instant('topNavigation.navMenu.archiveAsDicom') }]; }, ...(ngDevMode ? [{ debugName: "navMenuItems" }] : [])); userMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { var _this = this; this.currentLang(); return [{ command: function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // Sign-out wipes the local database; edits still in the autosave // debounce or an unfinished push would be lost without this. yield _this.workSessionNavService.flushPendingChanges(); yield _this.authService.logout(); _this.messageService.add({ life: 3000, severity: 'info', summary: _this.translate.instant('topNavigation.userMenu.signedOut') }); }); return function command() { return _ref.apply(this, arguments); }; }(), icon: 'sign-out', label: this.translate.instant('topNavigation.userMenu.signOut') }]; }, ...(ngDevMode ? [{ debugName: "userMenuItems" }] : [])); leafQueryParams() { let route = this.router.routerState.root; while (route.firstChild) route = route.firstChild; return route.snapshot.queryParamMap.get('otSeriesUid'); } openExportToDicomStore() { const seriesUid = this.childParams().get('seriesUid'); if (!seriesUid) return; const data = { defaultStoreUid: this.preferences.get().storeUid ?? this.childParams().get('storeUid') ?? undefined, existingOtSeriesUid: this.leafQueryParams() ?? undefined, seriesUids: [seriesUid], storeUid: this.childParams().get('storeUid') ?? undefined, studyUid: this.childParams().get('studyUid') ?? undefined, workSessionUid: this.childParams().get('workSessionUid') ?? undefined }; const reference = this.dialogService.open(_dicom_importer_components_export_to_store_dialog_export_to_store_dialog_component__WEBPACK_IMPORTED_MODULE_22__.ExportToStoreDialogComponent, { closable: true, data, header: this.translate.instant('topNavigation.navMenu.archiveAsDicom'), width: '28rem' }); reference?.onClose.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_12__.take)(1)).subscribe(outcome => { if (!outcome) return; this.messageService.add({ ...(outcome.detail ? { detail: outcome.detail } : {}), life: LIFE_BY_SEVERITY[outcome.severity], severity: outcome.severity, summary: this.translate.instant(outcome.messageKey) }); }); } static ɵfac = function TopNavigationComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TopNavigationComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵdefineComponent"]({ type: TopNavigationComponent, selectors: [["lib-top-navigation"]], features: [_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵProvidersFeature"]([_work_session_work_session_import_service__WEBPACK_IMPORTED_MODULE_24__.WorkSessionImportService])], decls: 39, vars: 35, consts: [["icon", ""], ["workspaceMenu", ""], ["item", ""], ["navMenu", ""], ["userMenu", ""], [1, "border-surface-800", "flex", "h-14", "shrink-0", "items-stretch", "gap-3", "border-b", "bg-(--p-app-chrome-app-header)", "pr-4", "pl-3", "text-sm", "select-none", 3, "aria-label"], [1, "flex", "shrink-0", "items-center", "gap-3"], ["data-test-id", "top-navigation-a-home-link", "href", "#", 1, "mx-2", "flex", "items-center", 3, "aria-label"], ["ngSrc", "assets/svg/logo.svg", "width", "36", "height", "36", "alt", "Logo", "priority", "", 1, "size-9"], ["data-test-id", "top-navigation-p-button-workspace", "outlined", "", "size", "small", "severity", "contrast", 3, "click", "pt"], ["icon", "angle-down", "iconClass", "text-muted-color text-xs"], ["data-test-id", "top-navigation-p-button-work-session-", "outlined", "", "size", "small", "severity", "contrast", 3, "pt"], [1, "flex", "min-w-0", "flex-1"], [1, "flex", "w-full", "min-w-0", 3, "activeWorkSessionUid"], [1, "flex", "shrink-0", "items-center", "gap-1"], ["data-test-id", "top-navigation-p-button-search", "text", "", "plain", "", "severity", "contrast", 3, "ariaLabel", "pt"], ["data-test-id", "top-navigation-p-button-notifications", "text", "", "plain", "", "severity", "contrast", 3, "ariaLabel", "pt"], ["data-test-id", "top-navigation-p-button-user-menu", "text", "", "plain", "", "severity", "contrast", 3, "onClick", "ariaLabel", "pt"], ["data-test-id", "top-navigation-p-menu-workspace", "popup", "", 3, "model"], ["data-test-id", "top-navigation-p-menu-navigation", "popup", "", 3, "model"], ["data-test-id", "top-navigation-p-menu-user", 3, "model", "popup"], ["data-test-id", "top-navigation-p-button-work-session-", "outlined", "", "size", "small", "severity", "contrast", 3, "click", "pt"], ["icon", "search", 1, "text-lg"], ["icon", "bell", 1, "text-lg"], ["icon", "user-circle", 1, "size-(--p-app-icon-size-md)"], [3, "item"]], template: function TopNavigationComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "nav", 5); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](2, "div", 6)(3, "a", 7); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](5, "img", 8); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](6, "p-button", 9); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵlistener"]("click", function TopNavigationComponent_Template_p_button_click_6_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const workspaceMenu_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreference"](28); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](workspaceMenu_r2.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtext"](7); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](8, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](9, "lib-icon", 10); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditionalCreate"](10, TopNavigationComponent_Conditional_10_Template, 4, 5, "p-button", 11); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](11, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵdeclareLet"](12); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditionalCreate"](13, TopNavigationComponent_Conditional_13_Template, 1, 1, "lib-work-session-nav", 13); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](14, "div", 14)(15, "p-button", 15); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](16, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](17, TopNavigationComponent_ng_template_17_Template, 1, 0, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](19, "p-button", 16); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](20, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](21, TopNavigationComponent_ng_template_21_Template, 1, 0, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](23, "p-button", 17); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](24, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵlistener"]("onClick", function TopNavigationComponent_Template_p_button_onClick_23_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); const userMenu_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreference"](36); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](userMenu_r6.toggle($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](25, TopNavigationComponent_ng_template_25_Template, 1, 0, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](27, "p-menu", 18, 1); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](29, TopNavigationComponent_ng_template_29_Template, 1, 1, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](31, "p-menu", 19, 3); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](33, TopNavigationComponent_ng_template_33_Template, 1, 1, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](35, "p-menu", 20, 4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](37, TopNavigationComponent_ng_template_37_Template, 1, 1, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵariaProperty"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵinterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](1, 18, "topNavigation.navMenu.homeAriaLabel"))); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵariaProperty"]("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵinterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](4, 20, "topNavigation.navMenu.homeLabel"))); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](31, _c0)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](8, 22, "topNavigation.navMenu.workspace"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditional"](ctx.childParams().get("seriesUid") ? 10 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵstoreLet"](ctx.childParams().get("workSessionUid") ?? undefined); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditional"](ctx.recentSessions().length > 0 ? 13 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](16, 25, "topNavigation.navMenu.searchAriaLabel"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](32, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](20, 27, "topNavigation.navMenu.notificationsAriaLabel"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](33, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](24, 29, "topNavigation.navMenu.userMenuAriaLabel"))("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](34, _c1)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("model", ctx.workspaceMenuItems()); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("model", ctx.navMenuItems()); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("model", ctx.userMenuItems())("popup", true); } }, dependencies: [primeng_avatar__WEBPACK_IMPORTED_MODULE_15__.AvatarModule, primeng_button__WEBPACK_IMPORTED_MODULE_16__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_16__.Button, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.IconComponent, primeng_menu__WEBPACK_IMPORTED_MODULE_18__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_18__.Menu, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_20__.MenuItemComponent, _work_session_nav_work_session_nav_component__WEBPACK_IMPORTED_MODULE_23__.WorkSessionNavComponent, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgOptimizedImage, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_13__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 12100 /*!*******************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-actors.service.ts ***! \*******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationActorsService: () => (/* binding */ AnnotationActorsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_post_process__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/post-process */ 16352); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../viewport-interaction/viewport-interaction.service */ 46184); /* harmony import */ var _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../window-details/window-details.service */ 99360); /* harmony import */ var _annotation_updaters_angle_updater__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./annotation-updaters/angle-updater */ 59985); /* harmony import */ var _annotation_updaters_distance_updater__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./annotation-updaters/distance-updater */ 44967); /* harmony import */ var _annotation_updaters_object3d_updater__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./annotation-updaters/object3d-updater */ 50980); /* harmony import */ var _annotation_updaters_point_updater__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./annotation-updaters/point-updater */ 4800); /* harmony import */ var _annotation_updaters_spline_updater__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./annotation-updaters/spline-updater */ 62781); /** * This service listens for updates from the `AnnotationFacade`, * and ensures each annotation has a corresponding `AnnotationUpdater` instance * which is called as relevant changes are made. * * It also keeps references to active viewports so that renders can be triggered * on relevant updates. */ class AnnotationActorsService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.AnnotationFacade); interactionModeService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_9__.InteractionModeService); engine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.RenderingEngineService); renderSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.renderSettingsStore); viewportStoreInstance = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.viewportStore); object3DGeometryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.Object3DGeometryFacade); viewports = []; latestFadeCameras = {}; updaterLookup = new Map(); clippingRangeOverrides = new Map(); mouseWorldPosition = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_10__.ViewportInteractionService).mouseWorldPosition; hoveredAnnotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_10__.ViewportInteractionService).hoveredAnnotation; dragDetails = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_10__.ViewportInteractionService).dragDetails; devicePixelRatio = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_window_details_window_details_service__WEBPACK_IMPORTED_MODULE_11__.WindowDetailsService).devicePixelRatio; annotationSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { return this.annotationFacade.annotationSize() / this.devicePixelRatio(); }, ...(ngDevMode ? [{ debugName: "annotationSize" }] : [])); // Include the annotation currently being created so we can render it, // but not include it in the proper collection until it is complete. annotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const annotations = this.annotationFacade.annotations(); const beingCreated = this.annotationFacade.annotationBeingCreated(); if (beingCreated !== undefined) { return [...annotations, beingCreated]; } return annotations; }, ...(ngDevMode ? [{ debugName: "annotations" }] : [])); effectsReady = false; initEffects() { if (this.effectsReady) return; (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.assertInInjectionContext)(this.initEffects); // Handle changes to any annotations in the store const updateHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const annotations = this.annotations(); const usedIds = []; for (const annotation of annotations) { if (!annotation.hidden && (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_6__.isRenderable)(annotation)) { // Update Item here this.updateAnnotationActors(annotation); usedIds.push(annotation.id); } } this.cleanupEntries(usedIds); this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "updateHandler" }] : [])); // By moving this to a separate effect, we don't have to // update every item on each render unless the selection changes const selectHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const selectedAnnotations = this.annotationFacade.selectedAnnotations(); const interactionMode = this.interactionModeService.interactionMode(); for (const updater of this.updaterLookup.values()) { if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.ADD_POINTS && interactionMode.annotationId === updater.annotation.id) { updater.setInteractionState(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.ADDING_POINTS); } else if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.CREATE && interactionMode.annotation.id === updater.annotation.id) { updater.setInteractionState(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.BEING_CREATED); } else if (selectedAnnotations.includes(updater.annotation)) { updater.setInteractionState(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.SELECTED); } else { updater.setInteractionState(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.DESELECTED); } } // Tell the screen-space outline pass which Object3D annotations are // selected. The pass filters by `outlinable` flag on each actor. const outlineIds = new Set(); for (const annotation of selectedAnnotations) { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsObject3D)(annotation)) outlineIds.add(annotation.id); } for (const pass of this.engine.getPostProcessPassesById(_tomoverse_post_process__WEBPACK_IMPORTED_MODULE_5__.OUTLINE_PASS_ID)) { pass.setSelectedAnnotationIds(outlineIds); } // On the VOLUME_3D viewport, new control-point actors are created with // generic lighting values from applyAnnotationLighting. refreshLighting() // applies the lit material used for every VR preset without waiting for the // next zoom to trigger refreshForViewportScaleChange. this.refreshLighting(); this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "selectHandler" }] : [])); // Separate handler for mouse position change as well, because this happens // often and usually doesn't affect most annotations const mouseMoveHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const mousePosition = this.mouseWorldPosition(); const interactionMode = this.interactionModeService.interactionMode(); let activeAnnotationId; switch (interactionMode.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.ADD_POINTS: { activeAnnotationId = interactionMode.annotationId; break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.CREATE: { activeAnnotationId = interactionMode.annotation.id; break; } } for (const updater of this.updaterLookup.values()) { // Right now only annotations being created will use this if (updater.annotation.id === activeAnnotationId) { updater.setMouseWorldPosition(mousePosition); break; } } this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "mouseMoveHandler" }] : [])); // Though this iterates through everything, most updaters will // ignore the `setIsHovered` calls because the value won't change const hoverHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const hoverDetails = this.hoveredAnnotation(); const dragDetails = this.dragDetails(); for (const updater of this.updaterLookup.values()) { let isHovered = false; let pointIndex; // Drag takes precedence if (dragDetails.annotationId) { isHovered = dragDetails.annotationId === updater.annotation.id; pointIndex = dragDetails.pointIndex; } else { isHovered = hoverDetails?.annotationId === updater.annotation.id; pointIndex = hoverDetails?.pointIndex; } updater.setIsHovered(isHovered, pointIndex); } this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "hoverHandler" }] : [])); // Re-push fade uniforms to each updater whenever a viewport camera // changes. Source of truth is the viewport store rather than // viewport.getCamera() because the store is updated first and the // Cornerstone viewport catches up afterwards. const fadeCameraHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const cameras = this.viewportStoreInstance.viewportCameras(); const byViewportId = {}; for (const [axisState, details] of Object.entries(cameras)) { byViewportId[axisState] = { focalPoint: details.focalPoint, position: details.position, viewPlaneNormal: details.viewPlaneNormal }; } this.latestFadeCameras = byViewportId; for (const updater of this.updaterLookup.values()) { updater.refreshFade(byViewportId); } this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "fadeCameraHandler" }] : [])); const annotationSizeHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const annotationSize = this.annotationSize(); for (const updater of this.updaterLookup.values()) { updater.setAnnotationSize(annotationSize); } this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "annotationSizeHandler" }] : [])); //Without this, switching ENDO <-> X-ray leaves the 3d object's lighting // state stale until the next signal that re-runs the annotations effect. const lightingPresetHandler = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.effect)(() => { const projectionMode = (0,_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.isProjectionPreset)(this.renderSettings.volumeSettings().selectedPreset); for (const updater of this.updaterLookup.values()) { updater.setProjectionMode(projectionMode); } this.refreshLighting(); this.renderViewports(); }, ...(ngDevMode ? [{ debugName: "lightingPresetHandler" }] : [])); // Destroy effects, otherwise this service can't be garbage collected (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(() => { updateHandler.destroy(); selectHandler.destroy(); mouseMoveHandler.destroy(); hoverHandler.destroy(); // Unsubscribe camera observers installed by `syncClippingRangeOverrides`. for (const restore of this.clippingRangeOverrides.values()) restore(); this.clippingRangeOverrides.clear(); fadeCameraHandler.destroy(); annotationSizeHandler.destroy(); lightingPresetHandler.destroy(); }); this.effectsReady = true; } setViewports(viewports) { const removedViewports = this.viewports.filter(vp => !viewports.includes(vp)); this.viewports = viewports; for (const updater of this.updaterLookup.values()) { updater.setViewports(viewports); } // Tear down overlay renderers for viewports that are no longer active. // Updaters already removed their actors in the setViewports call above. for (const viewport of removedViewports) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.detachAnnotationOverlay)(viewport); } // Cornerstone re-tiles its offscreen canvas whenever the active viewport // set changes, so every remaining overlay needs its sub-rect re-synced. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.resyncAnnotationOverlayViewports)(viewports); this.syncClippingRangeOverrides(); this.renderViewports(); } refreshForViewportScaleChange() { for (const updater of this.updaterLookup.values()) { updater.setViewports(this.viewports); } this.refreshLighting(); this.renderViewports(); } refreshLighting() { const renderMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.untracked)(() => this.renderSettings.volumeSettings().selectedPreset); for (const viewport of this.viewports) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.applyAnnotationActorLighting)(viewport.id, viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.ViewportType.VOLUME_3D ? renderMode : undefined); } } /** * Pins a wide [-9999, 9999] clipping range on each VolumeViewport3D camera * whenever an Object3D annotation is tracked. Object3D actors are excluded * from scene bounds, so Cornerstone's auto-computed near/far would z-clip * geometry extending past the volume. Hooks `Modified()` directly because * Cornerstone suppresses the DOM CAMERA_MODIFIED event. */ syncClippingRangeOverrides() { const currentIds = new Set(this.viewports.map(viewport => viewport.id)); for (const [id, restore] of this.clippingRangeOverrides) { if (!currentIds.has(id)) { restore(); this.clippingRangeOverrides.delete(id); } } for (const viewport of this.viewports) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.ViewportType.VOLUME_3D) continue; if (this.clippingRangeOverrides.has(viewport.id)) continue; const camera = viewport.getRenderer().getActiveCamera(); let pinning = false; const subscription = camera.onModified(() => { // Guard against our own `setClippingRange` re-triggering Modified(). if (pinning) return; if (!this.hasObject3DUpdater()) return; const [near, far] = camera.getClippingRange(); if (near === -9999 && far === 9999) return; pinning = true; try { camera.setClippingRange(-9999, 9999); } finally { pinning = false; } }); this.clippingRangeOverrides.set(viewport.id, () => subscription.unsubscribe()); } } renderViewports() { this.viewports = this.viewports.filter(engine => !engine.isDisabled); this.engine.renderAll(); } hasObject3DUpdater() { for (const updater of this.updaterLookup.values()) { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsObject3D)(updater.annotation)) return true; } return false; } updateAnnotationActors(annotation) { const updater = this.updaterLookup.get(annotation.id); if (updater === undefined) { const newUpdater = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.untracked)(() => this.createUpdater(annotation)); if (newUpdater) { newUpdater.refreshFade(this.latestFadeCameras); newUpdater.setProjectionMode((0,_tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.isProjectionPreset)((0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.untracked)(() => this.renderSettings.volumeSettings().selectedPreset))); this.updaterLookup.set(annotation.id, newUpdater); } } else { updater.update(annotation); } } createUpdater(annotation) { // If an annotation is currently being created, it is also considered selected // for display purposes. const interactionState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.untracked)(() => { const selectedAnnotations = this.annotationFacade.selectedAnnotations(); const interactionMode = this.interactionModeService.interactionMode(); if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.ADD_POINTS && interactionMode.annotationId === annotation.id) { return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.ADDING_POINTS; } if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.InteractionModeType.CREATE && interactionMode.annotation.id === annotation.id) { return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.BEING_CREATED; } if (selectedAnnotations.includes(annotation)) { return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.SELECTED; } return _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationInteractionState.DESELECTED; }); switch (annotation.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.ANGLE: { return new _annotation_updaters_angle_updater__WEBPACK_IMPORTED_MODULE_12__.AngleUpdater(annotation, this.viewports, interactionState, this.annotationSize()); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.CLOSED_SPLINE: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.OPEN_SPLINE: { return new _annotation_updaters_spline_updater__WEBPACK_IMPORTED_MODULE_16__.SplineUpdater(annotation, this.viewports, interactionState, this.annotationSize()); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.CYLINDER: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.HOLLOW_CYLINDER: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.STL: { return this.createObject3DUpdater(annotation, interactionState); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.DISTANCE: { return new _annotation_updaters_distance_updater__WEBPACK_IMPORTED_MODULE_13__.DistanceUpdater(annotation, this.viewports, interactionState, this.annotationSize()); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_4__.AnnotationSourceType.POINT: { return new _annotation_updaters_point_updater__WEBPACK_IMPORTED_MODULE_15__.PointUpdater(annotation, this.viewports, interactionState, this.annotationSize()); } default: { return; } } } createObject3DUpdater(annotation, interactionState) { if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsObject3D)(annotation)) return; const geometry = this.object3DGeometryFacade.getGeometry(annotation.id); if (!geometry) return; return new _annotation_updaters_object3d_updater__WEBPACK_IMPORTED_MODULE_14__.Object3DUpdater(annotation, this.viewports, interactionState, geometry, this.annotationSize()); } cleanupEntries(idsToKeep) { for (const key of this.updaterLookup.keys()) { if (!idsToKeep.includes(key)) { this.updaterLookup.get(key)?.cleanup(); this.updaterLookup.delete(key); } } } static ɵfac = function AnnotationActorsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnnotationActorsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: AnnotationActorsService, factory: AnnotationActorsService.ɵfac }); } /***/ }, /***/ 75939 /*!****************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-fade-shader.ts ***! \****************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CAMERA_DEC_TOKEN: () => (/* binding */ CAMERA_DEC_TOKEN), /* harmony export */ LIGHT_IMPL_TOKEN: () => (/* binding */ LIGHT_IMPL_TOKEN), /* harmony export */ POSITION_VC_DEC_TOKEN: () => (/* binding */ POSITION_VC_DEC_TOKEN), /* harmony export */ POSITION_VC_IMPL_TOKEN: () => (/* binding */ POSITION_VC_IMPL_TOKEN), /* harmony export */ applyAnnotationFade: () => (/* binding */ applyAnnotationFade), /* harmony export */ applyFadeShader: () => (/* binding */ applyFadeShader) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _shaders_annotation_fade_decl_frag_glsl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/annotation-fade-decl.frag.glsl */ 68105); /* harmony import */ var _shaders_annotation_fade_decl_vert_glsl__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/annotation-fade-decl.vert.glsl */ 22926); /* harmony import */ var _shaders_annotation_fade_impl_frag_glsl__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./shaders/annotation-fade-impl.frag.glsl */ 50927); /* harmony import */ var _shaders_annotation_fade_impl_vert_glsl__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./shaders/annotation-fade-impl.vert.glsl */ 6504); const ANNOTATION_FADE_FEATURE = 'annotation-fade'; // vtk template placeholders we splice into. Each must match a token vtk.js // emits in its shipped vtkPolyDataVS / vtkPolyDataFS shaders byte-for-byte // or the corresponding String.replace silently no-ops. Exported so a test // can verify they still appear in vtk.js's shipped poly-data shaders. const CAMERA_DEC_TOKEN = '//VTK::Camera::Dec'; const POSITION_VC_IMPL_TOKEN = '//VTK::PositionVC::Impl'; const POSITION_VC_DEC_TOKEN = '//VTK::PositionVC::Dec'; const LIGHT_IMPL_TOKEN = '//VTK::Light::Impl'; const parametersByMapper = new WeakMap(); const REPLACEMENTS = [(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vertexReplacement)(CAMERA_DEC_TOKEN, [CAMERA_DEC_TOKEN, _shaders_annotation_fade_decl_vert_glsl__WEBPACK_IMPORTED_MODULE_3__["default"]].join('\n'), { replaceFirst: true }), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vertexReplacement)(POSITION_VC_IMPL_TOKEN, [POSITION_VC_IMPL_TOKEN, _shaders_annotation_fade_impl_vert_glsl__WEBPACK_IMPORTED_MODULE_5__["default"]].join('\n'), { replaceFirst: true }), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.fragmentReplacement)(POSITION_VC_DEC_TOKEN, [POSITION_VC_DEC_TOKEN, _shaders_annotation_fade_decl_frag_glsl__WEBPACK_IMPORTED_MODULE_2__["default"]].join('\n'), { replaceFirst: true }), // Pre-replace on //VTK::Light::Impl, the token vtk.js expands into the // gl_FragData[0] = ... write. By inserting the token back at the start // of our replacement, vtk.js still substitutes its color-write code // first; our heatmap override then runs after and overwrites the color. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.fragmentReplacement)(LIGHT_IMPL_TOKEN, [LIGHT_IMPL_TOKEN, _shaders_annotation_fade_impl_frag_glsl__WEBPACK_IMPORTED_MODULE_4__["default"]].join('\n'), { replaceFirst: true }), // POST dedup (replaceFirst: false runs after replaceShaderValues). // When lastLightComplexity > 0, vtk.js also emits `uniform mat4 MCVCMatrix;` // via //VTK::Camera::Dec, producing a duplicate alongside our own // declaration above. This removes it. Not testable against the shipped // shader source — this anchor only exists post-substitution. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.vertexReplacement)('uniform mat4 MCVCMatrix;\nuniform mat4 MCVCMatrix;', 'uniform mat4 MCVCMatrix;', { replaceAll: true })]; /** * Convenience wrapper that resolves `FadeShaderParameters` from a viewport's * fade camera and the updater's selection state, then forwards to * `applyFadeShader`. No-op on non-ORTHOGRAPHIC viewports — the shader install * only makes sense on MPR (see comment on `applyFadeShader` above). */ function applyAnnotationFade(viewport, mapper, camera, selected) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportType.ORTHOGRAPHIC) return; if (!camera) { applyFadeShader(mapper, { cameraToPlaneDistance: 0, enabled: false, selected, visibleDistance: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.ANNOTATION_VISIBLE_DISTANCE_MM }); return; } const [px, py, pz] = camera.position; const [fx, fy, fz] = camera.focalPoint; applyFadeShader(mapper, { cameraToPlaneDistance: Math.hypot(fx - px, fy - py, fz - pz), enabled: true, selected, visibleDistance: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.ANNOTATION_VISIBLE_DISTANCE_MM }); } function applyFadeShader(mapper, parameters) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.setShaderReplacement)(mapper, ANNOTATION_FADE_FEATURE, REPLACEMENTS); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.setShaderCallback)(mapper, ANNOTATION_FADE_FEATURE, { callback: (_userData, cellBO) => { const current = parametersByMapper.get(mapper); if (!current) return; const program = cellBO.getProgram(); if (program.isUniformUsed('uFadeEnabled')) { program.setUniformi('uFadeEnabled', current.enabled ? 1 : 0); } if (program.isUniformUsed('uFadeVisibleDistance')) { program.setUniformf('uFadeVisibleDistance', current.visibleDistance); } if (program.isUniformUsed('uFadeSelectedAlpha')) { program.setUniformf('uFadeSelectedAlpha', _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.ANNOTATION_SELECTED_OUT_OF_PLANE_ALPHA); } if (program.isUniformUsed('uFadeCameraToPlaneDistance')) { program.setUniformf('uFadeCameraToPlaneDistance', current.cameraToPlaneDistance); } if (program.isUniformUsed('uFadeSelected')) { program.setUniformi('uFadeSelected', current.selected ? 1 : 0); } }, userData: undefined }); parametersByMapper.set(mapper, parameters); } /***/ }, /***/ 59985 /*!***************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/angle-updater.ts ***! \***************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AngleUpdater: () => (/* binding */ AngleUpdater) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Filters/General/TubeFilter */ 21362); /* harmony import */ var _kitware_vtk_js_Filters_Sources_ArcSource__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Filters/Sources/ArcSource */ 80371); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./get-point-scale-for-viewport */ 51847); /* harmony import */ var _multi_point_updater__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./multi-point-updater */ 67792); class AngleUpdater extends _multi_point_updater__WEBPACK_IMPORTED_MODULE_6__.MultiPointUpdater { additionalActorList(additional) { if (!additional) return {}; const out = {}; if (additional.arc) out['arc'] = additional.arc.actor; return out; } additionalGhostList(additional) { if (!additional?.arc?.ghostActor) return {}; return { 'arc:ghost': additional.arc.ghostActor }; } refreshFadeForViewport(viewport, collection) { super.refreshFadeForViewport(viewport, collection); const arc = collection.additional?.arc; if (arc) { this.applyFadeToPolyLine(viewport, arc.mapper); } } updateAdditional(viewport, collection) { if (!collection.additional) { collection.additional = {}; } const { additional } = collection; this.syncArc(viewport, additional); } // If we don't interpolate the lines, the tubeFilter starts // looking wonky on some tighter angles. // If there are any performance issues, we can probably use a // lighter interpolation method as we don't have to handle any curves. getPolyLinePoints() { const [a, b, c] = this.current.points; const points = []; if (a && b) { points.push(...(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.calculateSplinePath)([a, b], false)); } if (b && c) { points.push(...(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.calculateSplinePath)([b, c], false).splice(1)); } return points; } syncArc(viewport, additional) { const [a, b, c] = this.current.points; if (a && b && c) { if (additional.arc) { this.updateArc(viewport, additional.arc, a, b, c); } else { additional.arc = this.createArc(viewport, [a, b, c]); } } else { if (additional.arc) { this.detachLineGhost(viewport, additional.arc, `${this.current.id}:arc:ghost`); this.deleteActor(viewport, additional.arc.actor, `${this.current.id}:arc`); additional.arc = undefined; } } } updateArc(viewport, arcDetails, a, b, c) { const { filter, mapper, source } = arcDetails; const { center, point1, point2 } = this.calculateArc(a, b, c); filter.setRadius((0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_5__.getPointScaleForViewport)(viewport, this.annotationSize)); source.setPoint1([...point1]); source.setPoint2([...point2]); source.setCenter([...center]); this.applyFadeToPolyLine(viewport, mapper); } createArc(viewport, controlPoints) { const [a, b, c] = controlPoints; const { center, point1, point2 } = this.calculateArc(a, b, c); const source = _kitware_vtk_js_Filters_Sources_ArcSource__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ center: [...center], point1: [...point1], point2: [...point2], resolution: 32 }); const filter = _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ capping: true, numberOfSides: 32, radius: (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_5__.getPointScaleForViewport)(viewport, this.annotationSize), sidesShareVertices: false }); filter.setInputConnection(source.getOutputPort()); const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(filter); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationActor)(viewport, `${this.current.id}:arc`, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); // Set custom property for easy lookup on actor clicks, etc actor.set({ annotationId: this.current.id }, true); filter.update(); mapper.getBounds(); this.applyFadeToPolyLine(viewport, mapper); const arc = { actor, filter, mapper, source }; this.attachLineGhost(viewport, arc, `${this.current.id}:arc:ghost`); return arc; } calculateArc(a, b, c) { const length1 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.distance(a, b); const length2 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.distance(c, b); const point1 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); const point2 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); if (length2 > length1) { gl_matrix__WEBPACK_IMPORTED_MODULE_3__.lerp(point1, b, a, 0.3); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.lerp(point2, b, c, 0.3); } else { gl_matrix__WEBPACK_IMPORTED_MODULE_3__.lerp(point1, b, c, 0.3); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.lerp(point2, b, a, 0.3); } return { center: b, point1: point1, point2: point2 }; } } /***/ }, /***/ 55127 /*!***********************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/constants.ts ***! \***********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CREATED_POINT_SCALE: () => (/* binding */ CREATED_POINT_SCALE), /* harmony export */ DEFAULT_ANNOTATION_RADIUS: () => (/* binding */ DEFAULT_ANNOTATION_RADIUS), /* harmony export */ GHOST_OPACITY: () => (/* binding */ GHOST_OPACITY), /* harmony export */ HOVERED_POINT_SCALE: () => (/* binding */ HOVERED_POINT_SCALE) /* harmony export */ }); const CREATED_POINT_SCALE = 1.5; const HOVERED_POINT_SCALE = 1.5; const DEFAULT_ANNOTATION_RADIUS = 2; const GHOST_OPACITY = 0.4; /***/ }, /***/ 44967 /*!******************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/distance-updater.ts ***! \******************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ DistanceUpdater: () => (/* binding */ DistanceUpdater) /* harmony export */ }); /* harmony import */ var _multi_point_updater__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./multi-point-updater */ 67792); class DistanceUpdater extends _multi_point_updater__WEBPACK_IMPORTED_MODULE_0__.MultiPointUpdater {} /***/ }, /***/ 51847 /*!******************************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/get-point-scale-for-viewport.ts ***! \******************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ getPointScaleForViewport: () => (/* binding */ getPointScaleForViewport) /* harmony export */ }); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants */ 55127); const getPointScaleForViewport = (viewport, radiusPx = _constants__WEBPACK_IMPORTED_MODULE_0__.DEFAULT_ANNOTATION_RADIUS) => { if (!viewport) { return 1; } const renderer = viewport.getRenderer(); const camera = renderer.getActiveCamera(); const canvasHeight = viewport.canvas?.clientHeight ?? 1; return radiusPx * (2 * camera.getParallelScale() / canvasHeight) * globalThis.devicePixelRatio; }; /***/ }, /***/ 67792 /*!*********************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/multi-point-updater.ts ***! \*********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MultiPointUpdater: () => (/* binding */ MultiPointUpdater) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Filters/General/TubeFilter */ 21362); /* harmony import */ var _kitware_vtk_js_Filters_Sources_SphereSource__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Filters/Sources/SphereSource */ 52284); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _vtk_poly_line_source__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../vtk-poly-line-source */ 48333); /* harmony import */ var _annotation_fade_shader__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../annotation-fade-shader */ 75939); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./constants */ 55127); /* harmony import */ var _get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./get-point-scale-for-viewport */ 51847); // We can share the same source for all control points, because // only actor-specific properties change. // The actual line between points will have to be annotation-specific. const POINT_SOURCE = _kitware_vtk_js_Filters_Sources_SphereSource__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ phiResolution: 25, radius: 2, thetaResolution: 25 }); class MultiPointUpdater { current; viewports; interactionState; _annotationSize; static pointSource = POINT_SOURCE; actorLookup = new Map(); fadeCameras = {}; projectionMode = false; mouseWorldPosition = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.position)(0, 0, 0); hidesPrimary(viewport) { return this.projectionMode && viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportType.VOLUME_3D; } ghostOpacity() { return this.projectionMode ? 1 : _constants__WEBPACK_IMPORTED_MODULE_7__.GHOST_OPACITY; } get isSelected() { return [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.AnnotationInteractionState.ADDING_POINTS, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.AnnotationInteractionState.BEING_CREATED, _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.AnnotationInteractionState.SELECTED].includes(this.interactionState); } // Override where necessary showPoint(index) { return true; } // Override where necessary pointIsPickable(index) { return true; } get isBeingCreated() { return this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.AnnotationInteractionState.BEING_CREATED; } get isAddingPoints() { return this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.AnnotationInteractionState.ADDING_POINTS; } _isHovered = false; get isHovered() { return this._isHovered; } _hoveredPointIndex; get hoveredPointIndex() { return this._hoveredPointIndex; } get annotationSize() { return this._annotationSize; } constructor(current, viewports, interactionState, _annotationSize) { this.current = current; this.viewports = viewports; this.interactionState = interactionState; this._annotationSize = _annotationSize; this.updateActors(); } setMouseWorldPosition(mouseWorldPosition) { if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.positionsEqual)(this.mouseWorldPosition, mouseWorldPosition)) { this.mouseWorldPosition = mouseWorldPosition; this.updateActors(); } } get annotation() { return this.current; } update(annotation) { if (annotation !== this.current && annotation.type === this.current.type) { this.current = annotation; this.updateActors(); } } setAnnotationSize(annotationSize) { if (annotationSize !== this._annotationSize) { this._annotationSize = annotationSize; this.updateActors(); } } setInteractionState(interactionState) { if (interactionState !== this.interactionState) { this.interactionState = interactionState; this.updateActors(); } } setProjectionMode(projectionMode) { if (projectionMode !== this.projectionMode) { this.projectionMode = projectionMode; this.updateActors(); } } setIsHovered(isHovered, pointIndex) { if (isHovered !== this._isHovered || pointIndex !== this._hoveredPointIndex) { this._isHovered = isHovered; this._hoveredPointIndex = isHovered ? pointIndex : undefined; this.updateActors(); } } setViewports(viewports) { // Remove actors for any unregistered viewport const removals = this.viewports.filter(vp => !viewports.includes(vp)); for (const viewport of removals) { this.removeActorsForViewport(viewport); } // Otherwise, add or update any viewports as necessary this.viewports = viewports; this.updateActors(); } cleanup() { // Destroy all actors and remove from viewports for (const viewport of this.viewports) { this.removeActorsForViewport(viewport); } } refreshFade(camerasByViewportId) { this.fadeCameras = camerasByViewportId; for (const viewport of this.viewports) { const collection = this.actorLookup.get(viewport.id); if (!collection) continue; this.refreshFadeForViewport(viewport, collection); } } refreshFadeForViewport(viewport, collection) { this.applyFadeToPolyLine(viewport, collection.polyLine.mapper); for (const [index, actor] of collection.controlPoints.entries()) { const point = this.current.points[index]; if (!point) continue; actor.setVisibility(this.isPointInBand(viewport, point) && this.showPoint(index) && !this.hidesPrimary(viewport)); } } /** * Hard on/off for point-shaped actors (control points, single points, * preview point). Points are discarded out-of-band rather than faded. */ isPointInBand(viewport, worldPoint) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportType.ORTHOGRAPHIC) return true; const camera = this.fadeCameras[viewport.id]; if (!camera) return true; return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationPointInBand)(worldPoint, camera.focalPoint, camera.viewPlaneNormal); } applyFadeToPolyLine(viewport, mapper) { (0,_annotation_fade_shader__WEBPACK_IMPORTED_MODULE_6__.applyAnnotationFade)(viewport, mapper, this.fadeCameras[viewport.id], this.isSelected); } updateActors() { // Update the state of each actor as necessary for (const viewport of this.viewports) { const collection = this.actorCollectionForViewport(viewport); this.updateActorCollection(viewport, collection); } } actorCollectionForViewport(viewport) { const existing = this.actorLookup.get(viewport.id); if (existing) { return existing; } const collection = { controlPoints: [], polyLine: this.initPolyLine(viewport) }; if (viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportType.VOLUME_3D) { collection.ghostPolyLine = this.initGhostPolyLine(viewport, collection.polyLine); collection.controlPointGhosts = []; } for (const [index, point] of this.current.points.entries()) { collection.controlPoints.push(this.createControlPoint(viewport, index, point)); if (collection.controlPointGhosts) { collection.controlPointGhosts.push(this.createControlPointGhost(viewport, index, point)); } } this.actorLookup.set(viewport.id, collection); return collection; } attachLineGhost(viewport, line, ghostUid) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.ViewportType.VOLUME_3D) return; const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(line.filter); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); actor.getProperty().setOpacity(this.ghostOpacity()); actor.set({ annotationId: this.current.id }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationGhostActor)(viewport, ghostUid, actor); line.ghostActor = actor; line.ghostMapper = mapper; } additionalGhostList(_additional) { return {}; } detachLineGhost(viewport, line, ghostUid) { if (!line.ghostActor) return; (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.removeAnnotationGhostActor)(viewport, ghostUid); line.ghostActor.delete(); line.ghostMapper?.delete(); line.ghostActor = undefined; line.ghostMapper = undefined; } initGhostPolyLine(viewport, primary) { const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(primary.filter); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); actor.getProperty().setOpacity(this.ghostOpacity()); actor.setVisibility(this.projectionMode || this.isSelected); actor.set({ annotationId: this.current.id }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationGhostActor)(viewport, `${this.current.id}:polyLine:ghost`, actor); return actor; } initPolyLine(viewport) { const source = _vtk_poly_line_source__WEBPACK_IMPORTED_MODULE_5__["default"].newInstance({ points: this.getPolyLinePoints() }); const filter = _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ capping: true, numberOfSides: 32, radius: (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this._annotationSize) }); filter.setInputConnection(source.getOutputPort()); const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(filter); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationActor)(viewport, `${this.current.id}:polyLine`, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); // Set custom property for easy lookup on actor clicks, etc actor.set({ annotationId: this.current.id }, true); filter.update(); mapper.getBounds(); this.applyFadeToPolyLine(viewport, mapper); return { actor, filter, mapper, source }; } updatePolyLine(details, viewport) { details.source.setPoints(this.getPolyLinePoints()); details.filter.setRadius((0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this._annotationSize)); this.applyFadeToPolyLine(viewport, details.mapper); } getPolyLinePoints() { return this.current.points; } createControlPoint(viewport, index, position) { const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(POINT_SOURCE); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.setPosition(...position); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationActor)(viewport, `${this.current.id}:${index}`, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); // Set custom property for easy lookup on actor clicks, etc actor.set({ annotationId: this.current.id, pointIndex: index }, true); const scale = this.getScaleForPoint(viewport, index); actor.setScale(scale, scale, scale); actor.setVisibility(this.isPointInBand(viewport, position) && !this.hidesPrimary(viewport) && this.showPoint(index)); actor.setPickable(this.pointIsPickable(index)); return actor; } createControlPointGhost(viewport, index, position) { const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.annotationMapper)(POINT_SOURCE); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.setPosition(...position); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.applyAnnotationLighting)(actor, viewport); actor.getProperty().setOpacity(this.ghostOpacity()); actor.set({ annotationId: this.current.id, pointIndex: index }, true); const scale = this.getScaleForPoint(viewport, index); actor.setScale(scale, scale, scale); actor.setPickable(this.pointIsPickable(index)); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.addAnnotationGhostActor)(viewport, `${this.current.id}:${index}:ghost`, actor); return actor; } deleteControlPointGhost(viewport, ghost) { const { annotationId, pointIndex } = ghost.get('annotationId', 'pointIndex'); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.removeAnnotationGhostActor)(viewport, `${annotationId}:${pointIndex}:ghost`); const mapper = ghost.getMapper(); ghost.delete(); mapper?.delete(); } removeActorsForViewport(viewport) { const actorCollection = this.actorLookup.get(viewport.id); if (!actorCollection) return; this.actorLookup.delete(viewport.id); if (viewport.isDisabled) return; for (const actor of actorCollection.controlPoints) { this.deleteActor(viewport, actor); } if (actorCollection.controlPointGhosts) { for (const ghost of actorCollection.controlPointGhosts) { this.deleteControlPointGhost(viewport, ghost); } } if (actorCollection.additional) { const additionalActors = this.additionalActorList(actorCollection.additional); for (const [id, actor] of Object.entries(additionalActors)) { this.deleteActor(viewport, actor, `${this.current.id}:${id}`); } const additionalGhosts = this.additionalGhostList(actorCollection.additional); for (const [id, ghost] of Object.entries(additionalGhosts)) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.removeAnnotationGhostActor)(viewport, `${this.current.id}:${id}`); const mapper = ghost.getMapper(); ghost.delete(); mapper?.delete(); } } if (actorCollection.ghostPolyLine) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.removeAnnotationGhostActor)(viewport, `${this.current.id}:polyLine:ghost`); const ghostMapper = actorCollection.ghostPolyLine.getMapper(); actorCollection.ghostPolyLine.delete(); ghostMapper?.delete(); } this.deleteActor(viewport, actorCollection.polyLine.actor, `${this.current.id}:polyLine`); actorCollection.polyLine.filter.delete(); actorCollection.polyLine.mapper.delete(); actorCollection.polyLine.source.delete(); } updateActorCollection(viewport, collection) { if (this.isSelected) { this.updateActorCollectionSelected(viewport, collection); } else { this.updateActorCollectionDeselected(viewport, collection); } collection.polyLine.actor.setVisibility(!this.hidesPrimary(viewport)); const toUpdate = [...collection.controlPoints, collection.polyLine.actor, ...this.syncOverlayGhosts(collection)]; const { b, g, r } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.parseHexColor)(this.current.color) ?? { b: 0, g: 0, r: 0 }; for (const actor of toUpdate) { actor.getProperty().setColor(r / 255, g / 255, b / 255); } } /** Syncs overlay ghost opacity/visibility, then returns every actor still needing a colour refresh. */ syncOverlayGhosts(collection) { const toUpdate = []; const ghostVisible = this.projectionMode || this.isSelected; if (collection.additional) { const additionalPrimaries = this.additionalActorList(collection.additional); const additionalGhosts = this.additionalGhostList(collection.additional); for (const [key, actor] of Object.entries(additionalPrimaries)) { // Skip preview-only primaries (no ghost twin) so they stay visible during creation. if (`${key}:ghost` in additionalGhosts) actor.setVisibility(!this.projectionMode); toUpdate.push(actor); } for (const ghost of Object.values(additionalGhosts)) { ghost.getProperty().setOpacity(this.ghostOpacity()); ghost.setVisibility(ghostVisible); toUpdate.push(ghost); } } if (collection.ghostPolyLine) { collection.ghostPolyLine.getProperty().setOpacity(this.ghostOpacity()); collection.ghostPolyLine.setVisibility(ghostVisible); toUpdate.push(collection.ghostPolyLine); } if (collection.controlPointGhosts) { for (const ghost of collection.controlPointGhosts) { ghost.getProperty().setOpacity(this.ghostOpacity()); } toUpdate.push(...collection.controlPointGhosts); } return toUpdate; } updateActorCollectionSelected(viewport, collection) { const points = this.current.points; for (const [index, point] of points.entries()) { this.updatePoint(collection, index, viewport, point); } while (collection.controlPoints.length > points.length) { const removed = collection.controlPoints.pop(); if (removed) this.deleteActor(viewport, removed); const removedGhost = collection.controlPointGhosts?.pop(); if (removedGhost) this.deleteControlPointGhost(viewport, removedGhost); } this.updatePolyLine(collection.polyLine, viewport); this.updateAdditional(viewport, collection); } updateActorCollectionDeselected(viewport, collection) { // No control points when annotation isn't selected this.removeControlPoints(viewport, collection); this.updatePolyLine(collection.polyLine, viewport); this.updateAdditional(viewport, collection); } updatePoint(collection, index, viewport, position) { const actor = collection.controlPoints[index]; const scale = this.getScaleForPoint(viewport, index); const visible = this.isPointInBand(viewport, position) && this.showPoint(index); if (actor) { actor.setPosition(...position); actor.setScale(scale, scale, scale); actor.setVisibility(visible && !this.hidesPrimary(viewport)); actor.setPickable(this.pointIsPickable(index)); } else { collection.controlPoints[index] = this.createControlPoint(viewport, index, position); } if (!collection.controlPointGhosts) return; const ghost = collection.controlPointGhosts[index]; if (ghost) { ghost.setPosition(...position); ghost.setScale(scale, scale, scale); ghost.setVisibility(visible); ghost.setPickable(this.pointIsPickable(index)); } else { collection.controlPointGhosts[index] = this.createControlPointGhost(viewport, index, position); } } removeControlPoints(viewport, collection) { for (const actor of collection.controlPoints) { this.deleteActor(viewport, actor); } collection.controlPoints = []; if (collection.controlPointGhosts) { for (const ghost of collection.controlPointGhosts) { this.deleteControlPointGhost(viewport, ghost); } collection.controlPointGhosts = []; } } deleteActor(viewport, actor, id) { const { annotationId, pointIndex } = actor.get('annotationId', 'pointIndex'); const uid = id ?? (pointIndex === undefined ? annotationId : `${annotationId}:${pointIndex}`); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.removeAnnotationActor)(viewport, uid); actor.delete(); } updateAdditional(viewport, collection) { // Override where needed } additionalActorList(additional) { // Override where needed return {}; } getScaleForPoint(viewport, index) { const baseScale = (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this._annotationSize); return this.hoveredPointIndex === index ? baseScale * _constants__WEBPACK_IMPORTED_MODULE_7__.HOVERED_POINT_SCALE : baseScale; } } /***/ }, /***/ 24309 /*!**********************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/object3d-shell-debug.ts ***! \**********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Object3DShellDebug: () => (/* binding */ Object3DShellDebug) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/PolyData */ 95765); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Mapper__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Mapper */ 55857); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils */ 49585); // Debug-only! Renders the convex-hull picking shell as a translucent wireframe // next to the visible mesh. Lets us see the picking proxy directly in the // viewport. // Toggle via: // localStorage.setItem('__TVCT_DEBUG__', JSON.stringify({ showShell: true })); // location.reload(); const SHELL_DEBUG_RGB = [1, 0.5, 0]; const SHELL_DEBUG_OPACITY = 0.25; const SHELL_REPRESENTATION_WIREFRAME = 1; /** Per-annotation debug overlay; one wireframe actor per viewport. */ class Object3DShellDebug { annotationId; registryKey; shell; polyData; actors = new Map(); constructor(annotationId, registryKey, shell) { this.annotationId = annotationId; this.registryKey = registryKey; this.shell = shell; } syncTo(viewports, userMatrix) { for (const viewport of viewports) { this.actorFor(viewport)?.setUserMatrix(userMatrix); } } removeFor(viewport) { const actor = this.actors.get(viewport.id); if (!actor) return; this.actors.delete(viewport.id); if (!viewport.isDisabled) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.removeAnnotationActor)(viewport, this.registryKey); actor.delete(); } cleanup(viewports) { for (const viewport of viewports) this.removeFor(viewport); } actorFor(viewport) { const existing = this.actors.get(viewport.id); if (existing) return existing; if (viewport.isDisabled) return undefined; const mapper = _kitware_vtk_js_Rendering_Core_Mapper__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance(); mapper.setInputData(this.getPolyData()); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ mapper }); actor.setUseBounds(false); // Hardware selector must ignore the wireframe; otherwise the cap-fan // edges intercept clicks meant for the bore. actor.setPickable(false); const property = actor.getProperty(); property.setColor(...SHELL_DEBUG_RGB); property.setOpacity(SHELL_DEBUG_OPACITY); property.setRepresentation(SHELL_REPRESENTATION_WIREFRAME); property.setBackfaceCulling(false); actor.set({ annotationId: this.annotationId, isDebugShell: true }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.addAnnotationActor)(viewport, this.registryKey, actor); this.actors.set(viewport.id, actor); return actor; } getPolyData() { if (this.polyData) return this.polyData; const polyData = _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance(); polyData.getPoints().setData(this.shell.vertices, 3); // VTK cell format: [count, i0, i1, i2, ...] per triangle. const triangleCount = this.shell.indices.length / 3; const cells = new Uint32Array(triangleCount * 4); for (let triangle = 0; triangle < triangleCount; triangle++) { const cellOffset = triangle * 4; const indexOffset = triangle * 3; cells[cellOffset] = 3; cells[cellOffset + 1] = this.shell.indices[indexOffset] ?? 0; cells[cellOffset + 2] = this.shell.indices[indexOffset + 1] ?? 0; cells[cellOffset + 3] = this.shell.indices[indexOffset + 2] ?? 0; } polyData.getPolys().setData(cells); this.polyData = polyData; return polyData; } } /***/ }, /***/ 50980 /*!******************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/object3d-updater.ts ***! \******************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Object3DUpdater: () => (/* binding */ Object3DUpdater) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Common/Core/DataArray */ 40928); /* harmony import */ var _kitware_vtk_js_Common_DataModel_Plane__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/Plane */ 68497); /* harmony import */ var _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/PolyData */ 95765); /* harmony import */ var _kitware_vtk_js_Filters_Core_Cutter__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @kitware/vtk.js/Filters/Core/Cutter */ 24712); /* harmony import */ var _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @kitware/vtk.js/Filters/General/TubeFilter */ 21362); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Mapper__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Mapper */ 55857); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! gl-matrix */ 95329); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./constants */ 55127); /* harmony import */ var _get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./get-point-scale-for-viewport */ 51847); /* harmony import */ var _object3d_shell_debug__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./object3d-shell-debug */ 24309); // Cutter outline tube radius, as a fraction of the global annotation size. // Derived the same way spline/measurement tubes get their thickness // (`getPointScaleForViewport`) so it stays a constant screen size across zoom. const CUTTER_RADIUS_FRACTION = 0.75; const CUTTER_TUBE_SIDES = 3; // Opacity of the surface mesh on MPR while selected. Lower than the VR ghost // (`GHOST_OPACITY`) so the cutter cross-section reads clearly through it. const MPR_SELECTED_MESH_OPACITY = 0.25; // Re-cutting a mesh on every camera tick is an O(triangles) scan. Above this // cell count (typically full anatomical segmentation STLs) it stalls // interaction, so the MPR cuts are hidden instead. Lifting the cap needs a // faster cut path. // // TODO The issue should be resolved in a separate spike: https://tomoverse.atlassian.net/browse/TVC-868 const MAX_LIVE_CUT_CELLS = 100_000; /** * Renders Object3D annotations (Cylinder, Hollow Cylinder, STL) in VTK viewports. * * Geometry is read from `Object3DGeometryStore` by annotation id, so callers * must seed the store before `addAnnotation`. This keeps all subtypes on one * pipeline and keeps the DTO small (no mesh payloads on recolor/rename/rotate). * * Actors use `setUseBounds(false)` so they don't participate in scene bounds; * otherwise `resetCamera` would shift the focal point and misalign the volume * mapper's proximal/distal clipping planes. * * Rendering per viewport: * - MPR (orthographic): the slice-plane cross-section as a tube outline, * always visible; plus the full surface mesh at reduced opacity, shown only * while selected. The surface mesh does not use the in-plane fade shader. * - VR (3D): the full opaque surface mesh, plus a translucent ghost shown only * while selected. */ class Object3DUpdater { current; viewports; interactionState; geometry; annotationSize; actorLookup = new Map(); ghostLookup = new Map(); cutterLookup = new Map(); fadeCameras = {}; projectionMode = false; polyData; meshBounds; shellDebug; constructor(current, viewports, interactionState, geometry, annotationSize) { this.current = current; this.viewports = viewports; this.interactionState = interactionState; this.geometry = geometry; this.annotationSize = annotationSize; if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.getDebugFlagByName)('showShell') && this.geometry.shell) { this.shellDebug = new _object3d_shell_debug__WEBPACK_IMPORTED_MODULE_14__.Object3DShellDebug(this.current.id, `${this.actorKey}:shell`, this.geometry.shell); } this.updateActors(); } get isSelected() { return this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationInteractionState.BEING_CREATED || this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.AnnotationInteractionState.SELECTED; } get annotation() { return this.current; } update(annotation) { if (annotation !== this.current && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.annotationIsObject3D)(annotation)) { this.current = annotation; this.updateActors(); } } setAnnotationSize(annotationSize) { if (annotationSize === this.annotationSize) return; this.annotationSize = annotationSize; const userMatrix = this.userMatrix; for (const viewport of this.viewports) { const cutter = this.cutterLookup.get(viewport.id); if (cutter) this.updateCutter(viewport, cutter, userMatrix); } } refreshFade(camerasByViewportId) { this.fadeCameras = camerasByViewportId; const userMatrix = this.userMatrix; for (const viewport of this.viewports) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportType.ORTHOGRAPHIC) continue; const cutter = this.cutterLookup.get(viewport.id); if (cutter) this.updateCutter(viewport, cutter, userMatrix); } } setInteractionState(interactionState) { if (interactionState === this.interactionState) return; this.interactionState = interactionState; // The full surface mesh is only shown while selected — translucent on MPR // (the primary actor) and as the ghost on VR. The cutter outline is always // visible and unaffected. The screen-space selection outline is a separate // post-process pass keyed off the actor's `outlinable` flag, not this state. for (const viewport of this.viewports) { if (viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportType.ORTHOGRAPHIC) { this.actorLookup.get(viewport.id)?.setVisibility(this.isSelected); } this.ghostLookup.get(viewport.id)?.setVisibility(this.projectionMode || this.isSelected); } } setMouseWorldPosition(_mouseWorldPosition) { // Object3D annotations don't react to mouse position. } setProjectionMode(projectionMode) { if (projectionMode === this.projectionMode) return; this.projectionMode = projectionMode; this.applyProjectionState(); } applyProjectionState() { for (const viewport of this.viewports) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportType.VOLUME_3D) continue; this.actorLookup.get(viewport.id)?.setVisibility(!this.projectionMode); const ghost = this.ghostLookup.get(viewport.id); if (ghost) { ghost.getProperty().setOpacity(this.projectionMode ? 1 : _constants__WEBPACK_IMPORTED_MODULE_12__.GHOST_OPACITY); ghost.setVisibility(this.projectionMode || this.isSelected); } } } setIsHovered(_isHovered, _pointIndex) { // No hover visual for Object3D annotations. } setViewports(viewports) { const removals = this.viewports.filter(vp => !viewports.includes(vp)); for (const viewport of removals) { this.removeActorForViewport(viewport); } this.viewports = viewports; this.updateActors(); } cleanup() { for (const viewport of this.viewports) { this.removeActorForViewport(viewport); } } get actorKey() { return `${this.current.id}:${this.current.type}`; } /** Mesh→world transform shared by the surface, ghost, and cutter actors. */ get userMatrix() { return (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_10__.getObject3DTransformMatrix)(this.current); } /** True when the mesh is too large to re-cut live. */ get hideCuts() { return this.getPolyData().getPolys().getNumberOfCells() > MAX_LIVE_CUT_CELLS; } updateActors() { const userMatrix = this.userMatrix; for (const viewport of this.viewports) { this.updateActor(this.actorForViewport(viewport), userMatrix); const ghost = this.ghostLookup.get(viewport.id); if (ghost) this.updateActor(ghost, userMatrix); const cutter = this.cutterLookup.get(viewport.id); if (cutter) { this.updateActor(cutter.actor, userMatrix); // Actor transform moved → mesh-space cut plane needs re-deriving from // the latest world-space slice plane. this.updateCutter(viewport, cutter, userMatrix); } } this.shellDebug?.syncTo(this.viewports, userMatrix); } /** vtkActor wrapping the full surface mesh, shared setup for the primary and ghost actors. */ createMeshActor(viewport) { const mapper = _kitware_vtk_js_Rendering_Core_Mapper__WEBPACK_IMPORTED_MODULE_6__["default"].newInstance(); mapper.setInputData(this.getPolyData()); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_5__["default"].newInstance({ mapper }); actor.setUseBounds(false); actor.setUserMatrix(this.userMatrix); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.applyAnnotationLighting)(actor, viewport); return actor; } /** Cached vtkActor for the viewport, created on first access. * Lives on the annotation overlay renderer so it joins the hardware-selector pass. */ actorForViewport(viewport) { const existing = this.actorLookup.get(viewport.id); if (existing) return existing; const actor = this.createMeshActor(viewport); // `outlinable: true` opts this actor into the screen-space outline pass. actor.set({ annotationId: this.current.id, outlinable: true }, true); if (!viewport.isDisabled) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.addAnnotationActor)(viewport, this.actorKey, actor); if (viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportType.VOLUME_3D) { // Wide clipping range so geometry past the volume isn't z-clipped. viewport.getRenderer().getActiveCamera().setClippingRange(-9999, 9999); actor.setVisibility(!this.projectionMode); this.ghostLookup.set(viewport.id, this.createGhost(viewport)); } if (viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_9__.ViewportType.ORTHOGRAPHIC) { // On MPR the surface mesh is a translucent presence shown only while // selected; the cutter outline carries the slice cross-section. actor.getProperty().setOpacity(MPR_SELECTED_MESH_OPACITY); actor.setVisibility(this.isSelected); this.cutterLookup.set(viewport.id, this.createCutterActor(viewport)); } } this.actorLookup.set(viewport.id, actor); return actor; } createGhost(viewport) { const actor = this.createMeshActor(viewport); actor.getProperty().setOpacity(this.projectionMode ? 1 : _constants__WEBPACK_IMPORTED_MODULE_12__.GHOST_OPACITY); actor.setVisibility(this.projectionMode || this.isSelected); actor.set({ annotationId: this.current.id }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.addAnnotationGhostActor)(viewport, `${this.actorKey}:ghost`, actor); return actor; } /** * Renders the slice-plane × mesh intersection as a tube outline on MPR. * Without this, a cylinder oriented along the view vector has no geometry * *in* the slice plane — its side walls are perpendicular to the camera, so * the surface mesh alone shows nothing there. The cutter gives a precise * cross-section that's always present at the slice regardless of orientation. * * The cut polylines are tubed (rather than drawn as GL lines) so thickness is * reliable across GPUs and scales with the annotation size, matching how the * spline/measurement annotations render their lines. */ createCutterActor(viewport) { const plane = _kitware_vtk_js_Common_DataModel_Plane__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance(); const cutter = _kitware_vtk_js_Filters_Core_Cutter__WEBPACK_IMPORTED_MODULE_3__["default"].newInstance(); cutter.setInputData(this.getPolyData()); cutter.setCutFunction(plane); const tube = _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_4__["default"].newInstance({ capping: true, numberOfSides: CUTTER_TUBE_SIDES }); tube.setInputConnection(cutter.getOutputPort()); const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.annotationMapper)(tube); const userMatrix = this.userMatrix; const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_5__["default"].newInstance({ mapper }); actor.setUseBounds(false); actor.setUserMatrix(userMatrix); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.applyAnnotationLighting)(actor, viewport); // Hidden until we have a fade camera to derive the cut plane from. actor.setVisibility(false); actor.set({ annotationId: this.current.id }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.addAnnotationActor)(viewport, `${this.actorKey}:cutter`, actor); const record = { actor, cutter, mapper, plane, tube }; this.updateCutter(viewport, record, userMatrix); return record; } /** * Syncs the cutter to the viewport's current slice and zoom: the tube radius * (constant screen size) and the implicit cut plane. * * The cutter operates on the polyData in mesh-coord space, but the slice * plane is in world coords. Transforming the plane (origin + normal) into * mesh coords once is cheap; transforming every vertex of the mesh would * cost on every camera move. */ updateCutter(viewport, record, userMatrix) { if (this.hideCuts) { record.actor.setVisibility(false); return; } const camera = this.fadeCameras[viewport.id]; if (!camera) { record.actor.setVisibility(false); return; } const inv = gl_matrix__WEBPACK_IMPORTED_MODULE_7__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_7__.invert(inv, userMatrix); // Point (w=1): full affine, translation included. const [fx, fy, fz] = camera.focalPoint; const origin = [inv[0] * fx + inv[4] * fy + inv[8] * fz + inv[12], inv[1] * fx + inv[5] * fy + inv[9] * fz + inv[13], inv[2] * fx + inv[6] * fy + inv[10] * fz + inv[14]]; // Direction (w=0): rotation only. userMatrix is rigid (rotation + // translation, plus the STL axis-of-symmetry rotation), so the inverse // rotation applied to a normal preserves length within float precision. const [nx, ny, nz] = camera.viewPlaneNormal; const normal = [inv[0] * nx + inv[4] * ny + inv[8] * nz, inv[1] * nx + inv[5] * ny + inv[9] * nz, inv[2] * nx + inv[6] * ny + inv[10] * nz]; const magnitude = Math.hypot(...normal); if (magnitude > 0) { normal[0] /= magnitude; normal[1] /= magnitude; normal[2] /= magnitude; } // Broad-phase cull: if the mesh bounds sit entirely on one side of the // slice, the cross-section is empty. Hide the actor and leave the cut plane // untouched, so the cutter (an O(triangles) scan) doesn't re-execute for a // model that isn't on the current slice. if (!this.boundsStraddlePlane(origin, normal)) { record.actor.setVisibility(false); return; } record.actor.setVisibility(true); record.tube.setRadius((0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_13__.getPointScaleForViewport)(viewport, this.annotationSize * CUTTER_RADIUS_FRACTION)); record.plane.setOrigin(...origin); record.plane.setNormal(...normal); } /** Mesh-space axis-aligned bounds (center + half-extents), cached. */ getMeshBounds() { if (!this.meshBounds) { const [xMin, xMax, yMin, yMax, zMin, zMax] = this.getPolyData().getBounds(); this.meshBounds = { center: [(xMin + xMax) / 2, (yMin + yMax) / 2, (zMin + zMax) / 2], halfExtents: [(xMax - xMin) / 2, (yMax - yMin) / 2, (zMax - zMin) / 2] }; } return this.meshBounds; } /** * AABB-vs-plane test in mesh space: true when the bounding box crosses the * plane (so a cross-section exists). `normal` must be unit length. */ boundsStraddlePlane(origin, normal) { const { center, halfExtents } = this.getMeshBounds(); const centerDistance = normal[0] * (center[0] - origin[0]) + normal[1] * (center[1] - origin[1]) + normal[2] * (center[2] - origin[2]); const boxReach = halfExtents[0] * Math.abs(normal[0]) + halfExtents[1] * Math.abs(normal[1]) + halfExtents[2] * Math.abs(normal[2]); return Math.abs(centerDistance) <= boxReach; } getPolyData() { this.polyData ??= this.buildPolyData(); return this.polyData; } buildPolyData() { const polyData = _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance(); polyData.getPoints().setData(this.geometry.vertices, 3); const normals = _kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ name: 'Normals', numberOfComponents: 3, values: this.geometry.normals }); polyData.getPointData().setNormals(normals); if (this.geometry.indices.length > 0) { polyData.getPolys().setData(this.geometry.indices); } else { // Triangle soup: every 3 vertices form one triangle. // VTK cell format: [count, i0, i1, i2, ...] const triangleCount = this.geometry.vertices.length / 9; const cells = new Uint32Array(triangleCount * 4); for (let triangle = 0; triangle < triangleCount; triangle++) { const cellOffset = triangle * 4; const vertexOffset = triangle * 3; cells[cellOffset] = 3; cells[cellOffset + 1] = vertexOffset; cells[cellOffset + 2] = vertexOffset + 1; cells[cellOffset + 3] = vertexOffset + 2; } polyData.getPolys().setData(cells); } return polyData; } removeActorForViewport(viewport) { const actor = this.actorLookup.get(viewport.id); const ghost = this.ghostLookup.get(viewport.id); const cutter = this.cutterLookup.get(viewport.id); this.actorLookup.delete(viewport.id); this.ghostLookup.delete(viewport.id); this.cutterLookup.delete(viewport.id); // Actor/ghost/cutter live on the annotation overlay renderer; only the // renderer removal is skipped when the viewport is gone, but the VTK // objects are always freed to avoid leaking them on disable. if (actor) { if (!viewport.isDisabled) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.removeAnnotationActor)(viewport, this.actorKey); actor.delete(); } if (ghost) { if (!viewport.isDisabled) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.removeAnnotationGhostActor)(viewport, `${this.actorKey}:ghost`); const ghostMapper = ghost.getMapper(); ghost.delete(); ghostMapper?.delete(); } if (cutter) { if (!viewport.isDisabled) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.removeAnnotationActor)(viewport, `${this.actorKey}:cutter`); cutter.actor.delete(); cutter.mapper.delete(); cutter.tube.delete(); cutter.cutter.delete(); cutter.plane.delete(); } this.shellDebug?.removeFor(viewport); } updateActor(actor, userMatrix) { const { b, g, r } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_11__.parseHexColor)(this.current.color) ?? { b: 0, g: 0, r: 0 }; actor.getProperty().setColor(r / 255, g / 255, b / 255); actor.setUserMatrix(userMatrix); } } /***/ }, /***/ 4800 /*!***************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/point-updater.ts ***! \***************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PointUpdater: () => (/* binding */ PointUpdater), /* harmony export */ SOURCE: () => (/* binding */ SOURCE) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Filters_Sources_SphereSource__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Filters/Sources/SphereSource */ 52284); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./constants */ 55127); /* harmony import */ var _get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./get-point-scale-for-viewport */ 51847); function isPointInBand(viewport, camera, worldPoint) { if (viewport.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportType.ORTHOGRAPHIC) return true; if (!camera) return true; return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.annotationPointInBand)(worldPoint, camera.focalPoint, camera.viewPlaneNormal); } // We can share the same source for all points, because // only actor-specific properties change. // Other annotation types will likely need their own source/mapper per Updater instance. const SOURCE = _kitware_vtk_js_Filters_Sources_SphereSource__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ phiResolution: 25, radius: _constants__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_ANNOTATION_RADIUS, thetaResolution: 25 }); /** * Keeps a reference to a `Point` instance and any active viewports. * * When updates are received for the point's state or which viewports are active, * the `vtkActor` instance for each viewport is updated to match the * new point's state. */ class PointUpdater { current; viewports; interactionState; annotationSize; actorLookup = new Map(); ghostLookup = new Map(); fadeCameras = {}; projectionMode = false; hidesPrimary(viewport) { return this.projectionMode && viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportType.VOLUME_3D; } constructor(current, viewports, interactionState, annotationSize) { this.current = current; this.viewports = viewports; this.interactionState = interactionState; this.annotationSize = annotationSize; this.updateActors(); } isHovered = false; get isSelected() { return this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationInteractionState.BEING_CREATED || this.interactionState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationInteractionState.SELECTED; } get annotation() { return this.current; } update(annotation) { if (annotation !== this.current && annotation.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.POINT) { this.current = annotation; this.updateActors(); } } setAnnotationSize(annotationSize) { if (annotationSize !== this.annotationSize) { this.annotationSize = annotationSize; this.updateActors(); } } setInteractionState(interactionState) { if (interactionState !== this.interactionState) { this.interactionState = interactionState; this.updateActors(); } } setMouseWorldPosition(mouseWorldPosition) { // Individual points don't care about mouse position } setProjectionMode(projectionMode) { if (projectionMode !== this.projectionMode) { this.projectionMode = projectionMode; this.updateActors(); } } setViewports(viewports) { // Remove actors for any unregistered viewport const removals = this.viewports.filter(vp => !viewports.includes(vp)); for (const viewport of removals) { this.removeActorForViewport(viewport); } // Otherwise, add or update any viewports as necessary this.viewports = viewports; this.updateActors(); } setIsHovered(isHovered, pointIndex) { // Because this is a single-point, we don't care about pointIndex if (this.isHovered !== isHovered) { this.isHovered = isHovered; this.updateActors(); } } cleanup() { // Destroy all actors and remove from viewports for (const viewport of this.viewports) { this.removeActorForViewport(viewport); } } refreshFade(camerasByViewportId) { this.fadeCameras = camerasByViewportId; for (const [viewportId, actor] of this.actorLookup) { const viewport = this.viewports.find(vp => vp.id === viewportId); if (!viewport) continue; actor.setVisibility(isPointInBand(viewport, this.fadeCameras[viewport.id], this.current.position) && !this.hidesPrimary(viewport)); } } updateActors() { // Update the state of each actor as necessary for (const viewport of this.viewports) { const actor = this.actorForViewport(viewport); this.updateActor(actor, viewport); const visible = isPointInBand(viewport, this.fadeCameras[viewport.id], this.current.position); actor.setVisibility(visible && !this.hidesPrimary(viewport)); const ghost = this.ghostLookup.get(viewport.id); if (ghost) { this.updateActor(ghost, viewport); ghost.getProperty().setOpacity(this.projectionMode ? 1 : _constants__WEBPACK_IMPORTED_MODULE_4__.GHOST_OPACITY); ghost.setVisibility(visible && (this.projectionMode || this.isSelected)); } } } actorForViewport(viewport) { const existing = this.actorLookup.get(viewport.id); if (existing) { return existing; } const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.annotationMapper)(SOURCE); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ mapper }); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.addAnnotationActor)(viewport, this.current.id, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.applyAnnotationLighting)(actor, viewport); // `pointIndex: 0` matches the control-point convention so click // handlers can treat the Point sphere as its sole control point. actor.set({ annotationId: this.current.id, pointIndex: 0 }, true); this.actorLookup.set(viewport.id, actor); if (viewport.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportType.VOLUME_3D) { this.ghostLookup.set(viewport.id, this.createGhost(viewport)); } return actor; } createGhost(viewport) { const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.annotationMapper)(SOURCE); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ mapper }); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.applyAnnotationLighting)(actor, viewport); actor.getProperty().setOpacity(_constants__WEBPACK_IMPORTED_MODULE_4__.GHOST_OPACITY); actor.set({ annotationId: this.current.id, pointIndex: 0 }, true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.addAnnotationGhostActor)(viewport, `${this.current.id}:ghost`, actor); return actor; } removeActorForViewport(viewport) { const actor = this.actorLookup.get(viewport.id); if (!actor) return; this.actorLookup.delete(viewport.id); const ghost = this.ghostLookup.get(viewport.id); this.ghostLookup.delete(viewport.id); if (viewport.isDisabled) return; (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.removeAnnotationActor)(viewport, this.current.id); actor.delete(); if (ghost) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.removeAnnotationGhostActor)(viewport, `${this.current.id}:ghost`); const ghostMapper = ghost.getMapper(); ghost.delete(); ghostMapper?.delete(); } } updateActor(actor, viewport) { const { b, g, r } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.parseHexColor)(this.current.color) ?? { b: 0, g: 0, r: 0 }; actor.getProperty().setColor(r / 255, g / 255, b / 255); // Point annotations use the same enlarged scale whether hovered or // selected, so the two states don't stack and the point is always the // same size when either is active. const emphasisScale = this.isSelected || this.isHovered ? _constants__WEBPACK_IMPORTED_MODULE_4__.HOVERED_POINT_SCALE : 1; const scale = emphasisScale * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_5__.getPointScaleForViewport)(viewport, this.annotationSize); actor.setScale(scale, scale, scale); actor.setPosition(...this.current.position); } } /***/ }, /***/ 62781 /*!****************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/annotation-actors/annotation-updaters/spline-updater.ts ***! \****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SplineUpdater: () => (/* binding */ SplineUpdater) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Filters/General/TubeFilter */ 21362); /* harmony import */ var _kitware_vtk_js_Filters_Sources_LineSource__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Filters/Sources/LineSource */ 98671); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Actor */ 77251); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./constants */ 55127); /* harmony import */ var _get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./get-point-scale-for-viewport */ 51847); /* harmony import */ var _multi_point_updater__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./multi-point-updater */ 67792); const AXIS_MARKER_RADIUS = 0.8; class SplineUpdater extends _multi_point_updater__WEBPACK_IMPORTED_MODULE_9__.MultiPointUpdater { isClosed = false; get showPreview() { return this.isAddingPoints || this.isBeingCreated; } constructor(current, viewports, interactionState, annotationSize) { super(current, viewports, interactionState, annotationSize); this.isClosed = (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_4__.annotationIsClosedSpline)(current); } // Points are always shown (base class default) - only their interactivity changes // while being created, in pointIsPickable below. pointIsPickable(index) { if (index === 0 && this.isBeingCreated && this.isClosed) { return this.annotation.points.length > 2; } // Placed points are visible as they're created, but not yet draggable/clickable - // they only become interactive once the spline itself is finished. return !this.isBeingCreated; } refreshFadeForViewport(viewport, collection) { super.refreshFadeForViewport(viewport, collection); const axisMarker = collection.additional?.axisMarker; if (axisMarker) { this.applyFadeToPolyLine(viewport, axisMarker.mapper); } } additionalActorList(additional) { if (!additional) return {}; const out = {}; if (additional.axisMarker) out['axisMarker'] = additional.axisMarker.actor; if (additional.previewPoint) out['previewPoint'] = additional.previewPoint.actor; return out; } additionalGhostList(additional) { if (!additional?.axisMarker?.ghostActor) return {}; return { 'axisMarker:ghost': additional.axisMarker.ghostActor }; } updateAdditional(viewport, collection) { if (!collection.additional) { collection.additional = {}; } const { additional } = collection; if (this.showPreview && this.current.points.length > 0) { // Create / update the preview point this.syncPreviewPoint(viewport, additional); } else { // Clear preview this.clearPreviewPoint(viewport, additional); } if (this.isClosed) { if (this.isSelected && !this.isBeingCreated && this.current.points.length > 1) { this.syncAxisMarker(viewport, additional); } else { this.clearAxisMarker(viewport, additional); } const hoverScale = this.isClosed && this.hoveredPointIndex === 0 ? _constants__WEBPACK_IMPORTED_MODULE_7__.HOVERED_POINT_SCALE : 1; const scale = hoverScale * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this.annotationSize); collection.controlPoints[0]?.setScale(scale, scale, scale); } } getPolyLinePoints() { if (this.current.points.length === 0) { return []; } const endPoint = this.current.points.at(-1); if (this.isBeingCreated) { const points = [...this.current.points]; // Hovering the first point of a closed spline previews the completed loop // instead of a rubber-band segment out to the cursor - close over the existing // points rather than extending them with the mouse position. const closingPreview = this.isClosed && this.hoveredPointIndex === 0; if (!closingPreview && gl_matrix__WEBPACK_IMPORTED_MODULE_3__.dist(this.mouseWorldPosition, endPoint) > 1) { points.push(this.mouseWorldPosition); } return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.calculateSplinePath)(points, closingPreview); } return (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplinePath)(this.current); } syncPreviewPoint(viewport, additional) { // Don't show preview point when hovering over existing point in add points mode, // or when hovering over first point when creating closed spline const hoveringWhileAdding = this.isAddingPoints && this.hoveredPointIndex !== undefined; const closingSpline = this.isClosed && this.hoveredPointIndex === 0; if (additional.previewPoint && (hoveringWhileAdding || closingSpline)) { this.clearPreviewPoint(viewport, additional); return; } if (!additional.previewPoint) { additional.previewPoint = this.initPreviewPoint(viewport); } // In add point mode, we snap preview points to the spline let position = this.mouseWorldPosition; if (this.isAddingPoints && this.hoveredPointIndex === undefined) { position = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.snapPositionToSpline)(position, this.getPolyLinePoints()); } additional.previewPoint.actor.setPosition(...position); // Must match initPreviewPoint's formula - this overwrites that initial scale on every // sync (every mouse move), so omitting the viewport factor here previously left the // preview point's on-screen size tracking raw zoom instead of staying pixel-constant. const scale = (this.isAddingPoints ? 1 : 0.6) * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this.annotationSize); additional.previewPoint.actor.setScale(scale, scale, scale); } initPreviewPoint(viewport) { const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.annotationMapper)(SplineUpdater.pointSource); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.setPickable(false); actor.setPosition(...this.mouseWorldPosition); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.addAnnotationActor)(viewport, `${this.current.id}:previewPoint`, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.applyAnnotationLighting)(actor, viewport); const scale = 0.6 * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this.annotationSize); actor.setScale(scale, scale, scale); return { actor, mapper }; } clearPreviewPoint(viewport, additional) { const { previewPoint } = additional; if (previewPoint) { // Delete all actors etc this.deleteActor(viewport, previewPoint.actor, `${this.current.id}:previewPoint`); previewPoint.mapper.delete(); additional.previewPoint = undefined; } } getAxisMarkerPoints() { const centroid = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineCentroid)(this.current); const bestFitNormal = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplineBestFitNormal)(this.current); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.calculatePointsOnAxis)(centroid, bestFitNormal, 20); } initAxisMarker(viewport) { const [start, end] = this.getAxisMarkerPoints(); const source = _kitware_vtk_js_Filters_Sources_LineSource__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance({ point1: [...start], point2: [...end] }); const filter = _kitware_vtk_js_Filters_General_TubeFilter__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ capping: true, numberOfSides: 32, radius: AXIS_MARKER_RADIUS * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport) }); filter.addInputConnection(source.getOutputPort()); const mapper = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.annotationMapper)(filter); const actor = _kitware_vtk_js_Rendering_Core_Actor__WEBPACK_IMPORTED_MODULE_2__["default"].newInstance({ mapper }); actor.getProperty().setBackfaceCulling(true); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.addAnnotationActor)(viewport, `${this.current.id}:axisMarker`, actor); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_6__.applyAnnotationLighting)(actor, viewport); this.applyFadeToPolyLine(viewport, mapper); const line = { actor, filter, mapper, source }; this.attachLineGhost(viewport, line, `${this.current.id}:axisMarker:ghost`); return line; } syncAxisMarker(viewport, additional) { if (additional.axisMarker) { const [start, end] = this.getAxisMarkerPoints(); const { filter, mapper, source } = additional.axisMarker; filter.setRadius(AXIS_MARKER_RADIUS * (0,_get_point_scale_for_viewport__WEBPACK_IMPORTED_MODULE_8__.getPointScaleForViewport)(viewport, this.annotationSize)); source.setPoint1From([...start]); source.setPoint2From([...end]); source.modified(); this.applyFadeToPolyLine(viewport, mapper); } else { additional.axisMarker = this.initAxisMarker(viewport); } } clearAxisMarker(viewport, additional) { const { axisMarker } = additional; if (axisMarker) { this.detachLineGhost(viewport, axisMarker, `${this.current.id}:axisMarker:ghost`); // Delete all actors etc this.deleteActor(viewport, axisMarker.actor, `${this.current.id}:axisMarker`); axisMarker.mapper.delete(); additional.axisMarker = undefined; } } } /***/ }, /***/ 76045 /*!************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/camera-animation.service.ts ***! \************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CameraAnimationService: () => (/* binding */ CameraAnimationService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tweenjs_tween_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tweenjs/tween.js */ 31307); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! gl-matrix */ 23988); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** Duration of the camera transition, in milliseconds. */ const CAMERA_TRANSITION_MS = 500; /** * Drives the animated camera transition: it owns the tween, the * rAF loop and the slerp/lerp interpolation, and patches the viewport store each frame. */ class CameraAnimationService { viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore); tween; rafId; settle; /** * Animate the camera focal point to `position`, optionally facing `normal`. */ animateToPosition(position, normal, hooks) { this.cancel(); if (this.prefersReducedMotion()) { this.viewportStore.setCameraToPosition(position, normal); return; } const start = { intersection: this.viewportStore.intersection(), isocenter: this.viewportStore.isocenter(), matrix: gl_matrix__WEBPACK_IMPORTED_MODULE_2__.clone(this.viewportStore.matrix()) }; const target = this.viewportStore.cameraTargetForPosition(position, normal); // Already at the target: - skip the tween. if (gl_matrix__WEBPACK_IMPORTED_MODULE_3__.equals((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.positionToVec3)(start.intersection), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.positionToVec3)(target.intersection)) && gl_matrix__WEBPACK_IMPORTED_MODULE_3__.equals((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.positionToVec3)(start.isocenter), (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.positionToVec3)(target.isocenter)) && (!target.matrix || gl_matrix__WEBPACK_IMPORTED_MODULE_2__.equals(start.matrix, target.matrix))) { return; } hooks?.onStart?.(); this.settle = hooks?.onSettle; const progress = { t: 0 }; this.tween = new _tweenjs_tween_js__WEBPACK_IMPORTED_MODULE_1__.Tween(progress).to({ t: 1 }, CAMERA_TRANSITION_MS).easing(_tweenjs_tween_js__WEBPACK_IMPORTED_MODULE_1__.Easing.Cubic.InOut).onUpdate(() => this.viewportStore.setCameraState((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.cameraStateAtProgress)(start, target, progress.t))).start(); const tick = () => { const tween = this.tween; if (!tween) return; tween.update(); if (tween.isPlaying()) { this.rafId = requestAnimationFrame(tick); return; } // Snap to the canonical target so the final state matches the instant path. this.viewportStore.setCameraToPosition(position, normal); this.cancel(); }; this.rafId = requestAnimationFrame(tick); } /** Cancel any in-flight animation and run the pending settle hook once. */ cancel() { if (this.rafId !== undefined) { cancelAnimationFrame(this.rafId); this.rafId = undefined; } this.tween?.stop(); this.tween = undefined; const settle = this.settle; this.settle = undefined; settle?.(); } prefersReducedMotion() { return globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false; } static ɵfac = function CameraAnimationService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CameraAnimationService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: CameraAnimationService, factory: CameraAnimationService.ɵfac }); } /***/ }, /***/ 36896 /*!*******************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/build-cpr-actor.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ buildCprActor: () => (/* binding */ buildCprActor), /* harmony export */ updateCprCenterline: () => (/* binding */ updateCprCenterline) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Rendering_Core_ImageCPRMapper__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/ImageCPRMapper */ 96113); /* harmony import */ var _kitware_vtk_js_Rendering_Core_ImageSlice__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/ImageSlice */ 32745); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _spline_to_centerline__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./spline-to-centerline */ 46815); function buildCprActor(imageData, spline, rollRad = 0) { const centerline = (0,_spline_to_centerline__WEBPACK_IMPORTED_MODULE_3__.splineToCenterline)(spline, rollRad); const mapper = _kitware_vtk_js_Rendering_Core_ImageCPRMapper__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance(); mapper.setInputData(imageData, 0); mapper.setInputData(centerline.polyData, 1); mapper.setWidth(_cpr_config__WEBPACK_IMPORTED_MODULE_2__.CPR_WIDTH_MM); mapper.setOrientationArrayName(_spline_to_centerline__WEBPACK_IMPORTED_MODULE_3__.CPR_ORIENTATION_ARRAY_NAME); mapper.useStraightenedMode(); const actor = _kitware_vtk_js_Rendering_Core_ImageSlice__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance(); // vtkImageCPRMapper extends vtkAbstractMapper3D, not vtkAbstractImageMapper; // the runtime contract is compatible, the declared types don't match. actor.setMapper(mapper); return { actor, centerline, mapper }; } function updateCprCenterline(bundle, spline, rollRad = 0) { const centerline = (0,_spline_to_centerline__WEBPACK_IMPORTED_MODULE_3__.splineToCenterline)(spline, rollRad); bundle.mapper.setInputData(centerline.polyData, 1); bundle.centerline = centerline; return centerline; } /***/ }, /***/ 85367 /*!**********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/control-point-step.ts ***! \**********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ controlPointStepDelta: () => (/* binding */ controlPointStepDelta), /* harmony export */ normalizeCursorMm: () => (/* binding */ normalizeCursorMm) /* harmony export */ }); /** Pure arithmetic behind the ←/→ and a/d control-point stepping. */ /** Skips a control point the cursor is effectively already on. */ const STEP_EPSILON_MM = 0.5; /** * Undefined once an open spline is at its last control point. A closed spline's delta can * run past the seam — see `normalizeCursorMm`. */ function controlPointStepDelta(input) { const { closed, cursorMm, direction, distancesMm, totalLengthMm } = input; const sorted = distancesMm.toSorted((a, b) => a - b); // A closed cursor scrubbed to totalLength sits on the seam, which is 0: comparing from the // far end finds nothing ahead and wraps back onto the seam itself, so the key goes dead. const from = normalizeCursorMm(cursorMm, totalLengthMm, closed); const target = nextControlPointMm(sorted, from, direction, closed); if (target === undefined) return undefined; return sweepDelta(target - from, direction, closed ? totalLengthMm : undefined); } function nextControlPointMm(sorted, cursorMm, direction, closed) { const ahead = direction > 0 ? sorted.find(distance => distance > cursorMm + STEP_EPSILON_MM) : sorted.findLast(distance => distance < cursorMm - STEP_EPSILON_MM); if (ahead !== undefined) return ahead; if (!closed) return undefined; return direction > 0 ? sorted[0] : sorted.at(-1); } /** Force the sweep the way the key was pressed; an open arc has no way round to force. */ function sweepDelta(delta, direction, totalLengthMm) { if (totalLengthMm === undefined) return delta; if (direction > 0 && delta <= 0) return delta + totalLengthMm; if (direction < 0 && delta >= 0) return delta - totalLengthMm; return delta; } /** Closed arcs wrap at the seam; open ones stop at their ends. */ function normalizeCursorMm(distanceMm, totalLengthMm, closed) { if (!closed) return Math.max(0, Math.min(distanceMm, totalLengthMm)); if (totalLengthMm <= 0) return 0; return (distanceMm % totalLengthMm + totalLengthMm) % totalLengthMm; } /***/ }, /***/ 17924 /*!**************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-config.ts ***! \**************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CPR_CARRIER_VIEWPORT_IDS: () => (/* binding */ CPR_CARRIER_VIEWPORT_IDS), /* harmony export */ CPR_PANEL_BY_VIEWPORT_ID: () => (/* binding */ CPR_PANEL_BY_VIEWPORT_ID), /* harmony export */ CPR_REQUIRED_CARRIER_ROLES: () => (/* binding */ CPR_REQUIRED_CARRIER_ROLES), /* harmony export */ CPR_WIDTH_MM: () => (/* binding */ CPR_WIDTH_MM), /* harmony export */ CURSOR_GAP_MM: () => (/* binding */ CURSOR_GAP_MM), /* harmony export */ EDIT_NODE_FALLBACK_COLOR: () => (/* binding */ EDIT_NODE_FALLBACK_COLOR), /* harmony export */ EDIT_NODE_FILL_OPACITY: () => (/* binding */ EDIT_NODE_FILL_OPACITY), /* harmony export */ EDIT_NODE_HIT_RADIUS_PX: () => (/* binding */ EDIT_NODE_HIT_RADIUS_PX), /* harmony export */ EDIT_NODE_HOVER_RADIUS_PX: () => (/* binding */ EDIT_NODE_HOVER_RADIUS_PX), /* harmony export */ EDIT_NODE_NEAR_PLANE_MM: () => (/* binding */ EDIT_NODE_NEAR_PLANE_MM), /* harmony export */ EDIT_NODE_RADIUS_PX: () => (/* binding */ EDIT_NODE_RADIUS_PX), /* harmony export */ EDIT_NODE_STROKE_WIDTH_PX: () => (/* binding */ EDIT_NODE_STROKE_WIDTH_PX), /* harmony export */ LONG_AXIS_CAMERA_DISTANCE_MM: () => (/* binding */ LONG_AXIS_CAMERA_DISTANCE_MM), /* harmony export */ RIBBON_ZOOM_RATE_PER_DELTAY: () => (/* binding */ RIBBON_ZOOM_RATE_PER_DELTAY), /* harmony export */ ROTATE_DEG_PER_PX: () => (/* binding */ ROTATE_DEG_PER_PX), /* harmony export */ SHORT_AXIS_FOV_MM: () => (/* binding */ SHORT_AXIS_FOV_MM), /* harmony export */ SHORT_AXIS_INITIAL_POSITION_FRACTION: () => (/* binding */ SHORT_AXIS_INITIAL_POSITION_FRACTION), /* harmony export */ SHORT_AXIS_SCROLL_RATE_MM_PER_DELTAY: () => (/* binding */ SHORT_AXIS_SCROLL_RATE_MM_PER_DELTAY), /* harmony export */ isCprCarrierViewportId: () => (/* binding */ isCprCarrierViewportId) /* harmony export */ }); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../viewport-ids */ 85309); const CPR_CARRIER_VIEWPORT_IDS = { crossSection: 'cprShortAxis', longitudinal: 'cprLongitudinal', ribbonA: 'cprLongAxis', ribbonB: 'cprRibbonB' }; /** The roles a session enables today: one ribbon and the perpendicular cross-section. */ const CPR_REQUIRED_CARRIER_ROLES = ['ribbonA', 'crossSection']; const CARRIER_VIEWPORT_IDS = new Set(Object.values(CPR_CARRIER_VIEWPORT_IDS)); /** * Carriers are orchestrator-unregistered; call sites that walk every engine viewport must * skip them or their state bleeds through (annotation targeting, the global zoom effect). */ function isCprCarrierViewportId(id) { return CARRIER_VIEWPORT_IDS.has(id); } /** * The workspace panel each registered viewport occupies, for workspace-internal maximize. * Only the volume render is shown in the workspace; the three MPRs stay mounted but hidden, * so their own maximize buttons are unreachable and deliberately unmapped. */ const CPR_PANEL_BY_VIEWPORT_ID = { [_viewport_ids__WEBPACK_IMPORTED_MODULE_0__.VIEWPORT_IDS.REFORMAT]: 'reformat' }; /** Radial extent passed to `vtkImageCPRMapper.setWidth`, in millimetres. */ const CPR_WIDTH_MM = 60; /** Long-axis camera-back distance along the ribbon normal, in millimetres. */ const LONG_AXIS_CAMERA_DISTANCE_MM = 100; /** Central gap in the ribbon's cursor cross-bar, in millimetres, keeping the lumen visible. */ const CURSOR_GAP_MM = 16; /** Cut-plane rotation per pixel of radial background drag on the ribbon. */ const ROTATE_DEG_PER_PX = 0.5; /** Ribbon zoom factor per `WheelEvent.deltaY` unit while CTRL is held (or a trackpad pinch). */ const RIBBON_ZOOM_RATE_PER_DELTAY = 1 / 200; /** Short-axis field of view — the resliced output image extent, in millimetres. */ const SHORT_AXIS_FOV_MM = 120; /** Arc-length mm per `WheelEvent.deltaY` unit. */ const SHORT_AXIS_SCROLL_RATE_MM_PER_DELTAY = 1 / 100; /** Initial short-axis position as a fraction of total centerline length (0 = start). */ const SHORT_AXIS_INITIAL_POSITION_FRACTION = 0; /** How far off the cross-section plane a control point may sit and still get a handle, in mm. */ const EDIT_NODE_NEAR_PLANE_MM = 2; const EDIT_NODE_RADIUS_PX = 5; const EDIT_NODE_HOVER_RADIUS_PX = 7; const EDIT_NODE_HIT_RADIUS_PX = 10; const EDIT_NODE_FILL_OPACITY = 0.25; const EDIT_NODE_STROKE_WIDTH_PX = 1.5; const EDIT_NODE_FALLBACK_COLOR = 'var(--p-app-cpr-node-fallback)'; /***/ }, /***/ 72142 /*!***************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-cross-section-overlay.component.ts ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprCrossSectionOverlayComponent: () => (/* binding */ CprCrossSectionOverlayComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../window-details/window-details.service */ 99360); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _cpr_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./cpr.service */ 26144); /* harmony import */ var _cross_section_cut_line__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./cross-section-cut-line */ 3832); /* harmony import */ var _cross_section_nodes__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./cross-section-nodes */ 54776); /* harmony import */ var _ribbon_gestures__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./ribbon-gestures */ 61193); /** * SVG chrome and pointer surface over the cross-section carrier: the grabbable * cut-line indicator (where the ribbon's rotated plane cuts this slice) and the * wheel scrubbing the cursor along the vessel. Same substrate-free pattern as * the ribbon overlay; CTRL+right-drag W/L bubbles through to the panel. */ const _forTrack0 = ($index, $item) => $item.index; function CprCrossSectionOverlayComponent_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](1, "line", 3); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointerenter", function CprCrossSectionOverlayComponent_Conditional_1_For_2_Template_line_pointerenter_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hover.set(true)); })("pointerleave", function CprCrossSectionOverlayComponent_Conditional_1_For_2_Template_line_pointerleave_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hover.set(false)); })("pointerdown", function CprCrossSectionOverlayComponent_Conditional_1_For_2_Template_line_pointerdown_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.onCutLinePointerDown($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { const segment_r3 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("stroke", ctx_r1.CUT_LINE_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", segment_r3.x1)("y1", segment_r3.y1)("x2", segment_r3.x2)("y2", segment_r3.y2)("stroke-width", ctx_r1.strokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", segment_r3.x1)("y1", segment_r3.y1)("x2", segment_r3.x2)("y2", segment_r3.y2)("stroke-width", ctx_r1.CUT_LINE_HIT_WIDTH_PX); } } function CprCrossSectionOverlayComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 1); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterCreate"](1, CprCrossSectionOverlayComponent_Conditional_1_For_2_Template, 2, 12, null, null, _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterTrackByIndex"]); } if (rf & 2) { const line_r4 = ctx; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("stroke", ctx_r1.CUT_LINE_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", line_r4.gapFill.x1)("y1", line_r4.gapFill.y1)("x2", line_r4.gapFill.x2)("y2", line_r4.gapFill.y2)("stroke-width", ctx_r1.strokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeater"](line_r4.segments); } } function CprCrossSectionOverlayComponent_For_3_Template(rf, ctx) { if (rf & 1) { const _r5 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "circle", 4); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](1, "circle", 5); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointerenter", function CprCrossSectionOverlayComponent_For_3_Template_circle_pointerenter_1_listener() { const node_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hoveredNode.set(node_r6.index)); })("pointerleave", function CprCrossSectionOverlayComponent_For_3_Template_circle_pointerleave_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r5); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hoveredNode.set(undefined)); })("pointerdown", function CprCrossSectionOverlayComponent_For_3_Template_circle_pointerdown_1_listener($event) { const node_r6 = _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r5).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.onNodePointerDown($event, node_r6.index)); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { const node_r6 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("cx", node_r6.x)("cy", node_r6.y)("r", ctx_r1.nodeRadius(node_r6.index))("fill", ctx_r1.nodeColor())("fill-opacity", ctx_r1.EDIT_NODE_FILL_OPACITY)("stroke", ctx_r1.nodeColor())("stroke-width", ctx_r1.EDIT_NODE_STROKE_WIDTH_PX); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("cx", node_r6.x)("cy", node_r6.y)("r", ctx_r1.EDIT_NODE_HIT_RADIUS_PX); } } const CUT_LINE_COLOR = 'var(--p-app-cpr-cut-line)'; const CUT_LINE_HIT_WIDTH_PX = 16; class CprCrossSectionOverlayComponent { CUT_LINE_COLOR = CUT_LINE_COLOR; CUT_LINE_HIT_WIDTH_PX = CUT_LINE_HIT_WIDTH_PX; EDIT_NODE_HIT_RADIUS_PX = _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_HIT_RADIUS_PX; EDIT_NODE_FILL_OPACITY = _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_FILL_OPACITY; EDIT_NODE_STROKE_WIDTH_PX = _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_STROKE_WIDTH_PX; cprService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_cpr_service__WEBPACK_IMPORTED_MODULE_6__.CprService); session = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.cprSessionStore); host = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.ElementRef).nativeElement; box = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "box" }] : [])); hover = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "hover" }] : [])); dragging = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "dragging" }] : [])); drag; crosshairSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.viewportStore).crosshairSize; devicePixelRatio = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_window_details_window_details_service__WEBPACK_IMPORTED_MODULE_4__.WindowDetailsService).devicePixelRatio; strokeWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const base = this.crosshairSize() / this.devicePixelRatio(); return this.hover() || this.dragging() ? base * 2 : base; }, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : [])); hoveredNode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "hoveredNode" }] : [])); draggingNode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "draggingNode" }] : [])); dragPreviewPx = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "dragPreviewPx" }] : [])); dragWorld; nodeColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.cprService.activeSplineColor() ?? _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_FALLBACK_COLOR, ...(ngDevMode ? [{ debugName: "nodeColor" }] : [])); nodes = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { if (this.session.editState() !== 'editing') return []; this.cprService.shortAxisCameraVersion(); const plane = this.cprService.shortAxisPlane(); if (!plane) return []; const points = this.cprService.controlPoints(); const dragging = this.draggingNode(); const preview = this.dragPreviewPx(); return (0,_cross_section_nodes__WEBPACK_IMPORTED_MODULE_8__.nearPlaneNodeIndices)({ focalPoint: plane.focalPoint, grabbedIndex: dragging, normal: plane.normal, points, toleranceMm: _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_NEAR_PLANE_MM }).map(index => { const canvas = index === dragging && preview ? preview : this.cprService.worldToCanvas(points[index]); return canvas ? { index, x: canvas[0], y: canvas[1] } : undefined; }).filter(node => node !== undefined); }, ...(ngDevMode ? [{ debugName: "nodes" }] : [])); nodeRadius(index) { return this.hoveredNode() === index ? _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_HOVER_RADIUS_PX : _cpr_config__WEBPACK_IMPORTED_MODULE_5__.EDIT_NODE_RADIUS_PX; } cutLine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { // The framing doubles as the session-live gate: set at first ribbon framing, // cleared on teardown — no cut line over a dormant carrier. const box = this.box(); if (!this.cprService.ribbonFraming() || !box || box.height <= 0 || box.width <= 0) return; return (0,_cross_section_cut_line__WEBPACK_IMPORTED_MODULE_7__.cutLineGeometry)(box, this.session.rotationDeg()); }, ...(ngDevMode ? [{ debugName: "cutLine" }] : [])); constructor() { const observer = new ResizeObserver(() => { this.box.set({ height: this.host.clientHeight, width: this.host.clientWidth }); }); observer.observe(this.host); // Manual listener: wheel must be non-passive for preventDefault, which an // Angular binding cannot guarantee under a passive-events configuration. const onWheel = event => this.onWheel(event); this.host.addEventListener('wheel', onWheel, { passive: false }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(() => { observer.disconnect(); this.host.removeEventListener('wheel', onWheel); }); } onCutLinePointerDown(event) { if (event.button !== 0) return; const box = this.box(); if (!box) return; event.stopPropagation(); event.target.setPointerCapture?.(event.pointerId); const [x, y] = this.eventPosition(event); this.drag = { startPointerDeg: (0,_cross_section_cut_line__WEBPACK_IMPORTED_MODULE_7__.pointerAngleDeg)(box, x, y), startRotationDeg: this.session.rotationDeg() }; this.dragging.set(true); } onNodePointerDown(event, index) { if (event.button !== 0) return; event.stopPropagation(); event.target.setPointerCapture?.(event.pointerId); // Before the snap, so the grabbed node keeps its handle through the recompute. this.draggingNode.set(index); // Snap the plane onto the node, zeroing its residual off-plane error before it can move. const distanceMm = this.cprService.controlPointDistances()[index]; if (distanceMm !== undefined) this.cprService.jumpCursor(distanceMm); } onPointerMove(event) { if (this.draggingNode() !== undefined) { this.dragNode(event); return; } const drag = this.drag; const box = this.box(); if (!drag || !box) return; const [x, y] = this.eventPosition(event); const deltaDeg = (0,_cross_section_cut_line__WEBPACK_IMPORTED_MODULE_7__.pointerAngleDeg)(box, x, y) - drag.startPointerDeg; this.session.setRotationDeg(Math.round(drag.startRotationDeg + deltaDeg)); } onPointerUp(event) { const index = this.draggingNode(); if (index !== undefined) { const world = this.dragWorld; this.clearNodeDrag(event); // A press that never moved has nothing to commit. if (world) this.cprService.commitControlPointDrag(index, world); return; } this.clearCutLineDrag(event); } // A cancelled stream delivers no pointerup: a stale drag would keep rotating the cut line // with no button pressed, and a cancelled node drag must commit nothing. onPointerCancel(event) { if (this.draggingNode() !== undefined) { this.clearNodeDrag(event); return; } this.clearCutLineDrag(event); } // Previews in pixels and writes no `cursorMm`: the cursor effect never fires, so the plane // cannot chase the very handle it is derived from. dragNode(event) { const index = this.draggingNode(); const nodePosition = index === undefined ? undefined : this.cprService.controlPoints()[index]; const plane = this.cprService.shortAxisPlane(); const onPlane = this.cprService.canvasToWorld(this.eventPosition(event)); if (!nodePosition || !plane || !onPlane) return; this.dragWorld = (0,_cross_section_nodes__WEBPACK_IMPORTED_MODULE_8__.inPlaneDragTarget)({ nodePosition, normal: plane.normal, onPlane }); this.dragPreviewPx.set(this.cprService.worldToCanvas(this.dragWorld)); } clearNodeDrag(event) { (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_9__.releaseCapturedPointer)(event); this.draggingNode.set(undefined); this.dragPreviewPx.set(undefined); this.dragWorld = undefined; } clearCutLineDrag(event) { if (this.drag) (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_9__.releaseCapturedPointer)(event); this.drag = undefined; this.dragging.set(false); } onWheel(event) { if (!this.cprService.ribbonFraming()) return; // The whole surface scrolls, CTRL included — the carrier's old listener made // no modifier distinction and the cross-section has no zoom to give CTRL to. event.preventDefault(); // A scrub mid-drag would move the plane the drag is being measured against. if (this.draggingNode() !== undefined) return; const deltaY = (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_9__.normalizeWheelDeltaY)(event.deltaY, event.deltaMode); this.cprService.scrubCursor(deltaY * _cpr_config__WEBPACK_IMPORTED_MODULE_5__.SHORT_AXIS_SCROLL_RATE_MM_PER_DELTAY); } eventPosition(event) { const rect = this.host.getBoundingClientRect(); return [event.clientX - rect.left, event.clientY - rect.top]; } static ɵfac = function CprCrossSectionOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CprCrossSectionOverlayComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({ type: CprCrossSectionOverlayComponent, selectors: [["lib-cpr-cross-section-overlay"]], hostAttrs: [1, "absolute", "inset-0", "block"], decls: 4, vars: 1, consts: [[1, "h-full", "w-full", "select-none", 3, "pointermove", "pointerup", "pointercancel", "contextmenu"], ["opacity", "0.25", "pointer-events", "none"], ["data-cut-line", "", "pointer-events", "none"], ["data-cut-line-hit", "", "stroke", "transparent", "pointer-events", "stroke", 3, "pointerenter", "pointerleave", "pointerdown"], ["data-node-handle", "", "pointer-events", "none"], ["data-node-handle-hit", "", "fill", "transparent", "pointer-events", "all", 3, "pointerenter", "pointerleave", "pointerdown"]], template: function CprCrossSectionOverlayComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](0, "svg", 0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointermove", function CprCrossSectionOverlayComponent_Template_svg_pointermove_0_listener($event) { return ctx.onPointerMove($event); })("pointerup", function CprCrossSectionOverlayComponent_Template_svg_pointerup_0_listener($event) { return ctx.onPointerUp($event); })("pointercancel", function CprCrossSectionOverlayComponent_Template_svg_pointercancel_0_listener($event) { return ctx.onPointerCancel($event); })("contextmenu", function CprCrossSectionOverlayComponent_Template_svg_contextmenu_0_listener($event) { return $event.preventDefault(); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditionalCreate"](1, CprCrossSectionOverlayComponent_Conditional_1_Template, 3, 7); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterCreate"](2, CprCrossSectionOverlayComponent_For_3_Template, 2, 10, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { let tmp_0_0; _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditional"]((tmp_0_0 = ctx.cutLine()) ? 1 : -1, tmp_0_0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeater"](ctx.nodes()); } }, encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 3338 /*!******************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-image-data.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ buildCprImageData: () => (/* binding */ buildCprImageData) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Common/Core/DataArray */ 40928); /* harmony import */ var _kitware_vtk_js_Common_DataModel_ImageData__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/ImageData */ 56394); /** * A private `vtkImageData` for the CPR mapper: the shared volume's geometry with * scalars assembled once from Cornerstone's chunked `voxelManager`. Never hand the * mapper the shared imageData — mutating its `PointData` invalidates every other * viewport's cached volume texture and forces full re-uploads on entry. */ function buildCprImageData(shared) { const voxelManagerHolder = shared.get('voxelManager'); const voxelManager = voxelManagerHolder?.voxelManager; if (!voxelManager) { throw new Error('buildCprImageData: no voxelManager on imageData; ' + 'cannot assemble scalars for the CPR mapper.'); } const copy = _kitware_vtk_js_Common_DataModel_ImageData__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance(); copy.setDimensions(shared.getDimensions()); copy.setSpacing(shared.getSpacing()); copy.setOrigin(shared.getOrigin()); copy.setDirection(shared.getDirection()); copy.getPointData().setScalars(_kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ name: 'Scalars', numberOfComponents: voxelManager.numberOfComponents, values: voxelManager.getCompleteScalarDataArray() })); return copy; } /***/ }, /***/ 41326 /*!*******************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-resize-handle.directive.ts ***! \*******************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprResizeHandleDirective: () => (/* binding */ CprResizeHandleDirective) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 14975); /** Drag source for a workspace grid boundary: emits the px delta from where the drag started. */ /** One arrow-key press moves the boundary this far, as a tiny complete drag. */ const KEY_STEP_PX = 16; class CprResizeHandleDirective { axis = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required({ ...(ngDevMode ? { debugName: "axis" } : {}), alias: 'libCprResizeHandle' }); dragStarted = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); dragMoved = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); dragEnded = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.output)(); element = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_2__.ElementRef).nativeElement; origin = undefined; onKeyDown(event) { const direction = this.keyDirection(event.key); if (direction === undefined || this.origin !== undefined) return; event.preventDefault(); this.dragStarted.emit(); this.dragMoved.emit(direction * KEY_STEP_PX); this.dragEnded.emit(); } keyDirection(key) { if (this.axis() === 'x') { if (key === 'ArrowLeft') return -1; if (key === 'ArrowRight') return 1; } else { if (key === 'ArrowUp') return -1; if (key === 'ArrowDown') return 1; } return undefined; } onPointerDown(event) { event.preventDefault(); this.origin = this.coordinate(event); // Capture keeps the drag alive over the viewport canvases the handle sits between. this.element.setPointerCapture(event.pointerId); this.dragStarted.emit(); } onPointerMove(event) { if (this.origin === undefined) return; this.dragMoved.emit(this.coordinate(event) - this.origin); } onPointerUp(event) { if (this.origin === undefined) return; this.origin = undefined; this.element.releasePointerCapture(event.pointerId); this.dragEnded.emit(); } coordinate(event) { return this.axis() === 'x' ? event.clientX : event.clientY; } static ɵfac = function CprResizeHandleDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CprResizeHandleDirective)(); }; static ɵdir = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵdefineDirective"]({ type: CprResizeHandleDirective, selectors: [["", "libCprResizeHandle", ""]], hostAttrs: ["tabindex", "0"], hostBindings: function CprResizeHandleDirective_HostBindings(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵlistener"]("keydown", function CprResizeHandleDirective_keydown_HostBindingHandler($event) { return ctx.onKeyDown($event); })("pointercancel", function CprResizeHandleDirective_pointercancel_HostBindingHandler($event) { return ctx.onPointerUp($event); })("pointerdown", function CprResizeHandleDirective_pointerdown_HostBindingHandler($event) { return ctx.onPointerDown($event); })("pointermove", function CprResizeHandleDirective_pointermove_HostBindingHandler($event) { return ctx.onPointerMove($event); })("pointerup", function CprResizeHandleDirective_pointerup_HostBindingHandler($event) { return ctx.onPointerUp($event); }); } }, inputs: { axis: [1, "libCprResizeHandle", "axis"] }, outputs: { dragStarted: "dragStarted", dragMoved: "dragMoved", dragEnded: "dragEnded" } }); } /***/ }, /***/ 52158 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-ribbon-overlay.component.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprRibbonOverlayComponent: () => (/* binding */ CprRibbonOverlayComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 14975); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../window-details/window-details.service */ 99360); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _cpr_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./cpr.service */ 26144); /* harmony import */ var _long_axis_camera__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./long-axis-camera */ 51984); /* harmony import */ var _ribbon_cursor__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./ribbon-cursor */ 36955); /* harmony import */ var _ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./ribbon-gestures */ 61193); /* harmony import */ var _ribbon_projection__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./ribbon-projection */ 94212); /* harmony import */ var _ribbon_ruler__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./ribbon-ruler */ 15701); /** * SVG chrome and pointer surface over the ribbon carrier, projected through the * framing `CprService` publishes — never the camera. Owns every left-button and * wheel gesture on the ribbon; the panel's CTRL+right-drag W/L reaches its * handlers by bubbling. */ const _forTrack0 = ($index, $item) => $item.d + ($item.seam ? "-seam" : ""); const _forTrack1 = ($index, $item) => $item.index; function CprRibbonOverlayComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 1); } if (rf & 2) { const trace_r1 = ctx; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", trace_r1.x1)("y1", trace_r1.y1)("x2", trace_r1.x2)("y2", trace_r1.y2)("stroke", ctx_r1.nodeColor())("stroke-dasharray", ctx_r1.TRACE_DASH_ARRAY)("opacity", ctx_r1.TRACE_OPACITY); } } function CprRibbonOverlayComponent_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](0, "text", 4); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { const tick_r3 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"]().$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("fill", tick_r3.seam ? ctx_r1.SEAM_COLOR : ctx_r1.LABEL_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x", tick_r3.labelX)("y", tick_r3.labelY); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵtextInterpolate1"](" ", tick_r3.seam ? _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵpipeBind1"](2, 5, "planarReformation.seam") : tick_r3.label, " "); } } function CprRibbonOverlayComponent_For_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditionalCreate"](1, CprRibbonOverlayComponent_For_3_Conditional_1_Template, 3, 7, ":svg:text", 3); } if (rf & 2) { const tick_r3 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("stroke", tick_r3.seam ? ctx_r1.SEAM_COLOR : ctx_r1.TICK_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", tick_r3.x1)("y1", tick_r3.y1)("x2", tick_r3.x2)("y2", tick_r3.y2)("stroke-width", tick_r3.seam ? 2 : 1); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditional"](tick_r3.seam || tick_r3.label ? 1 : -1); } } function CprRibbonOverlayComponent_For_5_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "circle", 5); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](1, "circle", 6); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointerenter", function CprRibbonOverlayComponent_For_5_Template_circle_pointerenter_1_listener() { const marker_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hoveredNode.set(marker_r5.index)); })("pointerleave", function CprRibbonOverlayComponent_For_5_Template_circle_pointerleave_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.hoveredNode.set(undefined)); })("pointerdown", function CprRibbonOverlayComponent_For_5_Template_circle_pointerdown_1_listener($event) { const marker_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r4).$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.onNodeMarkerPointerDown($event, marker_r5.d)); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { const marker_r5 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("cx", marker_r5.x)("cy", marker_r5.y)("r", ctx_r1.markerRadius(marker_r5.index))("fill", ctx_r1.nodeColor())("fill-opacity", ctx_r1.EDIT_NODE_FILL_OPACITY)("stroke", ctx_r1.nodeColor())("stroke-width", ctx_r1.EDIT_NODE_STROKE_WIDTH_PX); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("cx", marker_r5.x)("cy", marker_r5.y)("r", ctx_r1.EDIT_NODE_HIT_RADIUS_PX); } } function CprRibbonOverlayComponent_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 8); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](1, "line", 9); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointerenter", function CprRibbonOverlayComponent_Conditional_6_For_2_Template_line_pointerenter_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r6); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.cursorHover.set(true)); })("pointerleave", function CprRibbonOverlayComponent_Conditional_6_For_2_Template_line_pointerleave_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r6); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.cursorHover.set(false)); })("pointerdown", function CprRibbonOverlayComponent_Conditional_6_For_2_Template_line_pointerdown_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r6); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r1.onCursorPointerDown($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { const segment_r7 = ctx.$implicit; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("stroke", ctx_r1.CURSOR_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", segment_r7.x1)("y1", segment_r7.y1)("x2", segment_r7.x2)("y2", segment_r7.y2)("stroke-width", ctx_r1.cursorStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", segment_r7.x1)("y1", segment_r7.y1)("x2", segment_r7.x2)("y2", segment_r7.y2)("stroke-width", ctx_r1.CURSOR_HIT_WIDTH_PX); } } function CprRibbonOverlayComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElement"](0, "line", 7); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterCreate"](1, CprRibbonOverlayComponent_Conditional_6_For_2_Template, 2, 12, null, null, _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterTrackByIndex"]); } if (rf & 2) { const bar_r8 = ctx; const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵstyleProp"]("stroke", ctx_r1.CURSOR_COLOR); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵattribute"]("x1", bar_r8.gapFill.x1)("y1", bar_r8.gapFill.y1)("x2", bar_r8.gapFill.x2)("y2", bar_r8.gapFill.y2)("stroke-width", ctx_r1.cursorStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeater"](bar_r8.segments); } } const TICK_COLOR = 'var(--p-app-cpr-tick)'; const LABEL_COLOR = 'var(--p-app-cpr-label)'; const SEAM_COLOR = 'var(--p-app-cpr-seam)'; const CURSOR_COLOR = 'var(--p-app-cpr-cursor)'; const CURSOR_HIT_WIDTH_PX = 16; const TRACE_DASH_ARRAY = '5 4'; const TRACE_OPACITY = 0.6; class CprRibbonOverlayComponent { TICK_COLOR = TICK_COLOR; LABEL_COLOR = LABEL_COLOR; SEAM_COLOR = SEAM_COLOR; CURSOR_COLOR = CURSOR_COLOR; CURSOR_HIT_WIDTH_PX = CURSOR_HIT_WIDTH_PX; TRACE_DASH_ARRAY = TRACE_DASH_ARRAY; TRACE_OPACITY = TRACE_OPACITY; EDIT_NODE_HIT_RADIUS_PX = _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_HIT_RADIUS_PX; EDIT_NODE_FILL_OPACITY = _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_FILL_OPACITY; EDIT_NODE_STROKE_WIDTH_PX = _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_STROKE_WIDTH_PX; cprService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_cpr_service__WEBPACK_IMPORTED_MODULE_7__.CprService); session = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.cprSessionStore); host = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.ElementRef).nativeElement; box = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "box" }] : [])); cursorHover = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "cursorHover" }] : [])); hoveredNode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, ...(ngDevMode ? [{ debugName: "hoveredNode" }] : [])); draggingCursor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "draggingCursor" }] : [])); backgroundGesture; crosshairSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore).crosshairSize; devicePixelRatio = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_window_details_window_details_service__WEBPACK_IMPORTED_MODULE_5__.WindowDetailsService).devicePixelRatio; cursorStrokeWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const base = this.crosshairSize() / this.devicePixelRatio(); return this.cursorHover() || this.draggingCursor() ? base * 2 : base; }, ...(ngDevMode ? [{ debugName: "cursorStrokeWidth" }] : [])); ticks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const framing = this.cprService.ribbonFraming(); const box = this.box(); if (!framing || !box || box.height <= 0 || box.width <= 0) return []; const closed = this.cprService.activeSplineIsClosed(); return (0,_ribbon_ruler__WEBPACK_IMPORTED_MODULE_12__.rulerTicks)(framing.ribbonLengthMm, closed).map(tick => (0,_ribbon_ruler__WEBPACK_IMPORTED_MODULE_12__.projectRulerTick)(framing, box, tick)); }, ...(ngDevMode ? [{ debugName: "ticks" }] : [])); nodeColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.cprService.activeSplineColor() ?? _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_FALLBACK_COLOR, ...(ngDevMode ? [{ debugName: "nodeColor" }] : [])); // Straightening puts the centerline at lambda = 0, so the trace is one straight line. centerlineTrace = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { if (this.session.editState() !== 'editing') return; const framing = this.cprService.ribbonFraming(); const box = this.box(); if (!framing || !box || box.height <= 0 || box.width <= 0) return; const [x1, y1] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_11__.ribbonToCanvas)(framing, box, { d: 0, lambda: 0 }); const [x2, y2] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_11__.ribbonToCanvas)(framing, box, { d: framing.ribbonLengthMm, lambda: 0 }); return { x1, x2, y1, y2 }; }, ...(ngDevMode ? [{ debugName: "centerlineTrace" }] : [])); nodeMarkers = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { if (this.session.editState() !== 'editing') return []; const framing = this.cprService.ribbonFraming(); const box = this.box(); if (!framing || !box || box.height <= 0 || box.width <= 0) return []; return this.cprService.controlPointDistances().map((d, index) => { const [x, y] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_11__.ribbonToCanvas)(framing, box, { d, lambda: 0 }); return { d, index, x, y }; }); }, ...(ngDevMode ? [{ debugName: "nodeMarkers" }] : [])); markerRadius(index) { return this.hoveredNode() === index ? _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_HOVER_RADIUS_PX : _cpr_config__WEBPACK_IMPORTED_MODULE_6__.EDIT_NODE_RADIUS_PX; } crossBar = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const framing = this.cprService.ribbonFraming(); const box = this.box(); if (!framing || !box || box.height <= 0 || box.width <= 0) return; return (0,_ribbon_cursor__WEBPACK_IMPORTED_MODULE_9__.cursorCrossBar)(framing, box, this.session.cursorMm()); }, ...(ngDevMode ? [{ debugName: "crossBar" }] : [])); constructor() { const observer = new ResizeObserver(() => { this.box.set({ height: this.host.clientHeight, width: this.host.clientWidth }); }); observer.observe(this.host); // Manual listener: wheel must be non-passive for preventDefault, which an // Angular binding cannot guarantee under a passive-events configuration. const onWheel = event => this.onWheel(event); this.host.addEventListener('wheel', onWheel, { passive: false }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(() => { observer.disconnect(); this.host.removeEventListener('wheel', onWheel); }); } /** Grab of the cross-bar: the drag scrubs the cursor along the arc. */ onCursorPointerDown(event) { if (event.button !== 0) return; event.stopPropagation(); event.target.setPointerCapture?.(event.pointerId); this.draggingCursor.set(true); } onNodeMarkerPointerDown(event, d) { if (event.button !== 0) return; event.stopPropagation(); this.cprService.jumpCursor(d); } /** Background press: a still click jumps the cursor; a radial drag rotates the cut plane. */ onSvgPointerDown(event) { if (event.button !== 0) return; event.target.setPointerCapture?.(event.pointerId); this.backgroundGesture = { moved: false, startRotationDeg: this.session.rotationDeg(), startX: event.clientX, startY: event.clientY }; } onSvgPointerMove(event) { if (this.draggingCursor()) { this.scrubToEvent(event); return; } const gesture = this.backgroundGesture; if (!gesture) return; if (!gesture.moved && (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__.exceedsStillClick)(gesture.startX, gesture.startY, event.clientX, event.clientY)) { gesture.moved = true; } if (gesture.moved) { // Rotation reads the radial screen axis: across the ribbon, whichever way it lies. const radialPx = this.session.orientation() === 'vertical' ? event.clientX - gesture.startX : event.clientY - gesture.startY; this.session.setRotationDeg(Math.round(gesture.startRotationDeg + radialPx * _cpr_config__WEBPACK_IMPORTED_MODULE_6__.ROTATE_DEG_PER_PX)); } } onSvgPointerUp(event) { (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__.releaseCapturedPointer)(event); if (this.draggingCursor()) { this.draggingCursor.set(false); return; } const gesture = this.backgroundGesture; this.backgroundGesture = undefined; if (gesture && !gesture.moved) this.scrubToEvent(event); } // A cancelled pointer stream delivers no pointerup; without this the next // hover would keep scrubbing or rotating with no button pressed. onSvgPointerCancel(event) { (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__.releaseCapturedPointer)(event); this.draggingCursor.set(false); this.backgroundGesture = undefined; } onWheel(event) { if (!this.cprService.ribbonFraming()) return; event.preventDefault(); const deltaY = (0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__.normalizeWheelDeltaY)(event.deltaY, event.deltaMode); if (event.ctrlKey) { // CTRL+wheel and trackpad pinch (which arrives as a CTRL wheel) zoom the ribbon. const factor = Math.exp(-deltaY * _cpr_config__WEBPACK_IMPORTED_MODULE_6__.RIBBON_ZOOM_RATE_PER_DELTAY); this.session.setRibbonZoom((0,_long_axis_camera__WEBPACK_IMPORTED_MODULE_8__.clampRibbonZoom)(this.session.ribbonZoom() * factor)); return; } this.cprService.scrubCursor((0,_ribbon_gestures__WEBPACK_IMPORTED_MODULE_10__.wheelCursorStepMm)(deltaY, event.shiftKey)); } scrubToEvent(event) { const framing = this.cprService.ribbonFraming(); const box = this.box(); if (!framing || !box) return; const rect = this.host.getBoundingClientRect(); const point = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_11__.canvasToRibbon)(framing, box, event.clientX - rect.left, event.clientY - rect.top); this.cprService.setCursor(point.d); } static ɵfac = function CprRibbonOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CprRibbonOverlayComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineComponent"]({ type: CprRibbonOverlayComponent, selectors: [["lib-cpr-ribbon-overlay"]], hostAttrs: [1, "absolute", "inset-0", "block"], decls: 7, vars: 2, consts: [[1, "h-full", "w-full", "select-none", 3, "pointerdown", "pointermove", "pointerup", "pointercancel", "contextmenu"], ["data-centerline-trace", "", "stroke-width", "1", "pointer-events", "none"], ["data-ruler-tick", "", "pointer-events", "none"], ["font-size", "11", "font-weight", "600", "pointer-events", "none", 1, "text-shadow-[0_0_3px_var(--p-app-viewport-outline),0_0_3px_var(--p-app-viewport-outline)]", 3, "fill"], ["font-size", "11", "font-weight", "600", "pointer-events", "none", 1, "text-shadow-[0_0_3px_var(--p-app-viewport-outline),0_0_3px_var(--p-app-viewport-outline)]"], ["data-ribbon-node", "", "pointer-events", "none"], ["data-ribbon-node-hit", "", "fill", "transparent", "pointer-events", "all", 3, "pointerenter", "pointerleave", "pointerdown"], ["opacity", "0.25", "pointer-events", "none"], ["data-cursor-line", "", "pointer-events", "none"], ["data-cursor-hit", "", "stroke", "transparent", "pointer-events", "stroke", 3, "pointerenter", "pointerleave", "pointerdown"]], template: function CprRibbonOverlayComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementStart"](0, "svg", 0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomListener"]("pointerdown", function CprRibbonOverlayComponent_Template_svg_pointerdown_0_listener($event) { return ctx.onSvgPointerDown($event); })("pointermove", function CprRibbonOverlayComponent_Template_svg_pointermove_0_listener($event) { return ctx.onSvgPointerMove($event); })("pointerup", function CprRibbonOverlayComponent_Template_svg_pointerup_0_listener($event) { return ctx.onSvgPointerUp($event); })("pointercancel", function CprRibbonOverlayComponent_Template_svg_pointercancel_0_listener($event) { return ctx.onSvgPointerCancel($event); })("contextmenu", function CprRibbonOverlayComponent_Template_svg_contextmenu_0_listener($event) { return $event.preventDefault(); }); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditionalCreate"](1, CprRibbonOverlayComponent_Conditional_1_Template, 1, 7, ":svg:line", 1); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterCreate"](2, CprRibbonOverlayComponent_For_3_Template, 2, 8, null, null, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeaterCreate"](4, CprRibbonOverlayComponent_For_5_Template, 2, 10, null, null, _forTrack1); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditionalCreate"](6, CprRibbonOverlayComponent_Conditional_6_Template, 3, 7); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdomElementEnd"](); } if (rf & 2) { let tmp_0_0; let tmp_3_0; _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditional"]((tmp_0_0 = ctx.centerlineTrace()) ? 1 : -1, tmp_0_0); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeater"](ctx.ticks()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrepeater"](ctx.nodeMarkers()); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵconditional"]((tmp_3_0 = ctx.crossBar()) ? 6 : -1, tmp_3_0); } }, dependencies: [_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 87660 /*!****************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-viewport.ts ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprViewport: () => (/* binding */ CprViewport) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Rendering_Core_Renderer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/Core/Renderer */ 45471); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); const WIDGET_ID_PREFIX = 'tomoverse:cpr-viewport:'; class CprViewport { host; renderer; renderWindow; widgetId; actorsByUid = new Map(); disposed = false; constructor(host, slot) { this.host = host; const primary = host.getRenderer?.(); const renderWindow = primary?.getRenderWindow?.(); if (!primary || !renderWindow) { throw new Error(`CprViewport: host viewport ${host.id} has no renderer or render window`); } this.renderWindow = renderWindow; this.widgetId = `${WIDGET_ID_PREFIX}${slot}`; this.renderer = _kitware_vtk_js_Rendering_Core_Renderer__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance(); this.renderer.setBackground(0, 0, 0); // Added after the host's primary ⇒ we render last in layer 0 and overwrite it. renderWindow.addRenderer(this.renderer); this.renderer.setLayer(0); // The engine's per-pass loop (getWidgetRenderers) flips this on only during // the host's pass. this.renderer.setDraw(false); this.syncViewportRectFromPrimary(); const widget = { getActor: () => { // Returning nothing short-circuits Cornerstone's `removeWidgets` cleanup. }, getEnabled: () => !this.disposed, getRenderer: () => { if (this.disposed) return; this.syncViewportRectFromPrimary(); return this.renderer; }, setEnabled: () => { // No-op: enabled state derives from `disposed` (see getEnabled). } }; host.addWidget(this.widgetId, widget); } get camera() { return this.renderer.getActiveCamera(); } setActors(actors) { if (this.disposed) return; const incomingUids = new Set(actors.map(a => a.uid)); for (const [uid, existing] of this.actorsByUid) { if (!incomingUids.has(uid)) { this.renderer.removeActor(existing); this.actorsByUid.delete(uid); } } for (const { actor, uid } of actors) { this.addActor(uid, actor); } } addActor(uid, actor) { if (this.disposed) return; const previous = this.actorsByUid.get(uid); if (previous === actor) return; if (previous) this.renderer.removeActor(previous); this.renderer.addActor(actor); this.actorsByUid.set(uid, actor); } removeActor(uid) { if (this.disposed) return; const existing = this.actorsByUid.get(uid); if (!existing) return; this.renderer.removeActor(existing); this.actorsByUid.delete(uid); } resetCamera() { if (this.disposed) return; this.renderer.resetCamera(); this.requestRender(); } requestRender() { if (this.disposed) return; this.host.render(); } dispose() { if (this.disposed) return; this.disposed = true; for (const [, actor] of this.actorsByUid) { this.renderer.removeActor(actor); } this.actorsByUid.clear(); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.removeViewportWidget)(this.host, this.widgetId); this.renderWindow.removeRenderer?.(this.renderer); this.renderer.delete?.(); } syncViewportRectFromPrimary() { const rect = this.primaryViewportRect(); if (rect) { this.renderer.setViewport(...rect); } } primaryViewportRect() { try { return this.host.getRenderer?.()?.getViewport?.(); } catch { // The host stops resolving a renderer once its engine starts tearing down. return undefined; } } } /***/ }, /***/ 11095 /*!***************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr-workspace.component.ts ***! \***************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprWorkspaceComponent: () => (/* binding */ CprWorkspaceComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../viewport-interaction/viewport-interaction.service */ 46184); /* harmony import */ var _control_point_step__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./control-point-step */ 85367); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _cpr_cross_section_overlay_component__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./cpr-cross-section-overlay.component */ 72142); /* harmony import */ var _cpr_resize_handle_directive__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./cpr-resize-handle.directive */ 41326); /* harmony import */ var _cpr_ribbon_overlay_component__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./cpr-ribbon-overlay.component */ 52158); /* harmony import */ var _cpr_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./cpr.service */ 26144); /* harmony import */ var _grid_fractions__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./grid-fractions */ 87242); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @angular/core */ 14975); /** * The curved-MPR workspace: a resizable CSS grid holding the CPR carrier mounts and the * registered viewports projected in from the viewer, plus the carrier container wiring * `CprService` gates its session on. */ const _c0 = ["workspaceGrid"]; const _c1 = ["middleColumn"]; const _c2 = ["cprLongAxisContainer"]; const _c3 = ["cprShortAxisContainer"]; const _c4 = (a0, a1) => ({ "animate-viewport-blur-in": a0, "animate-viewport-blur-out": a1 }); const _c5 = () => ({ $implicit: "ribbon" }); const _c6 = () => ({ $implicit: "crossSection" }); const _c7 = (a0, a1) => ({ $implicit: a0, name: a1, panel: "reformat", area: "1 / 3" }); const _c8 = () => ({ $implicit: "x", group: "columns", boundary: 0 }); const _c9 = () => ({ $implicit: "y", group: "middleRows", boundary: 0 }); const _c10 = () => ({ $implicit: "x", group: "topColumns", boundary: 0, area: "1 / 2" }); const _c11 = () => ({ $implicit: "y", group: "bodyRows", boundary: 0, area: "2 / 1 / 3 / -1" }); function CprWorkspaceComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "lib-viewport-button", 21); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("click", function CprWorkspaceComponent_Conditional_6_Template_lib_viewport_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.confirmEdit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](3, "lib-viewport-button", 22); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("click", function CprWorkspaceComponent_Conditional_6_Template_lib_viewport_button_click_3_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r2); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.cancelEdit()); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](1, 4, "planarReformation.confirmEdit"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](2, 6, "planarReformation.confirmEdit")); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](4, 8, "planarReformation.cancelEdit"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](5, 10, "planarReformation.cancelEdit")); } } function CprWorkspaceComponent_ng_container_15_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_16_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](0, CprWorkspaceComponent_Conditional_16_ng_container_0_Template, 1, 0, "ng-container", 15); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); const handle_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵreference"](33); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", handle_r4)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](2, _c8)); } } function CprWorkspaceComponent_Conditional_24_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelement"](0, "img", 18); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("src", ctx, _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵsanitizeUrl"]); } } function CprWorkspaceComponent_ng_container_26_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_27_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_27_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](0, CprWorkspaceComponent_Conditional_27_ng_container_0_Template, 1, 0, "ng-container", 15); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); const handle_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵreference"](33); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", handle_r4)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](2, _c9)); } } function CprWorkspaceComponent_ng_container_28_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_29_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_29_ng_container_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_Conditional_29_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](0, CprWorkspaceComponent_Conditional_29_ng_container_0_Template, 1, 0, "ng-container", 15)(1, CprWorkspaceComponent_Conditional_29_ng_container_1_Template, 1, 0, "ng-container", 15); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); const handle_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵreference"](33); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", handle_r4)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](4, _c10)); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", handle_r4)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](5, _c11)); } } function CprWorkspaceComponent_ng_template_30_ng_container_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_ng_template_30_Conditional_4_ng_container_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_ng_template_30_Conditional_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "div", 25); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](1, CprWorkspaceComponent_ng_template_30_Conditional_4_ng_container_1_Template, 1, 0, "ng-container", 20); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", ctx); } } function CprWorkspaceComponent_ng_template_30_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "div", 23)(1, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](2, CprWorkspaceComponent_ng_template_30_ng_container_2_Template, 1, 0, "ng-container", 20); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelement"](3, "lib-viewport-indicator", 24); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](4, CprWorkspaceComponent_ng_template_30_Conditional_4_Template, 2, 1, "div", 25); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_23_0; const viewportTemplate_r5 = ctx.$implicit; const name_r6 = ctx.name; const panel_r7 = ctx.panel; const area_r8 = ctx.area; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("grid-area", ctx_r2.panelArea(panel_r7, area_r8))("visibility", ctx_r2.panelHidden(panel_r7) ? "hidden" : null)("position", ctx_r2.panelMaximized(panel_r7) ? "absolute" : null)("inset", ctx_r2.panelMaximized(panel_r7) ? "0" : null); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵattribute"]("data-viewport", name_r6); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngClass", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction2"](16, _c4, ctx_r2.isBlur(), !ctx_r2.isBlur())); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", viewportTemplate_r5); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("viewportName", name_r6)("focusedViewport", ctx_r2.selectedMPRViewport())("initialState", ctx_r2.isInitialViewportState())("lastFocused", ctx_r2.lastSelectedMPRViewport()); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"]((tmp_23_0 = !ctx_r2.horizontal() && !ctx_r2.maximizedPanel() && panel_r7 === "reformat" && ctx_r2.cameraSliderTemplate()) ? 4 : -1, tmp_23_0); } } function CprWorkspaceComponent_ng_template_32_Template(rf, ctx) { if (rf & 1) { const _r9 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "div", 26); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("dragStarted", function CprWorkspaceComponent_ng_template_32_Template_div_dragStarted_0_listener() { const ctx_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r9); const group_r11 = ctx_r9.group; const boundary_r12 = ctx_r9.boundary; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.startTrackDrag(group_r11, boundary_r12)); })("dragMoved", function CprWorkspaceComponent_ng_template_32_Template_div_dragMoved_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r9); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.moveTrackDrag($event)); })("dragEnded", function CprWorkspaceComponent_ng_template_32_Template_div_dragEnded_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r9); const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.endTrackDrag()); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); } if (rf & 2) { const axis_r13 = ctx.$implicit; const group_r11 = ctx.group; const boundary_r12 = ctx.boundary; const area_r14 = ctx.area; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("grid-area", area_r14)("visibility", ctx_r2.maximizedPanel() ? "hidden" : null); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵclassProp"]("cursor-col-resize", axis_r13 === "x")("cursor-row-resize", axis_r13 === "y"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("libCprResizeHandle", axis_r13); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵattribute"]("aria-orientation", axis_r13 === "x" ? "vertical" : "horizontal")("aria-valuenow", ctx_r2.boundarySharePercent(group_r11, boundary_r12))("aria-valuemin", ctx_r2.minSharePercent)("aria-valuemax", ctx_r2.maxSharePercent); } } function CprWorkspaceComponent_ng_template_34_Template(rf, ctx) { if (rf & 1) { const _r15 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "div", 27)(1, "lib-viewport-button", 28); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("click", function CprWorkspaceComponent_ng_template_34_Template_lib_viewport_button_click_1_listener() { const panel_r16 = _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r15).$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx_r2.toggleMaximized(panel_r16)); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"]()(); } if (rf & 2) { const panel_r16 = ctx.$implicit; const ctx_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("icon", ctx_r2.maximizedPanel() === panel_r16 ? "arrow-down-left-and-arrow-up-right-to-center" : "arrow-up-right-and-arrow-down-left-from-center")("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](2, 4, ctx_r2.maximizedPanel() === panel_r16 ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](3, 6, ctx_r2.maximizedPanel() === panel_r16 ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel")); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵattribute"]("data-test-id", "cpr-lib-viewport-button-maximize-" + panel_r16); } } function CprWorkspaceComponent_ng_container_37_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_ng_container_38_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } function CprWorkspaceComponent_ng_container_39_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementContainer"](0); } } const RIGHT_MOUSE_BUTTON = 2; const STEP_DURATION_MS = 350; function stepDirection(key) { if (key === 'ArrowRight' || key === 'd') return 1; if (key === 'ArrowLeft' || key === 'a') return -1; return undefined; } class CprWorkspaceComponent { ViewportName = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.ViewportName; axialTemplate = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "axialTemplate" }] : [])); coronalTemplate = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "coronalTemplate" }] : [])); reformatTemplate = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "reformatTemplate" }] : [])); sagittalTemplate = _angular_core__WEBPACK_IMPORTED_MODULE_1__.input.required(...(ngDevMode ? [{ debugName: "sagittalTemplate" }] : [])); // The app page's camera slider docks on the volume panel — the only view here it drives. cameraSliderTemplate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(...(ngDevMode ? [undefined, { debugName: "cameraSliderTemplate" }] : [])); isBlur = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(false, ...(ngDevMode ? [{ debugName: "isBlur" }] : [])); isInitialViewportState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(true, ...(ngDevMode ? [{ debugName: "isInitialViewportState" }] : [])); lastSelectedMPRViewport = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.ViewportName.CORONAL, ...(ngDevMode ? [{ debugName: "lastSelectedMPRViewport" }] : [])); selectedMPRViewport = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.input)(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.ViewportName.CORONAL, ...(ngDevMode ? [{ debugName: "selectedMPRViewport" }] : [])); resizeStart = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.output)(); resizeEnd = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.output)(); // A still of the short-axis held over the live view during resize, so the engine's // rescale-during-drag doesn't flicker through. shortAxisFrozenFrame = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.signal)(undefined, ...(ngDevMode ? [{ debugName: "shortAxisFrozenFrame" }] : [])); session = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.cprSessionStore); horizontal = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.session.orientation() === 'horizontal', ...(ngDevMode ? [{ debugName: "horizontal" }] : [])); maximizedPanel = this.session.maximizedPanel; splineName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.cprService.activeSplineName(), ...(ngDevMode ? [{ debugName: "splineName" }] : [])); editing = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.session.editState() === 'editing', ...(ngDevMode ? [{ debugName: "editing" }] : [])); fractions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.session.fractions()[this.session.orientation()], ...(ngDevMode ? [{ debugName: "fractions" }] : [])); columnTracks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.trackList)(this.horizontal() ? this.fractions().topColumns : this.fractions().columns), ...(ngDevMode ? [{ debugName: "columnTracks" }] : [])); rowTracks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.horizontal() ? (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.trackList)(this.fractions().bodyRows) : 'minmax(0,1fr)', ...(ngDevMode ? [{ debugName: "rowTracks" }] : [])); middleRowTracks = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.trackList)(this.fractions().middleRows), ...(ngDevMode ? [{ debugName: "middleRowTracks" }] : [])); cprService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_cpr_service__WEBPACK_IMPORTED_MODULE_15__.CprService); interaction = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_9__.ViewportInteractionService); workspaceGrid = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('workspaceGrid'); middleColumn = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('middleColumn'); longAxisContainer = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('cprLongAxisContainer'); shortAxisContainer = _angular_core__WEBPACK_IMPORTED_MODULE_1__.viewChild.required('cprShortAxisContainer'); drag = undefined; mountResize = undefined; stepRaf = 0; constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.effect)(() => { const mounts = this.carrierMounts(); for (const [role, mount] of mounts) this.cprService.registerCarrierContainer(role, mount); (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.untracked)(() => this.observeMounts(mounts.map(([, mount]) => mount))); }); // Re-flowing the same panels changes every carrier's box, so run the resize contract — // orientation is set from the sidebar panel and maximize from the viewports' own buttons. let framed = false; (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.effect)(() => { this.session.orientation(); this.session.maximizedPanel(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.untracked)(() => { if (framed) { this.resizeStart.emit(); this.resizeEnd.emit(); } framed = true; }); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.effect)(() => { if (this.session.editState() !== 'editing') (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.untracked)(() => this.cancelStep()); }); const onKeyDown = event => this.onKeyDown(event); globalThis.addEventListener('keydown', onKeyDown); // Leaving CPR destroys this component; the service's readiness gate must not keep // a detached mount alive. Static roles, not carrierMounts(): the view queries can // already be unavailable here and a required read would throw. (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_2__.DestroyRef).onDestroy(() => { this.mountResize?.disconnect(); globalThis.removeEventListener('keydown', onKeyDown); this.cancelStep(); for (const role of _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_REQUIRED_CARRIER_ROLES) this.cprService.unregisterCarrierContainer(role); }); } onKeyDown(event) { if (this.session.editState() !== 'editing') return; // The resize handles step with the arrows too; whatever is nearer the focus owns the key. if (event.defaultPrevented || (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.isEditableTarget)(event.target)) return; const direction = stepDirection(event.key); if (!direction) return; event.preventDefault(); // One step per animation: a press mid-tween restarts it from further along and never arrives. if (this.stepRaf) return; this.stepControlPoint(direction); } stepControlPoint(direction) { const closed = this.cprService.activeSplineIsClosed(); const totalLengthMm = this.cprService.centerlineLengthMm(); const fromMm = this.session.cursorMm(); const deltaMm = (0,_control_point_step__WEBPACK_IMPORTED_MODULE_10__.controlPointStepDelta)({ closed, cursorMm: fromMm, direction, distancesMm: this.cprService.controlPointDistances(), totalLengthMm }); if (deltaMm === undefined) return; this.animateStep({ closed, deltaMm, fromMm, totalLengthMm }); } animateStep(input) { const { closed, deltaMm, fromMm, totalLengthMm } = input; this.cancelStep(); const startedAt = performance.now(); const tick = now => { const progress = Math.min(1, (now - startedAt) / STEP_DURATION_MS); const eased = 1 - (1 - progress) ** 3; this.cprService.setCursor((0,_control_point_step__WEBPACK_IMPORTED_MODULE_10__.normalizeCursorMm)(fromMm + deltaMm * eased, totalLengthMm, closed)); this.stepRaf = progress < 1 ? requestAnimationFrame(tick) : 0; }; this.stepRaf = requestAnimationFrame(tick); } cancelStep() { cancelAnimationFrame(this.stepRaf); this.stepRaf = 0; } carrierMounts() { return [['ribbonA', this.longAxisContainer().nativeElement], ['crossSection', this.shortAxisContainer().nativeElement]]; } freezeShortAxis() { const canvas = this.shortAxisContainer().nativeElement.querySelector('canvas'); if (!canvas) return; try { this.shortAxisFrozenFrame.set(canvas.toDataURL()); } catch { // Snapshot unavailable (e.g. empty/tainted canvas); fall back to the live view. } } unfreezeShortAxis() { this.shortAxisFrozenFrame.set(undefined); } panelArea(panel, horizontalArea) { return this.horizontal() ? horizontalArea : undefined; } minSharePercent = _grid_fractions__WEBPACK_IMPORTED_MODULE_16__.MIN_TRACK_SHARE * 100; maxSharePercent = 100 - _grid_fractions__WEBPACK_IMPORTED_MODULE_16__.MIN_TRACK_SHARE * 100; boundarySharePercent(group, boundary) { return (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.trackSharePercent)(this.fractions()[group], boundary); } /** * Maximize lifts the panel out of the grid rather than spanning it: in the vertical * arrangement the MPRs sit inside a column wrapper, where a full-grid span would only * cover that column. Absolute against the workspace host covers everything, both * orientations, without disturbing the tracks the other panels still occupy. */ panelMaximized(panel) { return this.maximizedPanel() === panel; } panelHidden(panel) { const maximized = this.maximizedPanel(); return maximized !== undefined && maximized !== panel; } /** * CTRL + right-drag is the app's W/L gesture; the carriers get it through the same * interaction instance the MPRs use, so the feel and the clamping are shared. */ startWindowDrag(event) { if (event.button !== RIGHT_MOUSE_BUTTON || !event.ctrlKey) return; event.preventDefault(); this.interaction.startWindowSettingsDrag([event.offsetX, event.offsetY]); } updateWindowDrag(event, role) { this.interaction.updateWindowSettingsDrag([event.offsetX, event.offsetY], _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS[role]); } toggleMaximized(panel) { this.session.toggleMaximizedPanel(panel); } exitWorkspace() { this.cprService.cancel(); } confirmEdit() { this.cprService.confirmEdit(); } cancelEdit() { this.cprService.cancelEdit(); } // The carriers' cameras are fixed in mm, so every change of their box — grid re-flow, // window resize, handle drag — has to re-impose the FOV the engine's resize rescaled. observeMounts(mounts) { this.mountResize?.disconnect(); this.mountResize = new ResizeObserver(() => { this.cprService.refreshShortAxisCamera(); this.cprService.refreshLongAxisCamera(); }); for (const mount of mounts) this.mountResize.observe(mount); } startTrackDrag(group, boundary) { const { axis, container } = this.trackGroup(group); const fractions = this.fractions()[group]; const containerPx = axis === 'x' ? container.clientWidth : container.clientHeight; this.drag = { availablePx: (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.availableTrackPx)(containerPx, fractions.length), boundary, fractions, group }; this.resizeStart.emit(); } // Deltas are measured from the drag origin, so they apply to the fractions as captured. moveTrackDrag(deltaPx) { if (!this.drag) return; const { availablePx, boundary, fractions, group } = this.drag; this.session.setTrackFractions(this.session.orientation(), group, (0,_grid_fractions__WEBPACK_IMPORTED_MODULE_16__.resizeTracks)(fractions, boundary, deltaPx, availablePx)); } endTrackDrag() { if (!this.drag) return; this.drag = undefined; this.resizeEnd.emit(); } // Horizontal's tracks all belong to the workspace grid itself; vertical's row groups // belong to the column wrappers, which is why those keep a box in that orientation. trackGroup(group) { switch (group) { case 'bodyRows': { return { axis: 'y', container: this.workspaceGrid().nativeElement }; } case 'columns': case 'topColumns': { return { axis: 'x', container: this.workspaceGrid().nativeElement }; } case 'middleRows': { return { axis: 'y', container: this.middleColumn().nativeElement }; } } } static ɵfac = function CprWorkspaceComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CprWorkspaceComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵdefineComponent"]({ type: CprWorkspaceComponent, selectors: [["lib-cpr-workspace"]], viewQuery: function CprWorkspaceComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵviewQuerySignal"](ctx.workspaceGrid, _c0, 5)(ctx.middleColumn, _c1, 5)(ctx.longAxisContainer, _c2, 5)(ctx.shortAxisContainer, _c3, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵqueryAdvance"](4); } }, hostAttrs: [1, "relative", "block", "h-full", "w-full"], hostVars: 6, hostBindings: function CprWorkspaceComponent_HostBindings(rf, ctx) { if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("--cpr-columns", ctx.columnTracks())("--cpr-middle-rows", ctx.middleRowTracks())("--cpr-rows", ctx.rowTracks()); } }, inputs: { axialTemplate: [1, "axialTemplate"], coronalTemplate: [1, "coronalTemplate"], reformatTemplate: [1, "reformatTemplate"], sagittalTemplate: [1, "sagittalTemplate"], cameraSliderTemplate: [1, "cameraSliderTemplate"], isBlur: [1, "isBlur"], isInitialViewportState: [1, "isInitialViewportState"], lastSelectedMPRViewport: [1, "lastSelectedMPRViewport"], selectedMPRViewport: [1, "selectedMPRViewport"] }, outputs: { resizeStart: "resizeStart", resizeEnd: "resizeEnd" }, decls: 40, vars: 52, consts: [["workspaceGrid", ""], ["cprLongAxisContainer", ""], ["middleColumn", ""], ["cprShortAxisContainer", ""], ["registeredPanel", ""], ["handle", ""], ["maximizeButton", ""], ["data-test-id", "cpr-div-workspace-header", 1, "pointer-events-auto", "absolute", "top-6", "left-6", "z-30", "flex", "items-center", "gap-1", "rounded", "bg-(--p-app-viewport-background)/60", "py-0.5", "pr-3", "pl-1", "text-(--p-app-viewport-label)"], ["data-test-id", "cpr-lib-viewport-button-exit-workspace", "icon", "arrow-left", "iconType", "prime", "tooltipPosition", "bottom", "tooltipStyleClass", "left-6! [&>.p-tooltip-arrow]:left-4!", 3, "click", "tooltip", "ariaLabel"], [1, "text-sm", "font-medium"], ["data-test-id", "cpr-div-panels", 1, "grid", "h-full", "w-full", "grid-cols-(--cpr-columns)", "grid-rows-(--cpr-rows)", "bg-(--p-app-viewport-background)"], ["data-viewport", "cpr-long-axis", 1, "relative", "overflow-hidden", "bg-(--p-app-viewport-background)", 3, "dblclick", "mousedown", "mousemove"], [1, "h-full", "w-full", 3, "ngClass"], [1, "relative", "h-full", "w-full"], [1, "h-full", "w-full", "bg-(--p-app-viewport-background)"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "grid", "grid-rows-(--cpr-middle-rows)", "bg-(--p-app-viewport-background)"], ["data-viewport", "cpr-short-axis", 1, "relative", "overflow-hidden", "bg-(--p-app-viewport-background)", 3, "dblclick", "mousedown", "mousemove"], ["alt", "", 1, "pointer-events-none", "absolute", "inset-0", "h-full", "w-full", 3, "src"], [1, "invisible", "absolute", "top-0", "left-0", "size-100", "overflow-hidden"], [4, "ngTemplateOutlet"], ["data-test-id", "cpr-lib-viewport-button-confirm-edit", "icon", "check", "iconType", "prime", "tooltipPosition", "bottom", 3, "click", "tooltip", "ariaLabel"], ["data-test-id", "cpr-lib-viewport-button-cancel-edit", "icon", "times", "iconType", "prime", "tooltipPosition", "bottom", 3, "click", "tooltip", "ariaLabel"], [1, "relative", "overflow-hidden", "bg-(--p-app-viewport-background)"], [3, "viewportName", "focusedViewport", "initialState", "lastFocused"], ["data-test-id", "cpr-div-camera-slider", 1, "pointer-events-none", "absolute", "top-0", "right-0", "z-10", "flex", "justify-end"], ["role", "separator", 1, "bg-surface-700", "hover:bg-primary-400", "touch-none", 3, "dragStarted", "dragMoved", "dragEnded", "libCprResizeHandle"], [1, "absolute", "right-0", "bottom-0", "z-10", "flex", "h-8", "items-center", "py-2", "pr-2"], ["iconType", "prime", "tooltipPosition", "top", 3, "click", "icon", "tooltip", "ariaLabel"]], template: function CprWorkspaceComponent_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](0, "div", 7)(1, "lib-viewport-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("click", function CprWorkspaceComponent_Template_lib_viewport_button_click_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.exitWorkspace()); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](4, "span", 9); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](6, CprWorkspaceComponent_Conditional_6_Template, 6, 12); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](7, "div", 10, 0)(9, "div", 11); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("dblclick", function CprWorkspaceComponent_Template_div_dblclick_9_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.toggleMaximized("ribbon")); })("mousedown", function CprWorkspaceComponent_Template_div_mousedown_9_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.startWindowDrag($event)); })("mousemove", function CprWorkspaceComponent_Template_div_mousemove_9_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.updateWindowDrag($event, "ribbonA")); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](10, "div", 12)(11, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelement"](12, "div", 14, 1)(14, "lib-cpr-ribbon-overlay"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](15, CprWorkspaceComponent_ng_container_15_Template, 1, 0, "ng-container", 15); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](16, CprWorkspaceComponent_Conditional_16_Template, 1, 3, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](17, "div", 16, 2)(19, "div", 17); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵlistener"]("dblclick", function CprWorkspaceComponent_Template_div_dblclick_19_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.toggleMaximized("crossSection")); })("mousedown", function CprWorkspaceComponent_Template_div_mousedown_19_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.startWindowDrag($event)); })("mousemove", function CprWorkspaceComponent_Template_div_mousemove_19_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵrestoreView"](_r1); return _angular_core__WEBPACK_IMPORTED_MODULE_2__["ɵɵresetView"](ctx.updateWindowDrag($event, "crossSection")); }); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](20, "div", 12)(21, "div", 13); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelement"](22, "div", 14, 3); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](24, CprWorkspaceComponent_Conditional_24_Template, 1, 1, "img", 18); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelement"](25, "lib-cpr-cross-section-overlay"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](26, CprWorkspaceComponent_ng_container_26_Template, 1, 0, "ng-container", 15); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](27, CprWorkspaceComponent_Conditional_27_Template, 1, 3, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](28, CprWorkspaceComponent_ng_container_28_Template, 1, 0, "ng-container", 15); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditionalCreate"](29, CprWorkspaceComponent_Conditional_29_Template, 2, 6); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](30, CprWorkspaceComponent_ng_template_30_Template, 5, 19, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplateRefExtractor"])(32, CprWorkspaceComponent_ng_template_32_Template, 1, 13, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplateRefExtractor"])(34, CprWorkspaceComponent_ng_template_34_Template, 4, 8, "ng-template", null, 6, _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementStart"](36, "div", 19); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtemplate"](37, CprWorkspaceComponent_ng_container_37_Template, 1, 0, "ng-container", 20)(38, CprWorkspaceComponent_ng_container_38_Template, 1, 0, "ng-container", 20)(39, CprWorkspaceComponent_ng_container_39_Template, 1, 0, "ng-container", 20); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_25_0; const registeredPanel_r17 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵreference"](31); const maximizeButton_r18 = _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵreference"](35); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](2, 37, "planarReformation.exit"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpipeBind1"](3, 39, "planarReformation.exit")); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵtextInterpolate"](ctx.splineName()); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"](ctx.editing() ? 6 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("grid-area", ctx.panelArea("ribbon", "3 / 1 / 4 / -1"))("visibility", ctx.panelHidden("ribbon") ? "hidden" : null)("position", ctx.panelMaximized("ribbon") ? "absolute" : null)("inset", ctx.panelMaximized("ribbon") ? "0" : null); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngClass", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction2"](41, _c4, ctx.isBlur(), !ctx.isBlur())); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", maximizeButton_r18)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](44, _c5)); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"](!ctx.horizontal() ? 16 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("display", ctx.horizontal() ? "contents" : null); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵstyleProp"]("grid-area", ctx.panelArea("crossSection", "1 / 1"))("visibility", ctx.panelHidden("crossSection") ? "hidden" : null)("position", ctx.panelMaximized("crossSection") ? "absolute" : null)("inset", ctx.panelMaximized("crossSection") ? "0" : null); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngClass", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction2"](45, _c4, ctx.isBlur(), !ctx.isBlur())); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"]((tmp_25_0 = ctx.shortAxisFrozenFrame()) ? 24 : -1, tmp_25_0); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", maximizeButton_r18)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction0"](48, _c6)); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"](!ctx.horizontal() ? 27 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", registeredPanel_r17)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵpureFunction2"](49, _c7, ctx.reformatTemplate(), ctx.ViewportName.REFORMAT)); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵconditional"](ctx.horizontal() ? 29 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](8); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", ctx.axialTemplate()); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", ctx.sagittalTemplate()); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_17__["ɵɵproperty"]("ngTemplateOutlet", ctx.coronalTemplate()); } }, dependencies: [_cpr_cross_section_overlay_component__WEBPACK_IMPORTED_MODULE_12__.CprCrossSectionOverlayComponent, _cpr_resize_handle_directive__WEBPACK_IMPORTED_MODULE_13__.CprResizeHandleDirective, _cpr_ribbon_overlay_component__WEBPACK_IMPORTED_MODULE_14__.CprRibbonOverlayComponent, _angular_common__WEBPACK_IMPORTED_MODULE_0__.NgClass, _angular_common__WEBPACK_IMPORTED_MODULE_0__.NgTemplateOutlet, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.ViewportButtonComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.ViewportIndicatorComponent, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_4__.TranslatePipe], styles: ["[_nghost-%COMP%] {\n --cpr-columns: minmax(0, 1.3fr) 4px minmax(0, 1fr);\n --cpr-rows: minmax(0, 1fr);\n --cpr-middle-rows: minmax(0, 1fr) 4px minmax(0, 1fr);\n}\n\n[role=separator][_ngcontent-%COMP%] {\n position: relative;\n}\n\n[role=separator][_ngcontent-%COMP%]::after {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n border-radius: var(--p-splitter-handle-border-radius);\n outline-color: transparent;\n}\n\n[role=separator][aria-orientation=vertical][_ngcontent-%COMP%]::after {\n height: 100%;\n width: 0.125rem;\n}\n\n[role=separator][aria-orientation=horizontal][_ngcontent-%COMP%]::after {\n height: 0.125rem;\n width: 100%;\n}\n\n[role=separator][_ngcontent-%COMP%]:focus-visible::after {\n box-shadow: var(--p-splitter-handle-focus-ring-shadow);\n outline: var(--p-splitter-handle-focus-ring-width) var(--p-splitter-handle-focus-ring-style) var(--p-splitter-handle-focus-ring-color);\n outline-offset: var(--p-splitter-handle-focus-ring-offset);\n}\n/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL2xpYnMvZmVhdHVyZS9zcmMvbGliL3ZvbHVtZS12aWV3ZXIvY3ByL2Nwci13b3Jrc3BhY2UuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNJO0VBQ0Usa0RBQUE7RUFDQSwwQkFBQTtFQUNBLG9EQUFBO0FBQU47O0FBR0k7RUFDRSxrQkFBQTtBQUFOOztBQUdJO0VBQ0UsV0FBQTtFQUNBLGtCQUFBO0VBQ0EsUUFBQTtFQUNBLFNBQUE7RUFDQSxnQ0FBQTtFQUNBLHFEQUFBO0VBQ0EsMEJBQUE7QUFBTjs7QUFHSTtFQUNFLFlBQUE7RUFDQSxlQUFBO0FBQU47O0FBR0k7RUFDRSxnQkFBQTtFQUNBLFdBQUE7QUFBTjs7QUFHSTtFQUNFLHNEQUFBO0VBQ0Esc0lBQUE7RUFFQSwwREFBQTtBQUROIiwic291cmNlc0NvbnRlbnQiOlsiXG4gICAgOmhvc3Qge1xuICAgICAgLS1jcHItY29sdW1uczogbWlubWF4KDAsIDEuM2ZyKSA0cHggbWlubWF4KDAsIDFmcik7XG4gICAgICAtLWNwci1yb3dzOiBtaW5tYXgoMCwgMWZyKTtcbiAgICAgIC0tY3ByLW1pZGRsZS1yb3dzOiBtaW5tYXgoMCwgMWZyKSA0cHggbWlubWF4KDAsIDFmcik7XG4gICAgfVxuXG4gICAgW3JvbGU9J3NlcGFyYXRvciddIHtcbiAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICB9XG5cbiAgICBbcm9sZT0nc2VwYXJhdG9yJ106OmFmdGVyIHtcbiAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgdG9wOiA1MCU7XG4gICAgICBsZWZ0OiA1MCU7XG4gICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtNTAlLCAtNTAlKTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWJvcmRlci1yYWRpdXMpO1xuICAgICAgb3V0bGluZS1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgfVxuXG4gICAgW3JvbGU9J3NlcGFyYXRvciddW2FyaWEtb3JpZW50YXRpb249J3ZlcnRpY2FsJ106OmFmdGVyIHtcbiAgICAgIGhlaWdodDogMTAwJTtcbiAgICAgIHdpZHRoOiAwLjEyNXJlbTtcbiAgICB9XG5cbiAgICBbcm9sZT0nc2VwYXJhdG9yJ11bYXJpYS1vcmllbnRhdGlvbj0naG9yaXpvbnRhbCddOjphZnRlciB7XG4gICAgICBoZWlnaHQ6IDAuMTI1cmVtO1xuICAgICAgd2lkdGg6IDEwMCU7XG4gICAgfVxuXG4gICAgW3JvbGU9J3NlcGFyYXRvciddOmZvY3VzLXZpc2libGU6OmFmdGVyIHtcbiAgICAgIGJveC1zaGFkb3c6IHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWZvY3VzLXJpbmctc2hhZG93KTtcbiAgICAgIG91dGxpbmU6IHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWZvY3VzLXJpbmctd2lkdGgpIHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWZvY3VzLXJpbmctc3R5bGUpXG4gICAgICAgIHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWZvY3VzLXJpbmctY29sb3IpO1xuICAgICAgb3V0bGluZS1vZmZzZXQ6IHZhcigtLXAtc3BsaXR0ZXItaGFuZGxlLWZvY3VzLXJpbmctb2Zmc2V0KTtcbiAgICB9XG4gICJdLCJzb3VyY2VSb290IjoiIn0= */"], changeDetection: 0 }); } /***/ }, /***/ 26144 /*!***************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cpr.service.ts ***! \***************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CprService: () => (/* binding */ CprService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @cornerstonejs/core */ 38277); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _build_cpr_actor__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./build-cpr-actor */ 36896); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _cpr_image_data__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./cpr-image-data */ 3338); /* harmony import */ var _cpr_viewport__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./cpr-viewport */ 87660); /* harmony import */ var _cross_section_nodes__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./cross-section-nodes */ 54776); /* harmony import */ var _long_axis_camera__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./long-axis-camera */ 51984); /* harmony import */ var _short_axis_viewport__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./short-axis-viewport */ 9091); /* harmony import */ var _spline_to_centerline__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./spline-to-centerline */ 46815); /** * Drives CPR mode: flips the app into the `LayoutType.CPR` layout and, once its * viewports exist, renders the long-axis ribbon (owned `CprViewport`) and the * short-axis slice (a dedicated Cornerstone oblique-MPR viewport). Restores the * prior layout on exit. */ const LONG_AXIS_ACTOR_UID = 'cpr-long-axis'; class CprService { engine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_4__.RenderingEngineService); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.AnnotationFacade); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.viewportStore); session = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.cprSessionStore); renderSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_7__.renderSettingsStore); desiredLayout = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "desiredLayout" }] : [])); carrierContainers = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)({}, ...(ngDevMode ? [{ debugName: "carrierContainers" }] : [])); // The active phase's MPR volume id, set by the viewer. CPR reforms from this volume so it tracks // the active phase rather than whichever volume is first in the cache (multiphase series). activeVolumeId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "activeVolumeId" }] : [])); targetSpline = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "targetSpline" }] : [])); active = undefined; editSnapshot = undefined; pendingSnapWorld = undefined; // The fan-out runs again through the cursor effect, so this outlives the call that set it. recentreOnCursor = true; pendingSwitchRecentre = false; // Held for the drag: each move rebuilds the centerline, so the cursor must re-aim at the point. grabbedPointIndex = undefined; // The effect can refire during the async enable, before `active` is set. starting = false; hostsReady = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const containers = this.carrierContainers(); return this.desiredLayout() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__.LayoutType.CPR && _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_REQUIRED_CARRIER_ROLES.every(role => !!containers[role]); }, ...(ngDevMode ? [{ debugName: "hostsReady" }] : [])); // Tracks the target spline's live data so CPR rebuilds on edit and cancels on delete. activeSplineData = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const id = this.targetSpline()?.id; return id ? this.annotationFacade.annotationMap()[id] : undefined; }, ...(ngDevMode ? [{ debugName: "activeSplineData" }] : [])); /** The spline being reformatted, for the drawer list's selection state. */ activeSplineId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.targetSpline()?.id, ...(ngDevMode ? [{ debugName: "activeSplineId" }] : [])); // Reads the live annotation, not the entry snapshot, so the bar follows renames. activeSplineName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.activeSplineData()?.name, ...(ngDevMode ? [{ debugName: "activeSplineName" }] : [])); // The framing the ribbon camera last applied — the SVG overlays' projection input. ribbonFraming = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "ribbonFraming" }] : [])); /** Closed splines wrap; the overlay ruler marks the seam at both ribbon ends. */ activeSplineIsClosed = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsClosedSpline)(this.activeSplineData()), ...(ngDevMode ? [{ debugName: "activeSplineIsClosed" }] : [])); activeSpline = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const annotation = this.activeSplineData(); return annotation && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(annotation) ? annotation : undefined; }, ...(ngDevMode ? [{ debugName: "activeSpline" }] : [])); controlPoints = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.activeSpline()?.points ?? [], ...(ngDevMode ? [{ debugName: "controlPoints" }] : [])); activeSplineColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.activeSpline()?.color, ...(ngDevMode ? [{ debugName: "activeSplineColor" }] : [])); // `updateCprCenterline` hands back a fresh object per rebuild, so derived state only // recomputes on that swap if the centerline is in the signal graph. centerline = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "centerline" }] : [])); centerlineLengthMm = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.centerline()?.totalLength ?? 0, ...(ngDevMode ? [{ debugName: "centerlineLengthMm" }] : [])); controlPointDistances = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const centerline = this.centerline(); return centerline ? (0,_cross_section_nodes__WEBPACK_IMPORTED_MODULE_14__.centerlineDistances)(centerline.positions, this.controlPoints()) : []; }, ...(ngDevMode ? [{ debugName: "controlPointDistances" }] : [])); // Bumped on every cross-section camera write: the engine is event-suppressed, so there is // no CAMERA_MODIFIED for the overlay to re-project its handles on. shortAxisCameraVersion = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "shortAxisCameraVersion" }] : [])); constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const ready = this.hostsReady(); const spline = this.activeSplineData(); const wanted = this.targetSpline(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { if (!wanted) return; if (!spline || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(spline)) { this.cancel(); return; } if (!this.active) { if (ready && !this.starting) { this.startSession(spline).catch(() => { // startSession handles its own cleanup; empty catch satisfies no-floating-promises. }); } return; } this.rebuildForSpline(spline); }); }); // The carriers are orchestrator-unregistered, so the window effect never reaches the // ribbon actor; it reads the same store the MPR pipeline does instead. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const { level, width } = this.renderSettings.windowSettings(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.applyRibbonWindow(width, level)); }); // The store owns the cursor; every writer converges here to move the views. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const cursorMm = this.session.cursorMm(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.applyCursor(cursorMm)); }); // Zoom re-frames only the ribbon; the cross-section's FOV is fixed. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this.session.ribbonZoom(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.refreshLongAxisCamera()); }); // Rotation re-composes the cut plane's orientation array in place; the cameras // stay put — the image under them spins. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const rollRad = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.deg2rad)(this.session.rotationDeg()); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.applyRoll(rollRad)); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.DestroyRef).onDestroy(() => this.tearDown()); } registerCarrierContainer(role, container) { this.carrierContainers.update(current => ({ ...current, [role]: container })); } unregisterCarrierContainer(role) { this.carrierContainers.update(current => { const next = { ...current }; delete next[role]; return next; }); } start(spline) { if (this.targetSpline()?.id === spline.id) return; this.cancelEdit(); this.releaseControlPoint(); // A switch re-frames the volume render; later edit rebuilds must not. this.pendingSwitchRecentre = true; this.session.setCursorMm(0); this.session.setRibbonZoom(1); this.session.setRotationDeg(0); this.session.setMaximizedPanel(undefined); this.targetSpline.set(spline); this.desiredLayout.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__.LayoutType.CPR); } cancel() { this.cancelEdit(); this.targetSpline.set(undefined); this.tearDown(); } /** Edits are written straight to the annotation; this snapshot is what Cancel restores. */ beginEdit() { const spline = this.activeSplineData(); if (!spline || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(spline)) return; this.editSnapshot = { annotationId: spline.id, points: spline.points }; this.session.setEditState('editing'); } confirmEdit() { this.editSnapshot = undefined; this.session.setEditState('review'); } commitControlPointDrag(index, world) { const spline = this.activeSpline(); if (!spline) return; // Consumed by the rebuild this write triggers: the landing point's arc distance can only // be measured against the centerline the edit produces, never the one it replaces. this.pendingSnapWorld = world; this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_8__.movePoint)(spline, index, world)); } /** Restore the control points held at edit entry. Exit and spline switch both land here. */ cancelEdit() { const snapshot = this.editSnapshot; this.editSnapshot = undefined; this.session.setEditState('review'); if (!snapshot) return; // Keyed by the snapshot's own id: a spline deleted mid-edit leaves nothing to restore onto. const annotation = this.annotationFacade.annotationMap()[snapshot.annotationId]; if (!annotation || !(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(annotation)) return; this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_8__.setPoints)(annotation, snapshot.points)); } // The engine's resize rescales parallelScale; re-assert the short-axis fixed FOV. refreshShortAxisCamera() { const active = this.active; if (!active) return; this.applyShortAxis(active.longAxis.bundle.centerline, this.session.cursorMm()); } shortAxisPlane() { return this.active?.shortAxis.handle?.plane(); } worldToCanvas(world) { return this.active?.shortAxis.handle?.worldToCanvas(world); } canvasToWorld(canvas) { return this.active?.shortAxis.handle?.canvasToWorld(canvas); } // resize(keepCamera) changes the carrier's aspect; re-fit the ribbon to the new box. refreshLongAxisCamera() { const longAxis = this.active?.longAxis; if (longAxis) this.applyLongAxisCamera(longAxis); } /** Nudge the cursor by a signed distance — wheel scrubs from either overlay land here. */ scrubCursor(deltaMm) { this.setCursor(this.session.cursorMm() + deltaMm); } /** The single clamp site: every cursor write lands inside the live arc. */ setCursor(distanceMm) { const active = this.active; if (!active) return; const total = active.longAxis.bundle.centerline.totalLength; this.recentreOnCursor = true; this.session.setCursorMm(Math.max(0, Math.min(total, distanceMm))); } /** A click on the active spline anywhere in the app: control point or bare centerline. */ snapCursorToSpline(details, viewportId, screenPos) { if (details.annotationId !== this.activeSplineId()) return; const centerline = this.active?.longAxis.bundle.centerline; if (!centerline) return; const { pointIndex } = details; if (pointIndex !== undefined) { this.grabbedPointIndex = pointIndex; const distanceMm = this.controlPointDistances()[pointIndex]; // The press may start a drag, which reads its target through the volume render's camera. if (distanceMm !== undefined) this.jumpCursor(distanceMm, false); return; } // Between control points there is no handle to read a position off, so intersect the // pick ray with the centerline instead. const ray = this.engine.getWorldRay(viewportId, screenPos); const hit = ray && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.closestPathPointToRay)(centerline.positions, ray); if (hit) this.jumpCursor((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.calculateDistanceOnPath)(centerline.positions, hit), false); } releaseControlPoint() { this.grabbedPointIndex = undefined; } /** * A click straight onto a control point. A scrub converges over many writes and a single * write cannot, so the fan-out and the repaint both run unconditionally here. */ jumpCursor(distanceMm, recentre = true) { const active = this.active; if (!active) return; const centerline = active.longAxis.bundle.centerline; const cursorMm = Math.max(0, Math.min(distanceMm, centerline.totalLength)); // Re-aiming and repainting an unmoved cursor would shift a view that has settled. if (cursorMm === this.session.cursorMm()) return; this.recentreOnCursor = recentre; this.session.setCursorMm(cursorMm); this.applyCursor(cursorMm); this.repaintShortAxis(centerline, cursorMm); } /** * Frame the ribbon: the whole reformation at zoom 1, else zoomed about the cursor. * Reads the session store, so scroll, zoom and resize all land here. */ applyLongAxisCamera(state) { const camera = state.viewport.camera; const focal = camera.getFocalPoint(); const orientation = this.session.orientation(); const ribbonLengthMm = state.bundle.centerline.totalLength; const framing = (0,_long_axis_camera__WEBPACK_IMPORTED_MODULE_15__.frameLongAxis)({ aspect: longAxisAspect(state.host), cursorMm: this.session.cursorMm(), orientation, previousFocal: state.framed ? { x: focal[0] ?? 0, y: focal[1] ?? 0 } : undefined, ribbonLengthMm, ribbonWidthMm: _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_WIDTH_MM, zoom: this.session.ribbonZoom() }); camera.setParallelProjection(true); camera.setParallelScale(framing.parallelScale); camera.setFocalPoint(framing.focalX, framing.focalY, 0); camera.setPosition(framing.focalX, framing.focalY, _cpr_config__WEBPACK_IMPORTED_MODULE_11__.LONG_AXIS_CAMERA_DISTANCE_MM); camera.setViewUp(...framing.viewUp); camera.setClippingRange(_cpr_config__WEBPACK_IMPORTED_MODULE_11__.LONG_AXIS_CAMERA_DISTANCE_MM * 0.5, _cpr_config__WEBPACK_IMPORTED_MODULE_11__.LONG_AXIS_CAMERA_DISTANCE_MM * 1.5); state.framed = true; state.viewport.requestRender(); this.ribbonFraming.set({ focalX: framing.focalX, focalY: framing.focalY, orientation, parallelScale: framing.parallelScale, ribbonLengthMm, ribbonWidthMm: _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_WIDTH_MM }); } applyRibbonWindow(width, level) { const longAxis = this.active?.longAxis; if (!longAxis) return; const property = longAxis.bundle.actor.getProperty(); property.setColorWindow(width); property.setColorLevel(level); longAxis.viewport.requestRender(); } startSession(spline) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this.starting = true; try { const containers = _this.carrierContainers(); const ribbonContainer = containers.ribbonA; const crossSectionContainer = containers.crossSection; const binding = _this.resolvePrimaryVolume(); if (!ribbonContainer || !crossSectionContainer || !binding) return; const cprImageData = (0,_cpr_image_data__WEBPACK_IMPORTED_MODULE_12__.buildCprImageData)(binding.imageData); let host; try { yield _this.engine.enable(ribbonContainer, { id: _cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS.ribbonA, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__.ViewportType.ORTHOGRAPHIC, volumeId: binding.volumeId }); host = _this.getHost(_cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS.ribbonA); } catch { host = undefined; } // Bail if the enable failed or the session was cancelled/re-targeted mid-await. if (!host || _this.targetSpline()?.id !== spline.id || _this.desiredLayout() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__.LayoutType.CPR) { _this.engine.disable(_cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS.ribbonA); return; } const longAxis = _this.startLongAxis(host, cprImageData, spline); const shortAxis = { handle: undefined }; _this.active = { enabledRoles: new Set(['ribbonA']), longAxis, shortAxis }; _this.startShortAxis(binding, longAxis, shortAxis, crossSectionContainer); // Initial setup already placed the crosshair with recentering enabled. _this.pendingSwitchRecentre = false; } finally { _this.starting = false; } })(); } startLongAxis(host, imageData, spline) { const viewport = new _cpr_viewport__WEBPACK_IMPORTED_MODULE_13__.CprViewport(host, 'long-axis'); const bundle = (0,_build_cpr_actor__WEBPACK_IMPORTED_MODULE_10__.buildCprActor)(imageData, spline, this.currentRollRad()); viewport.setActors([{ actor: bundle.actor, uid: LONG_AXIS_ACTOR_UID }]); const state = { bundle, framed: false, host, imageData, viewport }; this.centerline.set(bundle.centerline); this.applyLongAxisCamera(state); return state; } startShortAxis(binding, longAxis, shortAxis, container) { const centerline = longAxis.bundle.centerline; const initial = centerline.totalLength * _cpr_config__WEBPACK_IMPORTED_MODULE_11__.SHORT_AXIS_INITIAL_POSITION_FRACTION; this.session.setCursorMm(initial); this.pushCrosshair(centerline, initial, true); (0,_short_axis_viewport__WEBPACK_IMPORTED_MODULE_16__.startShortAxisViewport)({ centerline, container, engine: this.engine, initialDistance: initial, volumeId: binding.volumeId }).then(handle => { if (this.active?.shortAxis !== shortAxis) { this.engine.disable(_cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS.crossSection); return; } shortAxis.handle = handle; this.active.enabledRoles.add('crossSection'); // Both carriers enable after the last window write, so take the current settings now: // the ribbon through its actor, the cross-section through the engine's VOI pass. const { level, width } = this.renderSettings.windowSettings(); this.applyRibbonWindow(width, level); this.engine.updateMPRWindow(width, level); // Enabling a viewport re-tiles the shared offscreen surface, so both carriers' // fixed-FOV cameras have to be re-asserted once the last one is up. this.refreshShortAxisCamera(); this.refreshLongAxisCamera(); this.forceShortAxisRepaint(); }).catch(() => { // Enable failed; the long-axis still renders and teardown stays safe. }); } /** * Re-applying the corrected entry camera leaves the MTime unchanged, so without this the * short-axis keeps Cornerstone's volume-load reset (axial, fit-to-volume) until the first * scroll. Deferred so the entry churn settles first. */ forceShortAxisRepaint() { const nudge = () => { const active = this.active; if (!active?.shortAxis.handle) return; this.repaintShortAxis(active.longAxis.bundle.centerline, this.session.cursorMm()); }; const idle = globalThis.requestIdleCallback; if (idle) idle(nudge, { timeout: 2000 });else setTimeout(nudge, 500); } // A still-active session over a changed spline: keep the cursor where the user had it, // clamped to the edited length. Switches via start() open at 0 — it resets the store first. rebuildForSpline(spline) { if (!this.active) return; const centerline = (0,_build_cpr_actor__WEBPACK_IMPORTED_MODULE_10__.updateCprCenterline)(this.active.longAxis.bundle, spline, this.currentRollRad()); this.centerline.set(centerline); // The grabbed point has just moved, so it wins over the cursor's old arc distance. const grabbed = this.grabbedPointIndex; const snapWorld = this.pendingSnapWorld ?? (grabbed === undefined ? undefined : this.controlPoints()[grabbed]); this.pendingSnapWorld = undefined; const target = snapWorld ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.calculateDistanceOnPath)(centerline.positions, snapWorld) : this.session.cursorMm(); const cursorMm = Math.max(0, Math.min(target, centerline.totalLength)); // An edit moves the geometry under a held cursor, so only a switch re-frames. this.recentreOnCursor = this.pendingSwitchRecentre; this.pendingSwitchRecentre = false; this.session.setCursorMm(cursorMm); // The setter no-ops on an unchanged value, so the fan-out to the rebuilt // centerline has to run unconditionally. this.applyCursor(cursorMm); // The engine may skip the render above. A scrub repaints on its next tick; a rebuild cannot. this.repaintShortAxis(centerline, cursorMm); } applyCursor(cursorMm) { const active = this.active; if (!active) return; const centerline = active.longAxis.bundle.centerline; this.applyShortAxis(centerline, cursorMm); this.pushCrosshair(centerline, cursorMm, this.recentreOnCursor); this.applyLongAxisCamera(active.longAxis); } // Change the slice and restore it in one tick: only the final frame paints, but the MTime // advances, so the engine cannot skip the GPU render and the on-screen copy. repaintShortAxis(centerline, cursorMm) { const deltaMm = cursorMm + 1 <= centerline.totalLength ? 1 : -1; this.applyShortAxis(centerline, cursorMm + deltaMm); this.applyShortAxis(centerline, cursorMm); } // The one place the cross-section camera moves, so the overlay has one thing to watch. applyShortAxis(centerline, distanceMm) { const handle = this.active?.shortAxis.handle; if (!handle) return; handle.apply(centerline, distanceMm); this.shortAxisCameraVersion.update(version => version + 1); } applyRoll(rollRad) { const active = this.active; if (!active) return; (0,_spline_to_centerline__WEBPACK_IMPORTED_MODULE_17__.applyCenterlineRoll)(active.longAxis.bundle.centerline, rollRad); active.longAxis.viewport.requestRender(); } currentRollRad() { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.deg2rad)(this.session.rotationDeg()); } tearDown() { if (!this.active) return; const { enabledRoles, longAxis } = this.active; this.active = undefined; // Dispose the owned renderer before disabling the carrier it rides on. The mapper // and its private inputs go too, or their GL textures outlive the session. longAxis.viewport.dispose(); deleteVtkObject(longAxis.bundle.actor); deleteVtkObject(longAxis.bundle.mapper); deleteVtkObject(longAxis.bundle.centerline.polyData); deleteVtkObject(longAxis.imageData); for (const role of enabledRoles) this.engine.disable(_cpr_config__WEBPACK_IMPORTED_MODULE_11__.CPR_CARRIER_VIEWPORT_IDS[role]); this.centerline.set(undefined); // A commit whose rebuild never arrived must not snap the next session's cursor. this.pendingSnapWorld = undefined; this.releaseControlPoint(); this.ribbonFraming.set(undefined); this.desiredLayout.set(undefined); } pushCrosshair(centerline, distance, recentre) { const sample = (0,_spline_to_centerline__WEBPACK_IMPORTED_MODULE_17__.sampleCenterlineAt)(centerline, distance); if (!sample) return; const position = [sample.position[0], sample.position[1], sample.position[2]]; // Pan first: `updateIntersection` separates the two, so the isocenter must already be set. if (recentre) this.viewportStore.updateIsoCenter(position); this.viewportStore.updateIntersection(position); } getHost(viewportId) { return this.engine.getViewport(viewportId); } resolvePrimaryVolume() { const activeId = this.activeVolumeId(); const volume = activeId ? _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_3__["default"].getVolume(activeId) : (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.getPrimaryImageVolume)(); if (!volume?.imageData) return undefined; return { imageData: volume.imageData, volumeId: volume.volumeId }; } static ɵfac = function CprService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CprService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: CprService, factory: CprService.ɵfac }); } function longAxisAspect(host) { const width = host.canvas?.width ?? 1; const height = host.canvas?.height ?? 1; return height > 0 ? width / height : 1; } // `.delete()` is the vtk runtime method but isn't always on the typed surface. function deleteVtkObject(object) { object?.delete?.(); } /***/ }, /***/ 3832 /*!**************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cross-section-cut-line.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ cutLineGeometry: () => (/* binding */ cutLineGeometry), /* harmony export */ pointerAngleDeg: () => (/* binding */ pointerAngleDeg) /* harmony export */ }); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./cpr-config */ 17924); /** * The cross-section's cut-line indicator: where the ribbon's rotated plane cuts * this slice. The short-axis camera is framed from the same centerline frame the * roll composes onto — screen-right is the zero-roll lateral, screen-up the * frame's up — so the on-screen angle IS the roll, no world math needed. */ function cutLineGeometry(box, rotationDeg) { const centerX = box.width / 2; const centerY = box.height / 2; const rollRad = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_0__.deg2rad)(rotationDeg); // Screen y runs down, so a positive roll turns the line counter-clockwise. const dx = Math.cos(rollRad); const dy = -Math.sin(rollRad); // The camera shows SHORT_AXIS_FOV_MM over the box height; reach past the corners. const gapHalf = _cpr_config__WEBPACK_IMPORTED_MODULE_1__.CURSOR_GAP_MM / 2 * (box.height / _cpr_config__WEBPACK_IMPORTED_MODULE_1__.SHORT_AXIS_FOV_MM); const reach = Math.hypot(box.width, box.height) / 2; const segment = (from, to) => ({ x1: centerX + dx * from, x2: centerX + dx * to, y1: centerY + dy * from, y2: centerY + dy * to }); return { gapFill: segment(-gapHalf, gapHalf), segments: [segment(-reach, -gapHalf), segment(gapHalf, reach)] }; } /** The pointer's angle about the view centre, in the cut-line's degree convention. */ function pointerAngleDeg(box, x, y) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_0__.rad2deg)(Math.atan2(box.height / 2 - y, x - box.width / 2)); } /***/ }, /***/ 54776 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/cross-section-nodes.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ centerlineDistances: () => (/* binding */ centerlineDistances), /* harmony export */ inPlaneDragTarget: () => (/* binding */ inPlaneDragTarget), /* harmony export */ nearPlaneNodeIndices: () => (/* binding */ nearPlaneNodeIndices), /* harmony export */ planeOffsetMm: () => (/* binding */ planeOffsetMm) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Pure geometry behind the cross-section's control-point handles: which points are near * enough to the slice to show, where a dragged one lands, and where each sits along the arc. */ /** Signed distance from the slice plane along its normal, in millimetres. */ function planeOffsetMm(point, focalPoint, normal) { const offset = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.subtract(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), point, focalPoint); return gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dot(offset, gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), normal)); } /** The control points that get a handle: an off-plane one would drag with invisible depth error. */ function nearPlaneNodeIndices(input) { const { focalPoint, grabbedIndex, normal, points, toleranceMm } = input; const indices = []; for (const [index, point] of points.entries()) { const near = Math.abs(planeOffsetMm(point, focalPoint, normal)) < toleranceMm; if (near || index === grabbedIndex) indices.push(index); } return indices; } /** * Where a dragged control point lands: the pointer's position on the view plane, pushed back * out to the depth the point already had — a drag must never move a point through the slice. */ function inPlaneDragTarget(input) { const { nodePosition, normal, onPlane } = input; const unitNormal = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.normalize(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), normal); const depth = planeOffsetMm(nodePosition, onPlane, normal); return [onPlane[0] + unitNormal[0] * depth, onPlane[1] + unitNormal[1] * depth, onPlane[2] + unitNormal[2] * depth]; } /** * Arc distance of each control point. Always pass `CenterlineData.positions`, never * `getSplinePath(spline)`: the sampler reverses a bottom-up path, so spline-path distance * can run backwards against `cursorMm`. */ function centerlineDistances(positions, points) { return points.map(point => (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.calculateDistanceOnPath)(positions, point)); } /***/ }, /***/ 87242 /*!******************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/grid-fractions.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MIN_TRACK_SHARE: () => (/* binding */ MIN_TRACK_SHARE), /* harmony export */ WORKSPACE_GUTTER_PX: () => (/* binding */ WORKSPACE_GUTTER_PX), /* harmony export */ availableTrackPx: () => (/* binding */ availableTrackPx), /* harmony export */ resizeTracks: () => (/* binding */ resizeTracks), /* harmony export */ trackList: () => (/* binding */ trackList), /* harmony export */ trackSharePercent: () => (/* binding */ trackSharePercent) /* harmony export */ }); /** Grid track fractions for the CPR workspace and the drag math that keeps them valid. */ /** Gutter between workspace panels, in px — the `p-splitter` gutter size the grid replaced. */ const WORKSPACE_GUTTER_PX = 4; /** Smallest share of a track list one panel may keep; parity with the old `p-splitter` `minSizes: 5`. */ const MIN_TRACK_SHARE = 0.05; /** A `grid-template-*` value: fraction tracks separated by fixed gutter tracks for the drag handles. */ function trackList(fractions) { return fractions.map(fraction => `minmax(0,${fraction}fr)`).join(` ${WORKSPACE_GUTTER_PX}px `); } /** The px the fraction tracks share, i.e. the container minus its gutter tracks. */ function availableTrackPx(containerPx, trackCount) { return Math.max(0, containerPx - Math.max(0, trackCount - 1) * WORKSPACE_GUTTER_PX); } /** The share of the whole track list held before the boundary, in percent — for ARIA. */ function trackSharePercent(fractions, boundary) { const total = fractions.reduce((sum, fraction) => sum + fraction, 0); let before = 0; for (let index = 0; index <= boundary; index++) before += fractions[index] ?? 0; return total > 0 ? Math.round(100 * before / total) : 50; } /** * Move `deltaPx` across the boundary between tracks `boundary` and `boundary + 1`, as * `p-splitter` did: only the two adjacent tracks trade, neither drops below * `MIN_TRACK_SHARE`, and the fraction total is preserved. */ function resizeTracks(fractions, boundary, deltaPx, availablePx) { const next = [...fractions]; const before = fractions[boundary]; const after = fractions[boundary + 1]; const total = fractions.reduce((sum, fraction) => sum + fraction, 0); if (before === undefined || after === undefined || total <= 0 || availablePx <= 0) return next; if (deltaPx === 0) return next; const pairFraction = before + after; const pairPx = availablePx * (pairFraction / total); const minPx = availablePx * MIN_TRACK_SHARE; if (pairPx < minPx * 2) return next; const startPx = availablePx * (before / total); const movedPx = Math.min(Math.max(startPx + deltaPx, minPx), pairPx - minPx); next[boundary] = pairFraction * (movedPx / pairPx); next[boundary + 1] = pairFraction - next[boundary]; return next; } /***/ }, /***/ 51984 /*!********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/long-axis-camera.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MAX_RIBBON_ZOOM: () => (/* binding */ MAX_RIBBON_ZOOM), /* harmony export */ clampRibbonZoom: () => (/* binding */ clampRibbonZoom), /* harmony export */ fitParallelScale: () => (/* binding */ fitParallelScale), /* harmony export */ followAxis: () => (/* binding */ followAxis), /* harmony export */ frameLongAxis: () => (/* binding */ frameLongAxis) /* harmony export */ }); /* harmony import */ var _ribbon_projection__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ribbon-projection */ 94212); const MAX_RIBBON_ZOOM = 8; function clampRibbonZoom(zoom) { if (!Number.isFinite(zoom)) return 1; return Math.min(MAX_RIBBON_ZOOM, Math.max(1, zoom)); } /** * Half-height that fits the whole ribbon, with a 2% margin: the larger of what the * arc length needs and what the radial width needs, given which axis each occupies on screen. */ function fitParallelScale(input) { const aspect = input.aspect > 0 ? input.aspect : 1; const halfWidth = input.ribbonWidthMm / 2; const fit = input.orientation === 'vertical' ? Math.max(input.ribbonLengthMm / 2, halfWidth / aspect) : Math.max(halfWidth, input.ribbonLengthMm / (2 * aspect)); return fit * 1.02; } function frameLongAxis(input) { const aspect = input.aspect > 0 ? input.aspect : 1; const vertical = input.orientation === 'vertical'; const halfWidth = input.ribbonWidthMm / 2; const parallelScale = fitParallelScale(input) / clampRibbonZoom(input.zoom); // parallelScale is always the on-screen vertical half-extent; which ribbon axis that // covers depends on the roll. const alongHalf = vertical ? parallelScale : parallelScale * aspect; const acrossHalf = vertical ? parallelScale * aspect : parallelScale; return { focalX: followAxis(input.previousFocal?.x, halfWidth, acrossHalf, input.ribbonWidthMm), focalY: followAxis(input.previousFocal?.y, (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_0__.arcToWorldY)(input.ribbonLengthMm, input.cursorMm), alongHalf, input.ribbonLengthMm), parallelScale, // Rolling viewUp onto -x puts arc length across the screen, distal left to proximal right. viewUp: vertical ? [0, 1, 0] : [-1, 0, 0] }; } /** * Keep `target` in view along one axis: centred while everything fits, otherwise held * inside a dead-zone so the view only scrolls once the cursor nears an edge. */ function followAxis(previous, target, halfExtent, length) { if (halfExtent >= length / 2) return length / 2; const clamp = value => Math.min(Math.max(value, halfExtent), length - halfExtent); const focal = clamp(previous ?? target); const deadZoneHalf = 0.6 * halfExtent; const offset = target - focal; if (Math.abs(offset) <= deadZoneHalf) return clamp(focal); return clamp(target - Math.sign(offset) * deadZoneHalf); } /***/ }, /***/ 36955 /*!*****************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/ribbon-cursor.ts ***! \*****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ cursorCrossBar: () => (/* binding */ cursorCrossBar) /* harmony export */ }); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _ribbon_projection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ribbon-projection */ 94212); /** * The cursor cross-bar's canvas geometry: a line perpendicular to the arc at the * cursor, split around a central gap so the anatomy stays visible; the gap itself * carries a faint fill so the line reads as one. */ function cursorCrossBar(framing, box, cursorMm) { const half = framing.ribbonWidthMm / 2; const gapHalf = Math.min(_cpr_config__WEBPACK_IMPORTED_MODULE_0__.CURSOR_GAP_MM / 2, half); const segment = (from, to) => { const [x1, y1] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_1__.ribbonToCanvas)(framing, box, { d: cursorMm, lambda: from }); const [x2, y2] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_1__.ribbonToCanvas)(framing, box, { d: cursorMm, lambda: to }); return { x1, x2, y1, y2 }; }; return { gapFill: segment(-gapHalf, gapHalf), segments: [segment(-half, -gapHalf), segment(gapHalf, half)] }; } /***/ }, /***/ 61193 /*!*******************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/ribbon-gestures.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ STILL_CLICK_MAX_PX: () => (/* binding */ STILL_CLICK_MAX_PX), /* harmony export */ exceedsStillClick: () => (/* binding */ exceedsStillClick), /* harmony export */ normalizeWheelDeltaY: () => (/* binding */ normalizeWheelDeltaY), /* harmony export */ releaseCapturedPointer: () => (/* binding */ releaseCapturedPointer), /* harmony export */ wheelCursorStepMm: () => (/* binding */ wheelCursorStepMm) /* harmony export */ }); /** * Gesture math for the ribbon overlay: the plain-wheel cursor step and the * still-click discriminator (a press that never strays past the threshold jumps * the cursor; one that does becomes a rotation drag). */ /** Movement beyond this is a drag; at or under it, releasing counts as a click. */ const STILL_CLICK_MAX_PX = 3; /** What a line/page-mode notch reads as, in px — the classic mouse pixel delta. */ const NOTCH_EQUIVALENT_PX = 100; /** The step math assumes pixel deltas; line/page modes deliver ~±3 per notch. */ function normalizeWheelDeltaY(deltaY, deltaMode) { return deltaMode === WheelEvent.DOM_DELTA_PIXEL ? deltaY : Math.sign(deltaY) * NOTCH_EQUIVALENT_PX; } const WHEEL_DELTA_CAP = 50; const WHEEL_STEP_MM_PER_DELTAY = 0.02; const WHEEL_SHIFT_MULTIPLIER = 5; /** * Plain-wheel cursor nudge: ~1 mm per mouse notch, capped per event so a fast * wheel cannot jump, shift for coarse steps. Wheel down advances the cursor distally. */ function wheelCursorStepMm(deltaY, shiftKey) { const capped = Math.max(-WHEEL_DELTA_CAP, Math.min(WHEEL_DELTA_CAP, deltaY)); return capped * WHEEL_STEP_MM_PER_DELTAY * (shiftKey ? WHEEL_SHIFT_MULTIPLIER : 1); } function exceedsStillClick(startX, startY, x, y) { return Math.hypot(x - startX, y - startY) > STILL_CLICK_MAX_PX; } /** Release only a capture the target actually holds; a bare release can throw. */ function releaseCapturedPointer(event) { const target = event.target; if (target.hasPointerCapture?.(event.pointerId)) target.releasePointerCapture(event.pointerId); } /***/ }, /***/ 94212 /*!*********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/ribbon-projection.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ arcToWorldY: () => (/* binding */ arcToWorldY), /* harmony export */ canvasToRibbon: () => (/* binding */ canvasToRibbon), /* harmony export */ pxPerMm: () => (/* binding */ pxPerMm), /* harmony export */ ribbonToCanvas: () => (/* binding */ ribbonToCanvas) /* harmony export */ }); /** * CSS pixels per ribbon millimetre. parallelScale is the on-screen vertical * half-extent in mm, whichever orientation is showing. */ function pxPerMm(framing, box) { const height = box.height > 0 ? box.height : 1; const parallelScale = framing.parallelScale > 0 ? framing.parallelScale : 1; return height / (2 * parallelScale); } /** * Arc length ↔ the mapper's world y: it stacks its quads at `totalHeight - distance`, so * d = 0 sits at ribbonLengthMm and the arc descends. Self-inverse. */ function arcToWorldY(ribbonLengthMm, d) { return ribbonLengthMm - d; } function ribbonToCanvas(framing, box, point) { const scale = pxPerMm(framing, box); const x = framing.ribbonWidthMm / 2 + point.lambda - framing.focalX; const y = arcToWorldY(framing.ribbonLengthMm, point.d) - framing.focalY; // Screen axes follow the camera roll: vertical is viewUp +y (arc up the screen), // horizontal rolls viewUp onto -x (arc across the screen, lateral down it). if (framing.orientation === 'vertical') { return [box.width / 2 + x * scale, box.height / 2 - y * scale]; } return [box.width / 2 + y * scale, box.height / 2 + x * scale]; } function canvasToRibbon(framing, box, xPx, yPx) { const scale = pxPerMm(framing, box); const vertical = framing.orientation === 'vertical'; const x = (vertical ? xPx - box.width / 2 : yPx - box.height / 2) / scale; const y = (vertical ? box.height / 2 - yPx : xPx - box.width / 2) / scale; return { d: arcToWorldY(framing.ribbonLengthMm, framing.focalY + y), lambda: framing.focalX + x - framing.ribbonWidthMm / 2 }; } /***/ }, /***/ 15701 /*!****************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/ribbon-ruler.ts ***! \****************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ projectRulerTick: () => (/* binding */ projectRulerTick), /* harmony export */ rulerTicks: () => (/* binding */ rulerTicks) /* harmony export */ }); /* harmony import */ var _ribbon_projection__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ribbon-projection */ 94212); /** * Arc-length ruler for the ribbon overlay: tick generation and placement at the * ruler edge — minor ticks every 10 mm, labeled majors every 50 mm, seam ticks * marking a closed spline's wrap point at both ribbon ends. */ const MINOR_SPACING_MM = 10; const MAJOR_SPACING_MM = 50; const MINOR_INSET_PX = 5; const MAJOR_INSET_PX = 10; const SEAM_INSET_PX = 14; const LABEL_INSET_PX = 14; const LABEL_BASELINE_OFFSET_PX = 3; function rulerTicks(lengthMm, closed) { const ticks = []; for (let d = 0; d <= lengthMm; d += MINOR_SPACING_MM) { const major = d % MAJOR_SPACING_MM === 0; ticks.push({ d, label: major ? `${d}` : undefined, major, seam: false }); } if (closed) { ticks.push({ d: 0, label: undefined, major: true, seam: true }, { d: lengthMm, label: undefined, major: true, seam: true }); } return ticks; } function tickInsetPx(tick) { if (tick.seam) return SEAM_INSET_PX; return tick.major ? MAJOR_INSET_PX : MINOR_INSET_PX; } /** Place a tick at the ruler edge, inset into the ribbon across the arc's axis. */ function projectRulerTick(framing, box, tick) { const [x, y] = (0,_ribbon_projection__WEBPACK_IMPORTED_MODULE_0__.ribbonToCanvas)(framing, box, { d: tick.d, lambda: -framing.ribbonWidthMm / 2 }); const inset = tickInsetPx(tick); const vertical = framing.orientation === 'vertical'; return { ...tick, labelX: vertical ? x + LABEL_INSET_PX : x, labelY: (vertical ? y : y + LABEL_INSET_PX) + LABEL_BASELINE_OFFSET_PX, x1: x, x2: vertical ? x + inset : x, y1: y, y2: vertical ? y : y + inset }; } /***/ }, /***/ 9091 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/short-axis-viewport.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ startShortAxisViewport: () => (/* binding */ startShortAxisViewport) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _cpr_config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./cpr-config */ 17924); /* harmony import */ var _spline_to_centerline__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./spline-to-centerline */ 46815); function toPoint3(values) { return [values[0] ?? 0, values[1] ?? 0, values[2] ?? 0]; } function startShortAxisViewport(_x) { return _startShortAxisViewport.apply(this, arguments); } function _startShortAxisViewport() { _startShortAxisViewport = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (arguments_) { const { container, engine, volumeId } = arguments_; yield engine.enable(container, { id: _cpr_config__WEBPACK_IMPORTED_MODULE_3__.CPR_CARRIER_VIEWPORT_IDS.crossSection, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportType.ORTHOGRAPHIC, volumeId }); const viewport = engine.getViewport(_cpr_config__WEBPACK_IMPORTED_MODULE_3__.CPR_CARRIER_VIEWPORT_IDS.crossSection); function apply(centerline, distance) { const sample = (0,_spline_to_centerline__WEBPACK_IMPORTED_MODULE_4__.sampleCenterlineAt)(centerline, distance); if (!sample || !viewport) return; const focalPoint = toPoint3(sample.position); const normal = toPoint3(sample.tangent); // vtk derives viewPlaneNormal from (position − focalPoint), so set position // explicitly along the tangent — setting focalPoint alone keeps the stale // position and flips the normal when the focal point scrolls past it. const current = viewport.getCamera?.(); const camDistribution = current?.position && current?.focalPoint ? gl_matrix__WEBPACK_IMPORTED_MODULE_1__.distance(current.position, current.focalPoint) || _cpr_config__WEBPACK_IMPORTED_MODULE_3__.SHORT_AXIS_FOV_MM * 2 : _cpr_config__WEBPACK_IMPORTED_MODULE_3__.SHORT_AXIS_FOV_MM * 2; const cameraPosition = [focalPoint[0] + normal[0] * camDistribution, focalPoint[1] + normal[1] * camDistribution, focalPoint[2] + normal[2] * camDistribution]; viewport.setCamera({ focalPoint, parallelScale: _cpr_config__WEBPACK_IMPORTED_MODULE_3__.SHORT_AXIS_FOV_MM / 2, position: cameraPosition, viewUp: toPoint3(sample.viewUp) }); viewport.render(); } function plane() { const camera = viewport?.getCamera(); if (!camera?.focalPoint || !camera?.viewPlaneNormal) return undefined; return { focalPoint: toPoint3(camera.focalPoint), normal: toPoint3(camera.viewPlaneNormal) }; } function worldToCanvas(world) { const canvas = viewport?.worldToCanvas(toPoint3(world)); return canvas ? [canvas[0], canvas[1]] : undefined; } function canvasToWorld(canvas) { const world = viewport?.canvasToWorld(canvas); return world ? toPoint3(world) : undefined; } apply(arguments_.centerline, arguments_.initialDistance); // Wheel scrubbing lives on the cross-section overlay; disabling the carrier // viewport is `CprService`'s job — it owns the role registry. return { apply, canvasToWorld, plane, worldToCanvas }; }); return _startShortAxisViewport.apply(this, arguments); } /***/ }, /***/ 46815 /*!************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/cpr/spline-to-centerline.ts ***! \************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CPR_ORIENTATION_ARRAY_NAME: () => (/* binding */ CPR_ORIENTATION_ARRAY_NAME), /* harmony export */ applyCenterlineRoll: () => (/* binding */ applyCenterlineRoll), /* harmony export */ frameWithRoll: () => (/* binding */ frameWithRoll), /* harmony export */ pickUpAxis: () => (/* binding */ pickUpAxis), /* harmony export */ sampleCenterlineAt: () => (/* binding */ sampleCenterlineAt), /* harmony export */ splineToCenterline: () => (/* binding */ splineToCenterline) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Common/Core/DataArray */ 40928); /* harmony import */ var _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/PolyData */ 95765); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! gl-matrix */ 23988); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! gl-matrix */ 85648); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /** * Convert a Spline into the inputs `vtkImageCPRMapper` needs: a `vtkPolyData` * centerline with a per-point quaternion `Orientation` PointData array, a * cumulative arc-length lookup, and the per-point orientation frames. * * Frames are parallel-transported (rotation-minimizing) along the path — seeded * from a world-axis projection at the first point, then propagated by the minimal * rotation between consecutive tangents — so the user's roll (composed about the * local tangent into the orientation array) sweeps no seams on tortuous curves. * Frame convention: columns [lateral | up | tangent], i.e. local Z is the tangent * and local X is the mapper's sampling direction. */ const CPR_ORIENTATION_ARRAY_NAME = 'Orientation'; function splineToCenterline(spline, rollRad = 0) { const positions = orientPositionsForCpr((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_5__.getSplinePath)(spline)); const polyData = buildCenterlinePolyData(positions); const { cumulativeDistances, totalLength } = buildCumulativeDistances(positions); const frames = buildParallelTransportFrames(positions); distributeClosedPathTwist(positions, frames, cumulativeDistances, totalLength); writeOrientationArray(polyData, frames, rollRad); return { cumulativeDistances, frames, polyData, positions, totalLength }; } /** Re-compose the Orientation array for a new roll, in place on the live polydata. */ function applyCenterlineRoll(centerline, rollRad) { writeOrientationArray(centerline.polyData, centerline.frames, rollRad); } /** Compose a roll about the local tangent (local Z) onto a frame quaternion. */ function frameWithRoll(out, frame, rollRad) { const roll = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.setAxisAngle(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), [0, 0, 1], rollRad); return gl_matrix__WEBPACK_IMPORTED_MODULE_3__.multiply(out, frame, roll); } // The mapper draws d = 0 at the top of the ribbon, where the proximal end belongs. For these // vessels that is the superior end, so keep the greater Z first however the spline was drawn. function orientPositionsForCpr(path) { const first = path[0]; const last = path.at(-1); if (first && last && path.length >= 2 && first[2] < last[2]) { return path.toReversed(); } return [...path]; } function buildCenterlinePolyData(positions) { const nPoints = positions.length; const flat = new Float64Array(nPoints * 3); for (let index = 0; index < nPoints; index++) { const p = positions[index]; if (!p) continue; flat[index * 3] = p[0]; flat[index * 3 + 1] = p[1]; flat[index * 3 + 2] = p[2]; } const lines = new Uint32Array(nPoints + 1); lines[0] = nPoints; for (let index = 0; index < nPoints; index++) lines[index + 1] = index; const polyData = _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance(); polyData.getPoints().setData(flat, 3); polyData.getLines().setData(lines); return polyData; } function buildCumulativeDistances(positions) { const nPoints = positions.length; const cumulativeDistances = new Float32Array(nPoints); let total = 0; for (let index = 1; index < nPoints; index++) { const previous = positions[index - 1]; const current = positions[index]; if (!previous || !current) continue; total += gl_matrix__WEBPACK_IMPORTED_MODULE_4__.dist(previous, current); cumulativeDistances[index] = total; } return { cumulativeDistances, totalLength: total }; } /** Central-difference unit tangent at `index`; false when degenerate. */ function centralTangent(out, positions, index) { const previous = positions[Math.max(0, index - 1)]; const next = positions[Math.min(positions.length - 1, index + 1)]; if (!previous || !next) return false; gl_matrix__WEBPACK_IMPORTED_MODULE_4__.sub(out, next, previous); if (gl_matrix__WEBPACK_IMPORTED_MODULE_4__.length(out) < 1e-9) return false; gl_matrix__WEBPACK_IMPORTED_MODULE_4__.normalize(out, out); return true; } /** The first frame: world-axis-projected up, exactly the pre-transport construction. */ function seedFrame(out, T) { const up = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(); pickUpAxis(up, T); const unitY = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_4__.scaleAndAdd(unitY, up, T, -gl_matrix__WEBPACK_IMPORTED_MODULE_4__.dot(up, T)); gl_matrix__WEBPACK_IMPORTED_MODULE_4__.normalize(unitY, unitY); const unitX = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(); gl_matrix__WEBPACK_IMPORTED_MODULE_4__.cross(unitX, unitY, T); gl_matrix__WEBPACK_IMPORTED_MODULE_4__.normalize(unitX, unitX); // gl-matrix mat3 is column-major, so m[0..2]=col0, m[3..5]=col1, m[6..8]=col2. const m = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(); m[0] = unitX[0]; m[1] = unitX[1]; m[2] = unitX[2]; m[3] = unitY[0]; m[4] = unitY[1]; m[5] = unitY[2]; m[6] = T[0]; m[7] = T[1]; m[8] = T[2]; gl_matrix__WEBPACK_IMPORTED_MODULE_3__.fromMat3(out, m); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.normalize(out, out); } function buildParallelTransportFrames(positions) { const n = positions.length; const frames = new Float32Array(n * 4); const T = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(); const previousT = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(); const q = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.fromValues(0, 0, 0, 1); const step = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); let seeded = false; for (let index = 0; index < n; index++) { // A degenerate tangent carries the neighbouring frame forward unchanged. if (centralTangent(T, positions, index)) { if (seeded) { gl_matrix__WEBPACK_IMPORTED_MODULE_3__.rotationTo(step, previousT, T); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.multiply(q, step, q); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.normalize(q, q); } else { seedFrame(q, T); seeded = true; // Points before the first usable tangent share the seed frame. for (let back = 0; back < index; back++) writeQuat(frames, back, q); } gl_matrix__WEBPACK_IMPORTED_MODULE_4__.copy(previousT, T); } writeQuat(frames, index, q); } return frames; } function writeQuat(target, index, q) { target[index * 4] = q[0]; target[index * 4 + 1] = q[1]; target[index * 4 + 2] = q[2]; target[index * 4 + 3] = q[3]; } function readQuat(out, source, index) { return gl_matrix__WEBPACK_IMPORTED_MODULE_3__.set(out, source[index * 4], source[index * 4 + 1], source[index * 4 + 2], source[index * 4 + 3]); } /** * Transport around a closed path returns the end frame rotated about the shared * tangent (the path's holonomy). A closed spline's path repeats its first point * at the end, so without a correction the two ribbon ends disagree at the seam. * Unroll the residual twist proportionally along the arc. */ function distributeClosedPathTwist(positions, frames, cumulativeDistances, totalLength) { const n = positions.length; const first = positions[0]; const last = positions[n - 1]; if (n < 3 || totalLength <= 0 || !first || !last) return; if (gl_matrix__WEBPACK_IMPORTED_MODULE_4__.dist(first, last) > 1e-6) return; const seed = readQuat(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), frames, 0); const end = readQuat(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), frames, n - 1); const relative = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.multiply(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), gl_matrix__WEBPACK_IMPORTED_MODULE_3__.invert(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), end), seed); if (relative[3] < 0) gl_matrix__WEBPACK_IMPORTED_MODULE_3__.scale(relative, relative, -1); // The twist half of a swing-twist split about local Z; the swing part is only // the endpoints' one-sided tangent estimates disagreeing, and stays. const twist = 2 * Math.atan2(relative[2], relative[3]); if (Math.abs(twist) < 1e-9) return; const roll = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); const q = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); for (let index = 1; index < n; index++) { const fraction = cumulativeDistances[index] / totalLength; gl_matrix__WEBPACK_IMPORTED_MODULE_3__.setAxisAngle(roll, [0, 0, 1], twist * fraction); readQuat(q, frames, index); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.multiply(q, q, roll); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.normalize(q, q); writeQuat(frames, index, q); } } function writeOrientationArray(polyData, frames, rollRad) { const n = frames.length / 4; const orientations = new Float32Array(n * 4); const roll = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.setAxisAngle(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), [0, 0, 1], rollRad); const frame = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); const q = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); const previous = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(); for (let index = 0; index < n; index++) { gl_matrix__WEBPACK_IMPORTED_MODULE_3__.set(frame, frames[index * 4], frames[index * 4 + 1], frames[index * 4 + 2], frames[index * 4 + 3]); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.multiply(q, frame, roll); // The mapper interpolates raw components between points; a sign flip would // sweep the interpolant through zero, so keep neighbours in one hemisphere. if (index > 0 && gl_matrix__WEBPACK_IMPORTED_MODULE_3__.dot(q, previous) < 0) gl_matrix__WEBPACK_IMPORTED_MODULE_3__.scale(q, q, -1); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.copy(previous, q); writeQuat(orientations, index, q); } const pointData = polyData.getPointData(); const existing = pointData.getArrayByName?.(CPR_ORIENTATION_ARRAY_NAME); if (existing) { existing.setData(orientations); } else { pointData.addArray(_kitware_vtk_js_Common_Core_DataArray__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance({ name: CPR_ORIENTATION_ARRAY_NAME, numberOfComponents: 4, values: orientations })); } polyData.modified(); } function sampleCenterlineAt(centerline, distance, rollRad = 0) { const { cumulativeDistances, frames, positions, totalLength } = centerline; const n = positions.length; if (n < 2) return undefined; const clamped = Math.max(0, Math.min(distance, totalLength)); let index1 = 1; while (index1 < n && cumulativeDistances[index1] < clamped) index1++; if (index1 >= n) index1 = n - 1; const index0 = Math.max(0, index1 - 1); const d0 = cumulativeDistances[index0]; const d1 = cumulativeDistances[index1]; const segDelta = d1 - d0; const t = segDelta > 1e-9 ? (clamped - d0) / segDelta : 0; const p0 = positions[index0]; const p1 = positions[index1]; if (!p0 || !p1) return undefined; const position = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.fromValues(p0[0] * (1 - t) + p1[0] * t, p0[1] * (1 - t) + p1[1] * t, p0[2] * (1 - t) + p1[2] * t); const q0 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.fromValues(frames[index0 * 4], frames[index0 * 4 + 1], frames[index0 * 4 + 2], frames[index0 * 4 + 3]); const q1 = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.fromValues(frames[index1 * 4], frames[index1 * 4 + 1], frames[index1 * 4 + 2], frames[index1 * 4 + 3]); if (gl_matrix__WEBPACK_IMPORTED_MODULE_3__.dot(q0, q1) < 0) gl_matrix__WEBPACK_IMPORTED_MODULE_3__.scale(q1, q1, -1); const q = gl_matrix__WEBPACK_IMPORTED_MODULE_3__.slerp(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), q0, q1, t); gl_matrix__WEBPACK_IMPORTED_MODULE_3__.normalize(q, q); const tangent = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.transformQuat(gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(), [0, 0, 1], q); const viewUp = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.transformQuat(gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(), [0, 1, 0], q); const rolled = rollRad === 0 ? q : frameWithRoll(gl_matrix__WEBPACK_IMPORTED_MODULE_3__.create(), q, rollRad); const lateral = gl_matrix__WEBPACK_IMPORTED_MODULE_4__.transformQuat(gl_matrix__WEBPACK_IMPORTED_MODULE_4__.create(), [1, 0, 0], rolled); return { lateral, position, tangent, viewUp }; } // Pick the world axis with the smallest component in T — the one most // orthogonal to T. Seeds the transported frame; avoids the degenerate frame from // a fixed-axis pick when T happens to align with that axis (e.g. the prototype's // hardcoded world-Z collapses on spine-aligned splines). Exported for testability. function pickUpAxis(out, T) { const absX = Math.abs(T[0]); const absY = Math.abs(T[1]); const absZ = Math.abs(T[2]); if (absX <= absY && absX <= absZ) { out[0] = 1; out[1] = 0; out[2] = 0; } else if (absY <= absX && absY <= absZ) { out[0] = 0; out[1] = 1; out[2] = 0; } else { out[0] = 0; out[1] = 0; out[2] = 1; } } /***/ }, /***/ 20974 /*!******************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/ct-popover.service.ts ***! \******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CtPopoverService: () => (/* binding */ CtPopoverService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./viewport-ids */ 85309); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./volume-viewer-orchestrator.service */ 66035); const customPresetGroup = { items: [], label: `${_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_WINDOW_PRESET.name.toUpperCase()} PRESET` }; const defaultPresetGroup = { items: [], label: 'DICOM PRESET' }; const tvctPresetGroup = { items: [], label: 'TVCT PRESET' }; class CtPopoverService { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_6__.getLogger)(CtPopoverService.name); viewerOrchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_8__.VolumeViewerOrchestrator); renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.renderSettingsStore); engine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.RenderingEngineService); seriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('', ...(ngDevMode ? [{ debugName: "seriesUid" }] : [])); get scalarRange() { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.getVolumeScalarRange)((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.getViewport)(this.engine.ENGINE_ID, _viewport_ids__WEBPACK_IMPORTED_MODULE_7__.VIEWPORT_IDS.AXIAL)); } getCtFormConfig() { const seriesWindow = this.viewerOrchestrator.seriesWindowState(this.seriesUid()); if (!seriesWindow) { this.log.warn(`Series window state not found for series UID: ${this.seriesUid()}`); return []; } const [scalarMin, scalarMax] = this.scalarRange; const windowSettings = this.renderSettingsStore.windowSettings(); const option = preset => ({ label: `${preset.name} ${preset.level}/${preset.width}`, value: preset.name }); // eslint-disable-next-line sonarjs/cyclomatic-complexity const options = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { customPresetGroup.items = []; defaultPresetGroup.items = []; tvctPresetGroup.items = []; for (const { name } of this.renderSettingsStore.windowPresets()) { const volumeRenderPresets = this.renderSettingsStore.windowPresets(); const preset = volumeRenderPresets.find(preset => preset.name === name); if (name === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_WINDOW_PRESET.name && preset) { customPresetGroup.items = [...customPresetGroup.items, option(preset)]; } if (name.includes(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_PRESET_NAME) && preset) { defaultPresetGroup.items = [...defaultPresetGroup.items, option(preset)]; } if (!name.includes(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_PRESET_NAME) && name !== _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_WINDOW_PRESET.name && preset) { tvctPresetGroup.items = [...tvctPresetGroup.items, option(preset)]; } } return [customPresetGroup.items.length > 0 ? { ...customPresetGroup } : [], defaultPresetGroup.items.length > 0 ? { ...defaultPresetGroup } : [], tvctPresetGroup.items.length > 0 ? { ...tvctPresetGroup } : []]; }, ...(ngDevMode ? [{ debugName: "options" }] : [])); const config = [{ defaultValue: windowSettings.name, group: true, label: 'ctImageSettings.selectPreset', name: 'selectedPresetName', onChange: ctForm => { this.renderSettingsStore.selectWindowPreset(ctForm.selectedPresetName().value()); }, options, selectOptionsTemplate: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SelectOptionsTemplate.CT_SELECT_OPTIONS, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SELECT }, { defaultValue: windowSettings.width, label: 'ctImageSettings.windowWidth', max: Math.max(1, (scalarMax - scalarMin) * 2), min: 1, name: 'windowWidth', onChange: ctForm => { this.renderSettingsStore.updateCustomPreset({ width: ctForm.windowWidth().value() }); }, resetEvent: form => { const width = seriesWindow.defaultWindowWidth; this.renderSettingsStore.updateCustomPreset({ width }); form.windowWidth().value.set(width); }, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: windowSettings.level, label: 'ctImageSettings.windowLevel', max: scalarMax, min: scalarMin, name: 'windowLevel', onChange: ctForm => { this.renderSettingsStore.updateCustomPreset({ level: ctForm.windowLevel().value() }); }, resetEvent: form => { const level = seriesWindow.defaultWindowLevel; this.renderSettingsStore.updateCustomPreset({ level }); form.windowLevel().value.set(level); }, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }]; return config; } static ɵfac = function CtPopoverService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CtPopoverService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: CtPopoverService, factory: CtPopoverService.ɵfac }); } /***/ }, /***/ 50108 /*!***************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/endo-dev-panel/endo-dev-panel.component.ts ***! \***************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ EndoDevelopmentPanelComponent: () => (/* binding */ EndoDevelopmentPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_divider__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/divider */ 1432); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @angular/core */ 14975); const ENDO = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VolumeRenderingOption.ENDO]; class EndoDevelopmentPanelComponent { settings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.renderSettingsStore); orchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_9__.VolumeViewerOrchestrator); ENDO = ENDO; airTissueThreshold = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.airTissueThreshold, ...(ngDevMode ? [{ debugName: "airTissueThreshold" }] : [])); tissueBloodThreshold = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.tissueBloodThreshold, ...(ngDevMode ? [{ debugName: "tissueBloodThreshold" }] : [])); bloodCalciumThreshold = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.bloodCalciumThreshold, ...(ngDevMode ? [{ debugName: "bloodCalciumThreshold" }] : [])); opacityTransitionWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.opacityTransitionWidth, ...(ngDevMode ? [{ debugName: "opacityTransitionWidth" }] : [])); rgbTransitionWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.rgbTransitionWidth, ...(ngDevMode ? [{ debugName: "rgbTransitionWidth" }] : [])); ambient = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.ambient, ...(ngDevMode ? [{ debugName: "ambient" }] : [])); diffuse = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.diffuse, ...(ngDevMode ? [{ debugName: "diffuse" }] : [])); specular = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.specular, ...(ngDevMode ? [{ debugName: "specular" }] : [])); specularPower = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(ENDO.specularPower, ...(ngDevMode ? [{ debugName: "specularPower" }] : [])); constructor() { const initialSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.settings.volumeSettings()); if (initialSettings.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VolumeRenderingOption.ENDO) { this.airTissueThreshold.set(initialSettings.airTissueThreshold); this.tissueBloodThreshold.set(initialSettings.tissueBloodThreshold); this.bloodCalciumThreshold.set(initialSettings.bloodCalciumThreshold); this.opacityTransitionWidth.set(initialSettings.opacityTransitionWidth); this.rgbTransitionWidth.set(initialSettings.rgbTransitionWidth); this.ambient.set(initialSettings.ambient); this.diffuse.set(initialSettings.diffuse); this.specular.set(initialSettings.specular); this.specularPower.set(initialSettings.specularPower); } (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const airTissueThreshold = this.airTissueThreshold(); const tissueBloodThreshold = this.tissueBloodThreshold(); const bloodCalciumThreshold = this.bloodCalciumThreshold(); const opacityTransitionWidth = this.opacityTransitionWidth(); const rgbTransitionWidth = this.rgbTransitionWidth(); const ambient = this.ambient(); const diffuse = this.diffuse(); const specular = this.specular(); const specularPower = this.specularPower(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.settings.updateVolumeSettings({ airTissueThreshold, ambient, bloodCalciumThreshold, diffuse, opacityTransitionWidth, rgbTransitionWidth, specular, specularPower, tissueBloodThreshold })); }); } static ɵfac = function EndoDevelopmentPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EndoDevelopmentPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdefineComponent"]({ type: EndoDevelopmentPanelComponent, selectors: [["lib-endo-dev-panel"]], decls: 83, vars: 54, consts: [[1, "ring-surface-700", "bg-surface-900/95", "max-h-[80vh]", "w-[480px]", "overflow-y-auto", "rounded-lg", "p-4", "shadow-2xl", "ring-1"], [1, "text-color", "mb-3", "text-sm", "font-semibold"], [1, "text-surface-400", "mb-2", "text-xs", "tracking-wide", "uppercase"], [1, "grid", "grid-cols-[120px_1fr_44px_auto]", "items-center", "gap-2", "py-1"], [1, "text-muted-color", "text-right", "text-xs"], ["dataTestIdOverride", "endo-dev-panel-slider-air-tissue", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], [1, "text-surface-200", "text-right", "font-mono", "text-xs", "tabular-nums"], ["data-test-id", "endo-dev-panel-p-button-air-tissue-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["icon", "refresh"], ["dataTestIdOverride", "endo-dev-panel-slider-tissue-blood", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-tissue-blood-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-blood-calcium", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-blood-calcium-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-opacity-transition", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-opacity-transition-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-rgb-transition", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-rgb-transition-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], [1, "my-3"], ["dataTestIdOverride", "endo-dev-panel-slider-ambient", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-ambient-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-diffuse", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-diffuse-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-specular", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-specular-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "endo-dev-panel-slider-specular-power", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "endo-dev-panel-p-button-specular-power-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"]], template: function EndoDevelopmentPanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "div", 0)(1, "p", 1); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](2, "Endo Preset Tuner"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](3, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](4, "Thresholds (HU)"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](5, "div", 3)(6, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](7, "Air / Tissue"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](8, "lib-slider", 5); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_8_listener($event) { return ctx.airTissueThreshold.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](9, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](11, "p-button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_11_listener() { return ctx.airTissueThreshold.set(ctx.ENDO.airTissueThreshold); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](12, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](13, "div", 3)(14, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](15, "Tissue / Blood"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](16, "lib-slider", 9); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_16_listener($event) { return ctx.tissueBloodThreshold.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](17, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](18); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](19, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_19_listener() { return ctx.tissueBloodThreshold.set(ctx.ENDO.tissueBloodThreshold); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](20, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](21, "div", 3)(22, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](23, "Blood / Calcium"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](24, "lib-slider", 11); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_24_listener($event) { return ctx.bloodCalciumThreshold.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](25, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](26); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](27, "p-button", 12); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_27_listener() { return ctx.bloodCalciumThreshold.set(ctx.ENDO.bloodCalciumThreshold); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](28, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](29, "div", 3)(30, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](31, "Opacity Trans."); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](32, "lib-slider", 13); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_32_listener($event) { return ctx.opacityTransitionWidth.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](33, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](34); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](35, "p-button", 14); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_35_listener() { return ctx.opacityTransitionWidth.set(ctx.ENDO.opacityTransitionWidth); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](36, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](37, "div", 3)(38, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](39, "RGB Trans."); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](40, "lib-slider", 15); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_40_listener($event) { return ctx.rgbTransitionWidth.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](41, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](42); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](43, "p-button", 16); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_43_listener() { return ctx.rgbTransitionWidth.set(ctx.ENDO.rgbTransitionWidth); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](44, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](45, "p-divider", 17); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](46, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](47, "Lighting"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](48, "div", 3)(49, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](50, "Ambient"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](51, "lib-slider", 18); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_51_listener($event) { return ctx.ambient.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](52, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](53); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](54, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](55, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_55_listener() { return ctx.ambient.set(ctx.ENDO.ambient); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](56, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](57, "div", 3)(58, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](59, "Diffuse"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](60, "lib-slider", 20); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_60_listener($event) { return ctx.diffuse.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](61, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](62); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](63, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](64, "p-button", 21); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_64_listener() { return ctx.diffuse.set(ctx.ENDO.diffuse); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](65, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](66, "div", 3)(67, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](68, "Specular"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](69, "lib-slider", 22); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_69_listener($event) { return ctx.specular.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](70, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](71); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](72, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](73, "p-button", 23); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_73_listener() { return ctx.specular.set(ctx.ENDO.specular); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](74, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](75, "div", 3)(76, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](77, "Spec. Power"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](78, "lib-slider", 24); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function EndoDevelopmentPanelComponent_Template_lib_slider_sliderChanged_78_listener($event) { return ctx.specularPower.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](79, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](80); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](81, "p-button", 25); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function EndoDevelopmentPanelComponent_Template_p_button_onClick_81_listener() { return ctx.specularPower.set(ctx.ENDO.specularPower); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](82, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", -1024)("sliderMax", 0)("sliderStep", 1)("sliderValue", ctx.airTissueThreshold()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.airTissueThreshold(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", -200)("sliderMax", 500)("sliderStep", 1)("sliderValue", ctx.tissueBloodThreshold()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.tissueBloodThreshold(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 100)("sliderMax", ctx.orchestrator.volumeMaxPixelValue())("sliderStep", 1)("sliderValue", ctx.bloodCalciumThreshold()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.bloodCalciumThreshold(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 300)("sliderStep", 1)("sliderValue", ctx.opacityTransitionWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.opacityTransitionWidth(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 300)("sliderStep", 1)("sliderValue", ctx.rgbTransitionWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.rgbTransitionWidth(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](9); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.ambient()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](54, 45, ctx.ambient(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.diffuse()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](63, 48, ctx.diffuse(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.specular()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](72, 51, ctx.specular(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 1)("sliderMax", 128)("sliderStep", 1)("sliderValue", ctx.specularPower()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.specularPower(), " "); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.SliderComponent, primeng_button__WEBPACK_IMPORTED_MODULE_2__.Button, primeng_divider__WEBPACK_IMPORTED_MODULE_3__.Divider, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.IconComponent, primeng_tooltip__WEBPACK_IMPORTED_MODULE_4__.Tooltip, _angular_common__WEBPACK_IMPORTED_MODULE_0__.DecimalPipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 77335 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/map-viewport-name-to-id.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ mapViewportNameToId: () => (/* binding */ mapViewportNameToId) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./viewport-ids */ 85309); const mapViewportNameToId = viewportName => { const mapping = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportName.AXIAL]: _viewport_ids__WEBPACK_IMPORTED_MODULE_1__.VIEWPORT_IDS.AXIAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportName.CORONAL]: _viewport_ids__WEBPACK_IMPORTED_MODULE_1__.VIEWPORT_IDS.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportName.REFORMAT]: _viewport_ids__WEBPACK_IMPORTED_MODULE_1__.VIEWPORT_IDS.REFORMAT, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportName.SAGITTAL]: _viewport_ids__WEBPACK_IMPORTED_MODULE_1__.VIEWPORT_IDS.SAGITTAL }; return mapping[viewportName]; }; /***/ }, /***/ 1894 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/orientation-form-config.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ buildOrientationFormConfig: () => (/* binding */ buildOrientationFormConfig) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Builds the rotation-slider config (CC/RL/AX) for the universal settings popover. */ function buildOrientationFormConfig(getCurrent, update, onDragStart, onDragEnd) { const target = getCurrent(); if (!target) return []; const angulation = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationFromOrientation)(target.orientation); const setAxis = (axis, value, min, max) => { const current = getCurrent(); if (!current) return; const next = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.angulationFromOrientation)(current.orientation); next[axis] = Math.min(Math.max(value, min), max); update({ ...current, orientation: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.orientationFromAngulation)(next) }); }; const sliderField = (axis, label, min, max, valueFormatter) => ({ defaultValue: angulation[axis], label, max, min, name: axis, onChange: form => setAxis(axis, form[axis]().value(), min, max), onDragEnd, onDragStart, resetEvent: form => { setAxis(axis, 0, min, max); form[axis]().value.set(0); }, showValue: true, step: 1, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.SettingsPopoverField.SLIDER, valueFormatter, valueSuffix: '°' }); const config = [sliderField('cc', 'annotationMenu.editOrientation.craniocaudal', -90, 90, directionalAngle(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.formatCaudCran)), sliderField('rl', 'annotationMenu.editOrientation.raoLao', -180, 180, directionalAngle(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.formatRaoLao)), sliderField('ax', 'annotationMenu.editOrientation.axial', -180, 180)]; return config; } function directionalAngle(format) { return value => { const { direction, formattedValue } = format(Math.round(value)); return `${direction} ${formattedValue}`; }; } /***/ }, /***/ 21321 /*!*********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/provide-volume-viewer.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VOLUME_VIEWER_OPTIONS: () => (/* binding */ VOLUME_VIEWER_OPTIONS), /* harmony export */ provideVolumeViewer: () => (/* binding */ provideVolumeViewer) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _dicom_image_loader_dev__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../../dicom-image-loader-dev */ 99763); /* harmony import */ var _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../annotation-menu/annotation-menu-item.service */ 39860); /* harmony import */ var _annotation_menu_model_geometry_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../annotation-menu/model-geometry.service */ 27113); /* harmony import */ var _chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../chamber/chamber-menu/chamber-menu-item.service */ 44189); /* harmony import */ var _chamber_chamber_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../chamber/chamber.service */ 16592); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../colors/colors.service */ 39298); /* harmony import */ var _device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../device-sizing-chart/device-sizing-chart-dialog.service */ 26755); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _protocols_protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../protocols/protocol-creation-service/protocol-creation.service */ 88304); /* harmony import */ var _relative_measurements_relative_measurements_service__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../relative-measurements/relative-measurements.service */ 79408); /* harmony import */ var _s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../s-curve-relative-measurements/s-curve-relative-measurements.service */ 17464); /* harmony import */ var _sidebar_panels_services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../sidebar-panels/services/annotation-panel.service */ 56105); /* harmony import */ var _sidebar_panels_services_chamber_panel_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../sidebar-panels/services/chamber-panel.service */ 38164); /* harmony import */ var _camera_animation_service__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./camera-animation.service */ 76045); /* harmony import */ var _cpr_cpr_service__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./cpr/cpr.service */ 26144); /* harmony import */ var _ct_popover_service__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./ct-popover.service */ 20974); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./window-details/window-details.service */ 99360); // eslint-disable-next-line @nx/enforce-module-boundaries const VOLUME_VIEWER_OPTIONS = new _angular_core__WEBPACK_IMPORTED_MODULE_0__.InjectionToken('VOLUME_VIEWER_OPTIONS'); function provideVolumeViewer(options) { return [{ provide: VOLUME_VIEWER_OPTIONS, useValue: options }, { provide: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_4__.DICOM_IMAGE_LOADER, useValue: _dicom_image_loader_dev__WEBPACK_IMPORTED_MODULE_5__["default"] }, _colors_colors_service__WEBPACK_IMPORTED_MODULE_10__.ColorsService, _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_6__.AnnotationMenuItemService, _sidebar_panels_services_annotation_panel_service__WEBPACK_IMPORTED_MODULE_16__.AnnotationPanelService, _chamber_chamber_menu_chamber_menu_item_service__WEBPACK_IMPORTED_MODULE_8__.ChamberMenuItemService, _sidebar_panels_services_chamber_panel_service__WEBPACK_IMPORTED_MODULE_17__.ChamberPanelService, _chamber_chamber_service__WEBPACK_IMPORTED_MODULE_9__.ChamberService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.annotationStore, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.chamberStore, _camera_animation_service__WEBPACK_IMPORTED_MODULE_18__.CameraAnimationService, _cpr_cpr_service__WEBPACK_IMPORTED_MODULE_19__.CprService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.cprSessionStore, _ct_popover_service__WEBPACK_IMPORTED_MODULE_20__.CtPopoverService, _device_sizing_chart_device_sizing_chart_dialog_service__WEBPACK_IMPORTED_MODULE_11__.DeviceSizingChartDialogService, primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_1__.DialogService, _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_12__.InteractionModeService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.MeasurementService, _annotation_menu_model_geometry_service__WEBPACK_IMPORTED_MODULE_7__.ModelGeometryService, _protocols_protocol_creation_service_protocol_creation_service__WEBPACK_IMPORTED_MODULE_13__.ProtocolCreationService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.ProtocolFacade, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.protocolStore, _relative_measurements_relative_measurements_service__WEBPACK_IMPORTED_MODULE_14__.RelativeMeasurementsService, _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.RenderingEngineService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.renderSettingsStore, _s_curve_relative_measurements_s_curve_relative_measurements_service__WEBPACK_IMPORTED_MODULE_15__.SCurveRelativeMeasurementsService, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.sCurveStore, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.uiStore, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.viewportStore, _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.VolumeLoaderService, _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_21__.VolumeViewerOrchestrator, _tomoverse_store__WEBPACK_IMPORTED_MODULE_3__.volumeViewerStore, _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_22__.WindowDetailsService]; } /***/ }, /***/ 33032 /*!***********************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/render-quality-dev-panel/render-quality-dev-panel.component.ts ***! \***********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RenderQualityDevelopmentPanelComponent: () => (/* binding */ RenderQualityDevelopmentPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 14975); class RenderQualityDevelopmentPanelComponent { orchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_2__.VolumeViewerOrchestrator); static ɵfac = function RenderQualityDevelopmentPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RenderQualityDevelopmentPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵdefineComponent"]({ type: RenderQualityDevelopmentPanelComponent, selectors: [["lib-render-quality-dev-panel"]], decls: 9, vars: 5, consts: [[1, "ring-surface-700", "bg-surface-900/95", "w-[320px]", "rounded-lg", "p-4", "shadow-2xl", "ring-1"], [1, "text-color", "mb-3", "text-sm", "font-semibold"], [1, "grid", "grid-cols-[100px_1fr_44px]", "items-center", "gap-2", "py-1"], [1, "text-muted-color", "text-right", "text-xs"], ["dataTestIdOverride", "render-quality-dev-panel-slider-idle-quality", "name", "render-quality-idle-quality", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], [1, "text-surface-200", "text-right", "font-mono", "text-xs", "tabular-nums"]], template: function RenderQualityDevelopmentPanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](0, "div", 0)(1, "p", 1); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtext"](2, "Idle Render Quality"); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](3, "div", 2)(4, "span", 3); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtext"](5, "Max Quality"); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](6, "lib-slider", 4); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵlistener"]("sliderChanged", function RenderQualityDevelopmentPanelComponent_Template_lib_slider_sliderChanged_6_listener($event) { return ctx.orchestrator.idleImageQuality.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementStart"](7, "span", 5); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtext"](8); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵelementEnd"]()()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 100)("sliderStep", 1)("sliderValue", ctx.orchestrator.idleImageQuality()); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵtextInterpolate1"](" ", ctx.orchestrator.idleImageQuality(), " "); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_1__.SliderComponent], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 57669 /*!*****************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/s-curve-graph-popover.service.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ SCurveGraphPopoverService: () => (/* binding */ SCurveGraphPopoverService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); const FONT_SIZE_MIN = 6; const FONT_SIZE_MAX = 16; const LINE_WIDTH_MIN = 0.5; const LINE_WIDTH_MAX = 8; class SCurveGraphPopoverService { renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.renderSettingsStore); formConfig = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => [{ defaultValue: this.renderSettingsStore.sCurveGraphFontSize(), label: 'sCurveGraphSettings.fontSize', max: FONT_SIZE_MAX, min: FONT_SIZE_MIN, name: 'fontSize', onChange: form => { this.renderSettingsStore.setSCurveGraphFontSize(form.fontSize().value()); }, resetEvent: form => { this.renderSettingsStore.setSCurveGraphFontSize(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.DEFAULT_S_CURVE_GRAPH_FONT_SIZE); form.fontSize().value.set(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.DEFAULT_S_CURVE_GRAPH_FONT_SIZE); }, step: 0.1, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: this.renderSettingsStore.sCurveLineWidth(), label: 'sCurveGraphSettings.lineWidth', max: LINE_WIDTH_MAX, min: LINE_WIDTH_MIN, name: 'lineWidth', onChange: form => { this.renderSettingsStore.setSCurveLineWidth(form.lineWidth().value()); }, resetEvent: form => { this.renderSettingsStore.setSCurveLineWidth(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.DEFAULT_S_CURVE_LINE_WIDTH); form.lineWidth().value.set(_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_2__.DEFAULT_S_CURVE_LINE_WIDTH); }, step: 0.1, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: this.renderSettingsStore.sCurveShowChamberPoints(), label: 'sCurveGraphSettings.showChamberPoints', name: 'showChamberPoints', onChange: form => { this.renderSettingsStore.setSCurveShowChamberPoints(form.showChamberPoints().value()); }, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.TOGGLE }], ...(ngDevMode ? [{ debugName: "formConfig" }] : [])); static ɵfac = function SCurveGraphPopoverService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SCurveGraphPopoverService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: SCurveGraphPopoverService, factory: SCurveGraphPopoverService.ɵfac }); } /***/ }, /***/ 74278 /*!***********************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/vascular-dev-panel/vascular-dev-panel.component.ts ***! \***********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VascularDevelopmentPanelComponent: () => (/* binding */ VascularDevelopmentPanelComponent) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_divider__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/divider */ 1432); /* harmony import */ var primeng_tooltip__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/tooltip */ 30642); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @angular/core */ 14975); function VascularDevelopmentPanelComponent_Case_120_Template(rf, ctx) { if (rf & 1) { const _r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "p-button", 37); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Case_120_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r1); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.orchestrator.revertVascularMask()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); } } function VascularDevelopmentPanelComponent_Case_121_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "div", 35)(1, "p-button", 38); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Case_121_Template_p_button_onClick_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.orchestrator.acceptVascularMask()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](2, "p-button", 39); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Case_121_Template_p_button_onClick_2_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r3); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.orchestrator.refuseVascularMask()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("disabled", ctx_r1.orchestrator.vascularMaskComputing()); } } function VascularDevelopmentPanelComponent_Case_122_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "p-button", 40); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Case_122_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r1.previewSegmentation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); } } const VASCULAR = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_8__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VolumeRenderingOption.VASCULAR]; class VascularDevelopmentPanelComponent { settings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_6__.renderSettingsStore); orchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_9__.VolumeViewerOrchestrator); VASCULAR = VASCULAR; tissueBloodThreshold = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.tissueBloodThreshold, ...(ngDevMode ? [{ debugName: "tissueBloodThreshold" }] : [])); bloodCalciumThreshold = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.bloodCalciumThreshold, ...(ngDevMode ? [{ debugName: "bloodCalciumThreshold" }] : [])); opacityTransitionWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.opacityTransitionWidth, ...(ngDevMode ? [{ debugName: "opacityTransitionWidth" }] : [])); outlierOpacity = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.outlierOpacity, ...(ngDevMode ? [{ debugName: "outlierOpacity" }] : [])); ambient = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.ambient, ...(ngDevMode ? [{ debugName: "ambient" }] : [])); diffuse = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.diffuse, ...(ngDevMode ? [{ debugName: "diffuse" }] : [])); specular = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.specular, ...(ngDevMode ? [{ debugName: "specular" }] : [])); specularPower = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.specularPower, ...(ngDevMode ? [{ debugName: "specularPower" }] : [])); clusterSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.clusterSize, ...(ngDevMode ? [{ debugName: "clusterSize" }] : [])); erosionRadius = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.erosionRadius, ...(ngDevMode ? [{ debugName: "erosionRadius" }] : [])); gridStep = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.gridStep, ...(ngDevMode ? [{ debugName: "gridStep" }] : [])); minHU = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.minHU, ...(ngDevMode ? [{ debugName: "minHU" }] : [])); maxHU = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(VASCULAR.maxHU, ...(ngDevMode ? [{ debugName: "maxHU" }] : [])); constructor() { const initialSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.settings.volumeSettings()); if (initialSettings.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VolumeRenderingOption.VASCULAR) { this.tissueBloodThreshold.set(initialSettings.tissueBloodThreshold); this.bloodCalciumThreshold.set(initialSettings.bloodCalciumThreshold); this.opacityTransitionWidth.set(initialSettings.opacityTransitionWidth); this.outlierOpacity.set(initialSettings.outlierOpacity); this.gridStep.set(initialSettings.gridStep); this.clusterSize.set(initialSettings.clusterSize); this.erosionRadius.set(initialSettings.erosionRadius); this.minHU.set(initialSettings.minHU); this.maxHU.set(initialSettings.maxHU); this.ambient.set(initialSettings.ambient); this.diffuse.set(initialSettings.diffuse); this.specular.set(initialSettings.specular); this.specularPower.set(initialSettings.specularPower); } // Sync local signals from the store so changes made via the settings popover are reflected here. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const settings = this.settings.volumeSettings(); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VolumeRenderingOption.VASCULAR) return; (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { this.clusterSize.set(settings.clusterSize); this.erosionRadius.set(settings.erosionRadius); this.minHU.set(settings.minHU); this.maxHU.set(settings.maxHU); this.gridStep.set(settings.gridStep); this.tissueBloodThreshold.set(settings.tissueBloodThreshold); this.bloodCalciumThreshold.set(settings.bloodCalciumThreshold); this.opacityTransitionWidth.set(settings.opacityTransitionWidth); this.outlierOpacity.set(settings.outlierOpacity); this.ambient.set(settings.ambient); this.diffuse.set(settings.diffuse); this.specular.set(settings.specular); this.specularPower.set(settings.specularPower); }); }); // gridStep and clusterSize are excluded — they only take effect on slide end // and require a WebWorker recompute, not a live render update. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const tissueBloodThreshold = this.tissueBloodThreshold(); const bloodCalciumThreshold = this.bloodCalciumThreshold(); const opacityTransitionWidth = this.opacityTransitionWidth(); const outlierOpacity = this.outlierOpacity(); const ambient = this.ambient(); const diffuse = this.diffuse(); const specular = this.specular(); const specularPower = this.specularPower(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.settings.updateVolumeSettings({ ambient, bloodCalciumThreshold, diffuse, opacityTransitionWidth, outlierOpacity, specular, specularPower, tissueBloodThreshold })); }); } /** The orchestrator coalesces drag ticks and drops them outside preview state. */ onSegmentationParameterDrag() { this.orchestrator.previewVascularMaskLive({ clusterSize: this.clusterSize(), erosionRadius: this.erosionRadius(), gridStep: this.gridStep(), maxHU: this.maxHU(), minHU: this.minHU() }); } onThresholdSlideEnd() { this.settings.updateVolumeSettings({ clusterSize: this.clusterSize(), erosionRadius: this.erosionRadius(), gridStep: this.gridStep(), maxHU: this.maxHU(), minHU: this.minHU() }); if (this.orchestrator.vascularSegmentationState() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_5__.VascularSegmentationState.PREVIEWING) { this.orchestrator.previewVascularMask(); } } previewSegmentation() { this.onThresholdSlideEnd(); this.orchestrator.previewVascularMask(); } static ɵfac = function VascularDevelopmentPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || VascularDevelopmentPanelComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdefineComponent"]({ type: VascularDevelopmentPanelComponent, selectors: [["lib-vascular-dev-panel"]], decls: 123, vars: 78, consts: [[1, "ring-surface-700", "bg-surface-900/95", "max-h-[80vh]", "w-[480px]", "overflow-y-auto", "rounded-lg", "p-4", "shadow-2xl", "ring-1"], [1, "text-color", "mb-3", "text-sm", "font-semibold"], [1, "text-surface-400", "mb-2", "text-xs", "tracking-wide", "uppercase"], [1, "grid", "grid-cols-[120px_1fr_44px_auto]", "items-center", "gap-2", "py-1"], [1, "text-muted-color", "text-right", "text-xs"], ["dataTestIdOverride", "vascular-dev-panel-slider-tissue-blood", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], [1, "text-surface-200", "text-right", "font-mono", "text-xs", "tabular-nums"], ["data-test-id", "vascular-dev-panel-p-button-tissue-blood-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["icon", "refresh"], ["dataTestIdOverride", "vascular-dev-panel-slider-blood-calcium", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-blood-calcium-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], [1, "my-3"], ["dataTestIdOverride", "vascular-dev-panel-slider-min-hu", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-min-hu-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-max-hu", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-max-hu-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-opacity-transition", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-opacity-transition-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-outlier-opacity", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-outlier-opacity-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-grid-step", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-grid-step-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-cluster-size", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-cluster-size-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-erosion-radius", 3, "sliderChanged", "slideEnd", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-erosion-radius-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-ambient", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-ambient-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-diffuse", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-diffuse-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-specular", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-specular-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["dataTestIdOverride", "vascular-dev-panel-slider-specular-power", 3, "sliderChanged", "sliderMin", "sliderMax", "sliderStep", "sliderValue"], ["data-test-id", "vascular-dev-panel-p-button-specular-power-reset", "text", "", "size", "small", "severity", "secondary", "pTooltip", "Reset", 3, "onClick"], ["data-test-id", "vascular-dev-panel-p-button-revert-segmentation", "label", "Revert Segmentation", "fluid", "", "size", "small", "severity", "secondary"], [1, "flex", "gap-2"], ["data-test-id", "vascular-dev-panel-p-button-preview-segmentation", "label", "Preview Segmentation", "fluid", "", "size", "small"], ["data-test-id", "vascular-dev-panel-p-button-revert-segmentation", "label", "Revert Segmentation", "fluid", "", "size", "small", "severity", "secondary", 3, "onClick"], ["data-test-id", "vascular-dev-panel-p-button-accept-segmentation", "label", "Accept", "fluid", "", "size", "small", 3, "onClick", "disabled"], ["data-test-id", "vascular-dev-panel-p-button-refuse-segmentation", "label", "Refuse", "fluid", "", "size", "small", "severity", "secondary", 3, "onClick"], ["data-test-id", "vascular-dev-panel-p-button-preview-segmentation", "label", "Preview Segmentation", "fluid", "", "size", "small", 3, "onClick"]], template: function VascularDevelopmentPanelComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](0, "div", 0)(1, "p", 1); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](2, "Vascular Render Tuner"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](3, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](4, "Thresholds (HU)"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](5, "div", 3)(6, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](7, "Tissue / Blood"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](8, "lib-slider", 5); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_8_listener($event) { ctx.tissueBloodThreshold.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_8_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](9, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](10); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](11, "p-button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_11_listener() { ctx.tissueBloodThreshold.set(ctx.VASCULAR.tissueBloodThreshold); return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](12, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](13, "div", 3)(14, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](15, "Blood / Calcium"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](16, "lib-slider", 9); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_16_listener($event) { ctx.bloodCalciumThreshold.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_16_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](17, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](18); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](19, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_19_listener() { ctx.bloodCalciumThreshold.set(ctx.VASCULAR.bloodCalciumThreshold); return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](20, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](21, "p-divider", 11); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](22, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](23, "Segmentation"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](24, "div", 3)(25, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](26, "Min HU"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](27, "lib-slider", 12); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_27_listener($event) { ctx.minHU.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_27_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](28, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](29); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](30, "p-button", 13); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_30_listener() { ctx.minHU.set(ctx.VASCULAR.minHU); return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](31, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](32, "div", 3)(33, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](34, "Max HU"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](35, "lib-slider", 14); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_35_listener($event) { return ctx.maxHU.set($event); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_35_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](36, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](37); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](38, "p-button", 15); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_38_listener() { ctx.maxHU.set(ctx.VASCULAR.maxHU); return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](39, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](40, "div", 3)(41, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](42, "Opacity Trans."); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](43, "lib-slider", 16); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_43_listener($event) { ctx.opacityTransitionWidth.set($event); return ctx.onSegmentationParameterDrag(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](44, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](45); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](46, "p-button", 17); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_46_listener() { return ctx.opacityTransitionWidth.set(ctx.VASCULAR.opacityTransitionWidth); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](47, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](48, "div", 3)(49, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](50, "Outlier Opacity"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](51, "lib-slider", 18); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_51_listener($event) { ctx.outlierOpacity.set($event); return ctx.onSegmentationParameterDrag(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](52, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](53); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](54, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](55, "p-button", 19); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_55_listener() { return ctx.outlierOpacity.set(ctx.VASCULAR.outlierOpacity); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](56, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](57, "div", 3)(58, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](59, "Grid step"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](60, "lib-slider", 20); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_60_listener($event) { ctx.gridStep.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_60_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](61, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](62); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](63, "p-button", 21); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_63_listener() { return ctx.gridStep.set(ctx.VASCULAR.gridStep); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](64, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](65, "div", 3)(66, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](67, "Cluster size filter"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](68, "lib-slider", 22); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_68_listener($event) { ctx.clusterSize.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_68_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](69, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](70); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](71, "p-button", 23); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_71_listener() { return ctx.clusterSize.set(ctx.VASCULAR.clusterSize); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](72, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](73, "div", 3)(74, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](75, "Erosion radius"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](76, "lib-slider", 24); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_76_listener($event) { ctx.erosionRadius.set($event); return ctx.onSegmentationParameterDrag(); })("slideEnd", function VascularDevelopmentPanelComponent_Template_lib_slider_slideEnd_76_listener() { return ctx.onThresholdSlideEnd(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](77, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](78); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](79, "p-button", 25); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_79_listener() { return ctx.erosionRadius.set(ctx.VASCULAR.erosionRadius); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](80, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](81, "p-divider", 11); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](82, "p", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](83, "Lighting"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](84, "div", 3)(85, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](86, "Ambient"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](87, "lib-slider", 26); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_87_listener($event) { return ctx.ambient.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](88, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](89); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](90, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](91, "p-button", 27); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_91_listener() { return ctx.ambient.set(ctx.VASCULAR.ambient); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](92, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](93, "div", 3)(94, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](95, "Diffuse"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](96, "lib-slider", 28); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_96_listener($event) { return ctx.diffuse.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](97, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](98); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](99, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](100, "p-button", 29); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_100_listener() { return ctx.diffuse.set(ctx.VASCULAR.diffuse); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](101, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](102, "div", 3)(103, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](104, "Specular"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](105, "lib-slider", 30); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_105_listener($event) { return ctx.specular.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](106, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](107); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipe"](108, "number"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](109, "p-button", 31); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_109_listener() { return ctx.specular.set(ctx.VASCULAR.specular); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](110, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](111, "div", 3)(112, "span", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](113, "Spec. Power"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](114, "lib-slider", 32); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("sliderChanged", function VascularDevelopmentPanelComponent_Template_lib_slider_sliderChanged_114_listener($event) { return ctx.specularPower.set($event); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](115, "span", 6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtext"](116); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementStart"](117, "p-button", 33); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵlistener"]("onClick", function VascularDevelopmentPanelComponent_Template_p_button_onClick_117_listener() { return ctx.specularPower.set(ctx.VASCULAR.specularPower); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](118, "lib-icon", 8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelement"](119, "p-divider", 11); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditionalCreate"](120, VascularDevelopmentPanelComponent_Case_120_Template, 1, 0, "p-button", 34)(121, VascularDevelopmentPanelComponent_Case_121_Template, 3, 1, "div", 35)(122, VascularDevelopmentPanelComponent_Case_122_Template, 1, 0, "p-button", 36); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_65_0; _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](8); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", ctx.orchestrator.volumeMinPixelValue())("sliderMax", ctx.bloodCalciumThreshold())("sliderStep", 1)("sliderValue", ctx.tissueBloodThreshold()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.tissueBloodThreshold(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", ctx.tissueBloodThreshold())("sliderMax", ctx.orchestrator.volumeMaxPixelValue())("sliderStep", 1)("sliderValue", ctx.bloodCalciumThreshold()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.bloodCalciumThreshold(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](9); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", ctx.orchestrator.volumeMinPixelValue())("sliderMax", ctx.bloodCalciumThreshold())("sliderStep", 1)("sliderValue", ctx.minHU()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.minHU(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", ctx.tissueBloodThreshold())("sliderMax", ctx.orchestrator.volumeMaxPixelValue())("sliderStep", 1)("sliderValue", ctx.maxHU()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.maxHU(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 300)("sliderStep", 1)("sliderValue", ctx.opacityTransitionWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.opacityTransitionWidth(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.outlierOpacity()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](54, 66, ctx.outlierOpacity(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 1)("sliderMax", 100)("sliderStep", 1)("sliderValue", ctx.gridStep()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.gridStep(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 1000)("sliderMax", 500000)("sliderStep", 1)("sliderValue", ctx.clusterSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.clusterSize(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](6); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 10)("sliderStep", 0.1)("sliderValue", ctx.erosionRadius()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.erosionRadius(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](9); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.ambient()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](90, 69, ctx.ambient(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.diffuse()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](99, 72, ctx.diffuse(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 0)("sliderMax", 1)("sliderStep", 0.01)("sliderValue", ctx.specular()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵpipeBind2"](108, 75, ctx.specular(), "1.2-2"), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](7); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵproperty"]("sliderMin", 1)("sliderMax", 128)("sliderStep", 1)("sliderValue", ctx.specularPower()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵtextInterpolate1"](" ", ctx.specularPower(), " "); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditional"]((tmp_65_0 = ctx.orchestrator.vascularSegmentationState()) === "applied" ? 120 : tmp_65_0 === "previewing" ? 121 : 122); } }, dependencies: [_tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.SliderComponent, primeng_button__WEBPACK_IMPORTED_MODULE_2__.Button, primeng_divider__WEBPACK_IMPORTED_MODULE_3__.Divider, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_7__.IconComponent, primeng_tooltip__WEBPACK_IMPORTED_MODULE_4__.Tooltip, _angular_common__WEBPACK_IMPORTED_MODULE_0__.DecimalPipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 85309 /*!************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-ids.ts ***! \************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MPR_VIEWPORT_ID_LIST: () => (/* binding */ MPR_VIEWPORT_ID_LIST), /* harmony export */ NON_DEGRADING_VIEWPORT_ID_LIST: () => (/* binding */ NON_DEGRADING_VIEWPORT_ID_LIST), /* harmony export */ VIEWPORT_IDS: () => (/* binding */ VIEWPORT_IDS) /* harmony export */ }); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/enums */ 66556); const VIEWPORT_IDS = { AXIAL: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.TOPLEFTMAIN, // 'viewportAxial', CORONAL: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.MIDDLEMAIN, // 'viewportCoronal', REFORMAT: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.RIGHTMAIN, // 'viewport3d', SAGITTAL: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_0__.ViewportAxisState.BOTTOMLEFTMAIN // 'viewportSagittal', }; const MPR_VIEWPORT_ID_LIST = [VIEWPORT_IDS.AXIAL, VIEWPORT_IDS.CORONAL, VIEWPORT_IDS.SAGITTAL]; // Left-click in REFORMAT/CORONAL only changes the crosshair position without re-rendering // the 3D volume itself, so these viewports do not trigger quality degradation. const NON_DEGRADING_VIEWPORT_ID_LIST = [VIEWPORT_IDS.REFORMAT, VIEWPORT_IDS.CORONAL]; /***/ }, /***/ 34837 /*!***************************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/annotation-create-interaction.ts ***! \***************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationCreateInteraction: () => (/* binding */ AnnotationCreateInteraction) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); // 2x the default pick tolerance (see RenderingEngineService.getScreenPositionActor) - the // first point is a small, easy-to-miss target the user must deliberately re-hit to close // the shape, so it's worth being more forgiving here than the flat default used elsewhere. const FIRST_POINT_HIT_RADIUS = 10; /** * Handles clicks while in annotation creation mode. Depending on the type of * annotation, it may handle adding multiple points and deciding when an annotation * is complete. */ class AnnotationCreateInteraction { annotationFacade; colorsService; renderingEngineService; viewportStore; constructor(annotationFacade, colorsService, renderingEngineService, viewportStore) { this.annotationFacade = annotationFacade; this.colorsService = colorsService; this.renderingEngineService = renderingEngineService; this.viewportStore = viewportStore; } handle(screenPos, viewportId, annotationBeingCreated, isDoubleClick) { const worldPos = this.renderingEngineService.getWorldPosition(viewportId, screenPos); if (!worldPos) { this.annotationFacade.cancelAnnotationCreation(); return; } switch (annotationBeingCreated.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.ANGLE: { return this.angleBeingCreated(annotationBeingCreated, worldPos); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.CLOSED_SPLINE: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.OPEN_SPLINE: { return this.splineBeingCreated(annotationBeingCreated, screenPos, worldPos, isDoubleClick, viewportId); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.DISTANCE: { return this.distanceBeingCreated(annotationBeingCreated, worldPos); } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.AnnotationSourceType.POINT: { return this.pointBeingCreated(annotationBeingCreated, worldPos); } default: { this.annotationFacade.cancelAnnotationCreation(); } } return undefined; } angleBeingCreated(angle, worldPos) { const update = (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.show)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.appendPoint)(angle, [...worldPos])); this.annotationFacade.creatingAnnotation(update); this.setCrosshairPos([...worldPos]); if (update.points.length === 3) { this.creationComplete(); } return { annotationId: angle.id, pointIndex: update.points.length - 1 }; } distanceBeingCreated(distance, worldPos) { const update = (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.show)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.appendPoint)(distance, [...worldPos])); this.annotationFacade.creatingAnnotation(update); this.setCrosshairPos([...worldPos]); if (update.points.length === 2) { this.creationComplete(); } return { annotationId: distance.id, pointIndex: update.points.length - 1 }; } pointBeingCreated(point, worldPos) { this.annotationFacade.creatingAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.show)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.move)(point, [...worldPos]))); this.setCrosshairPos([...worldPos]); this.creationComplete(); return { annotationId: point.id }; } splineBeingCreated(spline, screenPos, worldPos, isDoubleClick, viewportId) { if (isDoubleClick && (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__.getValid)(spline)) { this.creationComplete(); return; } // If the first point of the current spline is clicked, close it if (spline.points.length > 1 && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsClosedSpline)(spline) && this.isFirstPointHit(spline.id, viewportId, screenPos)) { this.creationComplete(); return; } // If points are too close, they can break spline interpolation const lastPoint = spline.points.at(-1); if (lastPoint && gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dist(lastPoint, worldPos) < 1) { return; } const update = (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.show)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.appendPoint)(spline, [...worldPos])); this.annotationFacade.creatingAnnotation(update); this.setCrosshairPos([...worldPos]); return { annotationId: spline.id, pointIndex: update.points.length - 1 }; } /** Enter-to-finish: the same completion path double-click uses in splineBeingCreated, * gated the same way - a no-op until the annotation is actually valid (e.g. an open * spline needs at least 2 points). */ completeIfValid(annotation) { if (!(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_3__.getValid)(annotation)) return; this.creationComplete(); } /** Enter-to-finish for open/closed splines specifically: appends the mouse's current * world position as a final point first, then completes - unlike double-click, which * only completes with whatever points are already confirmed. Without this, the user * is left looking at a rubber-band preview extending to the cursor, and pressing Enter * would silently drop that last segment instead of placing it. Skips the append when * that position is redundant with the last confirmed point, the same guard a real * click uses in splineBeingCreated. */ completeSplineWithCurrentPosition(spline, worldPos) { const lastPoint = spline.points.at(-1); const tooClose = !!lastPoint && gl_matrix__WEBPACK_IMPORTED_MODULE_0__.dist(lastPoint, worldPos) < 1; const current = tooClose ? spline : (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.show)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.appendPoint)(spline, [...worldPos])); if (!tooClose) this.annotationFacade.creatingAnnotation(current); this.completeIfValid(current); } creationComplete() { this.annotationFacade.annotationCreationComplete(); this.colorsService.nextColor(); } setCrosshairPos(pos) { this.viewportStore.updateIntersection(pos); } isFirstPointHit(annotationId, viewportId, screenPos) { const actor = this.renderingEngineService.getScreenPositionActor(viewportId, screenPos, FIRST_POINT_HIT_RADIUS); const details = this.getActorAnnotationDetails(actor); return details?.annotationId === annotationId && details.pointIndex === 0; } getActorAnnotationDetails(actor) { const properties = actor?.get('annotationId', 'pointIndex'); if (properties?.annotationId === undefined) { return; } return properties; } } /***/ }, /***/ 59821 /*!***************************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/annotation-select-interaction.ts ***! \***************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ AnnotationSelectInteraction: () => (/* binding */ AnnotationSelectInteraction) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); class AnnotationSelectInteraction { annotationFacade; renderingEngineService; viewportStore; shellPicker; constructor(annotationFacade, renderingEngineService, viewportStore, shellPicker) { this.annotationFacade = annotationFacade; this.renderingEngineService = renderingEngineService; this.viewportStore = viewportStore; this.shellPicker = shellPicker; } handle(screenPos, viewportId, multiselect = false) { const hardwareActor = this.renderingEngineService.getScreenPositionActor(viewportId, screenPos); // On hardware-selector miss, ray-cast Object3D shells so clicks through holes still select. const actor = hardwareActor ?? this.fallbackPickObject3dShell(viewportId, screenPos); let details; if (!actor && !multiselect) { this.annotationFacade.deselectAllAnnotations(); } else { const { annotationId, pointIndex } = this.getActorAnnotationDetails(actor) ?? {}; if (annotationId) { if (multiselect) { this.annotationFacade.toggleSelectAnnotation(annotationId); } else { this.annotationFacade.selectAnnotations([annotationId]); } details = { annotationId, pointIndex }; } } // Move crosshair to control-point world position when clicking a point handle. const snapTarget = details?.pointIndex === undefined ? undefined : this.controlPointPosition(details.annotationId, details.pointIndex); const worldPos = snapTarget ?? this.renderingEngineService.getWorldPosition(viewportId, screenPos); if (worldPos) { this.setCrosshairPos(worldPos); } return details; } /** CPU picks when the hardware selector misses. Returns the back-most actor * along the click ray (3D) or the smallest-2D-AABB cross-section (MPR). */ fallbackPickObject3dShell(viewportId, screenPos) { for (const annotationId of this.shellPicker.pickShellAnnotationIds(viewportId, screenPos)) { const actor = this.findActorForAnnotation(viewportId, annotationId); if (actor) return actor; } return undefined; } findActorForAnnotation(viewportId, annotationId) { for (const actor of (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.getAnnotationActors)(viewportId)) { const properties = actor.get?.('annotationId'); if (properties?.annotationId === annotationId) return actor; } return undefined; } controlPointPosition(annotationId, pointIndex) { const annotation = this.annotationFacade.getAnnotationById(annotationId); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationHasPoints)(annotation)) { const point = annotation.points[pointIndex]; return point ? [...point] : undefined; } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationHasPosition)(annotation)) { return [...annotation.position]; } return undefined; } setCrosshairPos(pos) { this.viewportStore.updateIntersection(pos); } getActorAnnotationDetails(actor) { const properties = actor?.get('annotationId', 'pointIndex'); if (properties?.annotationId === undefined) { return; } return properties; } } /***/ }, /***/ 50295 /*!***************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/hover-interaction.ts ***! \***************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ HoverInteraction: () => (/* binding */ HoverInteraction) /* harmony export */ }); class HoverInteraction { renderingEngineService; shellPicker; hoverTimeout; constructor(renderingEngineService, shellPicker) { this.renderingEngineService = renderingEngineService; this.shellPicker = shellPicker; } /** * expandedFirstPointCheck widens the pick radius for one specific target (a closed * spline's first point while it's being created) rather than for hover generally - * widening the default for every actor would make unrelated nearby annotations start * hovering from farther away than intended. Falling back to it only when the normal- * radius pick misses also avoids fighting the point's own hover-triggered size increase: * without the wider fallback, the cursor can sit visually over the enlarged point but * just outside the flat default radius, causing hover to flicker on/off each frame. */ handle(screenPos, viewportId, hoveredAnnotationSignal, expandedFirstPointCheck) { if (this.hoverTimeout !== undefined) cancelAnimationFrame(this.hoverTimeout); this.hoverTimeout = requestAnimationFrame(() => { const actor = this.renderingEngineService.getScreenPositionActor(viewportId, screenPos); let details = this.getActorAnnotationDetails(actor); if (!details && expandedFirstPointCheck) { const widerActor = this.renderingEngineService.getScreenPositionActor(viewportId, screenPos, expandedFirstPointCheck.hitRadius); const widerDetails = this.getActorAnnotationDetails(widerActor); if (widerDetails?.annotationId === expandedFirstPointCheck.annotationId && widerDetails.pointIndex === 0) { details = widerDetails; } } hoveredAnnotationSignal.set(details ?? this.shellHoverDetails(viewportId, screenPos)); }); } shellHoverDetails(viewportId, screenPos) { const [annotationId] = this.shellPicker.pickShellAnnotationIds(viewportId, screenPos); return annotationId ? { annotationId } : undefined; } getActorAnnotationDetails(actor) { const properties = actor?.get('annotationId', 'pointIndex'); if (properties?.annotationId === undefined) { return; } return properties; } } /***/ }, /***/ 38112 /*!***********************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/object3d-drag-interaction.ts ***! \***********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Object3DDragInteraction: () => (/* binding */ Object3DDragInteraction) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /** Time constant (ms) for the grab-offset decay. */ const FOLLOW_TAU_MS = 80; /** Below this world-space offset magnitude the glide is treated as finished. */ const OFFSET_EPSILON = 0.05; /** * Eases an Object3D into a move-drag. * * On the first move of a gesture we record the gap between the model's position * and the cursor as a decaying offset, so the model glides from where it sat to * the cursor and then tracks it 1:1 with no steady-state lag. */ class Object3DDragInteraction { annotationFacade; annotationId; target = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); offset = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(); hasTarget = false; rafId; lastFrameTime = 0; constructor(annotationFacade) { this.annotationFacade = annotationFacade; } get isActive() { return this.annotationId !== undefined; } update(annotationId, cursorWorld) { if (this.annotationId !== annotationId) { const annotation = this.annotationFacade.getAnnotationById(annotationId); if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsObject3D)(annotation)) return; this.annotationId = annotationId; gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(this.offset, annotation.position[0] - cursorWorld[0], annotation.position[1] - cursorWorld[1], annotation.position[2] - cursorWorld[2]); this.lastFrameTime = performance.now(); } gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(this.target, cursorWorld[0], cursorWorld[1], cursorWorld[2]); this.hasTarget = true; this.ensureLoop(); } /** Commits the final 1:1 position (if the model still exists). */ end() { if (this.annotationId && this.hasTarget) { this.updateAnnotation(this.target); } if (this.rafId !== undefined) cancelAnimationFrame(this.rafId); this.rafId = undefined; this.annotationId = undefined; this.hasTarget = false; gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(this.offset, 0, 0, 0); } ensureLoop() { if (this.rafId === undefined) { this.rafId = requestAnimationFrame(this.tick); } } tick = now => { this.rafId = undefined; if (!this.annotationId || !this.hasTarget) return; const dt = Math.max(0, now - this.lastFrameTime); this.lastFrameTime = now; gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scale(this.offset, this.offset, Math.exp(-dt / FOLLOW_TAU_MS)); const settled = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.length(this.offset) < OFFSET_EPSILON; if (settled) gl_matrix__WEBPACK_IMPORTED_MODULE_0__.set(this.offset, 0, 0, 0); if (!this.updateAnnotation(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.add(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), this.target, this.offset))) { this.end(); return; } if (!settled) this.ensureLoop(); }; /** Writes `pos` to the tracked annotation. Returns false if it vanished. */ updateAnnotation(pos) { const annotation = this.annotationId ? this.annotationFacade.getAnnotationById(this.annotationId) : undefined; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_1__.annotationIsObject3D)(annotation)) return false; this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_2__.move)(annotation, [pos[0], pos[1], pos[2]])); return true; } } /***/ }, /***/ 50892 /*!***************************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/object3d-rotation-interaction.ts ***! \***************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Object3DRotationInteraction: () => (/* binding */ Object3DRotationInteraction) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** A full screen sweep rotates PI * ROTATION_SENSITIVITY (≈270° at 1.5). */ const ROTATION_SENSITIVITY = 1.5; /** * Rotates a selected Object3D in place via right-mouse drag, mapping * screen-space deltas to yaw/pitch about the camera's view-up and right axes. */ class Object3DRotationInteraction { annotationFacade; renderingEngineService; renderSettingsStore; object3DGeometryFacade; _isRotating = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(false, ...(ngDevMode ? [{ debugName: "_isRotating" }] : [])); isRotating = this._isRotating.asReadonly(); dragState; /** * The single selected Object3D, or `undefined` if there isn't exactly one or it is locked. */ selectedObject3D = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { const selected = this.annotationFacade.selectedAnnotations(); if (selected.length !== 1) return; const [first] = selected; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsObject3D)(first) || first.locked) return; return first; }, ...(ngDevMode ? [{ debugName: "selectedObject3D" }] : [])); constructor(annotationFacade, renderingEngineService, renderSettingsStore, object3DGeometryFacade) { this.annotationFacade = annotationFacade; this.renderingEngineService = renderingEngineService; this.renderSettingsStore = renderSettingsStore; this.object3DGeometryFacade = object3DGeometryFacade; } get isDragging() { return this.dragState !== undefined; } /** * Begin a right-mouse rotation drag if an Object3D is selected and the viewport's * camera/canvas are in a state that lets us derive rotation axes. * Returns `true` iff the drag was started. */ tryStartDrag(event, viewportId) { const selected = this.selectedObject3D(); if (!selected) return false; const screenPos = [event.offsetX, event.offsetY]; if (!this.clickIsInsideModel(selected, viewportId, screenPos)) return false; const axes = this.getRotationAxes(viewportId, event.currentTarget); if (!axes) return false; this.dragState = { annotationId: selected.id, axes, lastScreen: screenPos, viewportId }; this.renderSettingsStore.setLowQuality(true); return true; } /** * Apply a drag delta if the move is in the drag's origin viewport. * Returns `true` if the event was consumed by rotation. */ updateDrag(event, viewportId) { const drag = this.dragState; if (!drag || drag.viewportId !== viewportId) return false; // Per-frame screen-space delta in pixels. Updating `lastScreen` each call is what makes // rotations accumulate: the next event's dx/dy is applied on top of the orientation // produced by this frame, so the object appears to follow the cursor across a long drag. // If we kept the mousedown origin as the anchor instead, the rotation would snap back // toward identity whenever the cursor crossed the origin. const dx = event.offsetX - drag.lastScreen[0]; const dy = event.offsetY - drag.lastScreen[1]; drag.lastScreen = [event.offsetX, event.offsetY]; if (dx === 0 && dy === 0) return true; const annotation = this.annotationFacade.getAnnotationById(drag.annotationId); if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_3__.annotationIsObject3D)(annotation)) return true; this._isRotating.set(true); this.applyYawPitch(annotation, drag.axes, dx, dy); return true; } endDrag() { if (!this.dragState) return; this.dragState = undefined; this.renderSettingsStore.setLowQuality(false); this._isRotating.set(false); } /** Cancel all in-flight rotation state. */ cancel() { const wasActive = this.dragState !== undefined || this._isRotating(); this.dragState = undefined; this._isRotating.set(false); if (wasActive) this.renderSettingsStore.setLowQuality(false); } applyYawPitch(annotation, axes, dx, dy) { // Horizontal drag (dx) → yaw around the camera's up axis. // Vertical drag (dy) → pitch around the camera's right axis. // Both axes are world-space. `rotateAboutAxis` pre-multiplies, so the composition is // final = pitch * yaw * current // Reading right-to-left: apply current, then yaw, then pitch. const yaw = this.angle(dx, axes.width); const pitch = this.angle(dy, axes.height); const rotated = (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.rotateAboutAxis)((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_4__.rotateAboutAxis)(annotation, axes.up, yaw), axes.right, pitch); this.annotationFacade.updateAnnotation(rotated); } angle(delta, length) { // Map pixel displacement to radians. `delta / length` [-1, 1] is the signed fraction of // the canvas swept, multiplying by π gives 180° for a full-canvas sweep, and the // sensitivity factor stretches that to ~270° at the default ROTATION_SENSITIVITY. return delta / length * Math.PI * ROTATION_SENSITIVITY; } clickIsInsideModel(annotation, viewportId, screenPos) { const geometry = this.object3DGeometryFacade.getGeometry(annotation.id); const shell = geometry?.shell; if (!shell) return false; const userMatrix = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.buildObject3dTransform)(annotation, geometry.centroid); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.silhouetteContainsClick)(shell, userMatrix, world => this.renderingEngineService.worldToCanvas(viewportId, [world[0], world[1], world[2]]), screenPos); } getRotationAxes(viewportId, target) { const camera = this.renderingEngineService.getViewport(viewportId)?.getCamera?.(); if (!camera?.viewUp || !camera.viewPlaneNormal) return undefined; const canvas = target instanceof HTMLElement ? target : undefined; const width = canvas?.clientWidth ?? 0; const height = canvas?.clientHeight ?? 0; if (width <= 0 || height <= 0) return undefined; const up = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.fromValues(camera.viewUp[0], camera.viewUp[1], camera.viewUp[2]); const normal = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.fromValues(camera.viewPlaneNormal[0], camera.viewPlaneNormal[1], camera.viewPlaneNormal[2]); const right = gl_matrix__WEBPACK_IMPORTED_MODULE_2__.cross(gl_matrix__WEBPACK_IMPORTED_MODULE_2__.create(), up, normal); return { height, right, up, width }; } } /***/ }, /***/ 64974 /*!*************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/pan-interaction.ts ***! \*************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ PanInteraction: () => (/* binding */ PanInteraction) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Handles panning by moving the isocenter relative to mouse movement. */ class PanInteraction { renderingEngineService; viewportStore; panPosition; constructor(renderingEngineService, viewportStore) { this.renderingEngineService = renderingEngineService; this.viewportStore = viewportStore; } get isActive() { return this.panPosition !== undefined; } start(mousePos) { this.panPosition = { cursor2D: mousePos, isocenter: this.viewportStore.isocenter() }; } update(mousePos, viewportId) { if (this.panPosition === undefined) return; const currentPosition = this.renderingEngineService.getWorldPosition(viewportId, mousePos); // Instead of storing the last 3d cursor position, we calculate it now // from the last 2d position to account for camera changes etc. const previousPosition = this.renderingEngineService.getWorldPosition(viewportId, this.panPosition.cursor2D); if (!currentPosition || !previousPosition) return; const delta = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.subtract(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), currentPosition, previousPosition); const newIsocenter = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.subtract(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), this.panPosition.isocenter, delta); this.panPosition = { cursor2D: mousePos, isocenter: newIsocenter }; this.viewportStore.updateIsoCenter((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.position)(newIsocenter[0], newIsocenter[1], newIsocenter[2])); } end() { this.panPosition = undefined; } } /***/ }, /***/ 22526 /*!****************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/scroll-interaction.ts ***! \****************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ScrollInteraction: () => (/* binding */ ScrollInteraction) /* harmony export */ }); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! gl-matrix */ 87396); /** * Scrolls through volume slices by moving the intersection * along the view normal of the viewport scrolled on. */ class ScrollInteraction { renderingEngineService; viewportStore; constructor(renderingEngineService, viewportStore) { this.renderingEngineService = renderingEngineService; this.viewportStore = viewportStore; } update(delta, viewportId) { const viewport = this.renderingEngineService.getViewport(viewportId); const viewNormal = viewport?.getCamera().viewPlaneNormal; if (!viewNormal) return; const intersection = this.viewportStore.intersection(); const updated = gl_matrix__WEBPACK_IMPORTED_MODULE_0__.scaleAndAdd(gl_matrix__WEBPACK_IMPORTED_MODULE_0__.create(), intersection, viewNormal, delta); this.viewportStore.updateIntersection(updated); } } /***/ }, /***/ 66646 /*!***************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/twist-interaction.ts ***! \***************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ TwistInteraction: () => (/* binding */ TwistInteraction) /* harmony export */ }); /** * Rotates the slice plane about its view normal at the given viewport. */ class TwistInteraction { viewportStore; constructor(viewportStore) { this.viewportStore = viewportStore; } update(deltaDegrees, viewportId) { const axis = this.viewportStore.viewportAxisMapping()[viewportId]; if (!axis) return; this.viewportStore.rotateCrosshair(axis, deltaDegrees); } } /***/ }, /***/ 78730 /*!***********************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/wheel-quality-interaction.ts ***! \***********************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WheelQualityInteraction: () => (/* binding */ WheelQualityInteraction) /* harmony export */ }); class WheelQualityInteraction { renderSettingsStore; timeoutMs; constructor(renderSettingsStore, timeoutMs = 200) { this.renderSettingsStore = renderSettingsStore; this.timeoutMs = timeoutMs; } start() { this.renderSettingsStore.lowQualityWithTimeout(this.timeoutMs); } } /***/ }, /***/ 76371 /*!*************************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/window-settings-interaction.ts ***! \*************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WindowSettingsInteraction: () => (/* binding */ WindowSettingsInteraction) /* harmony export */ }); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @cornerstonejs/core */ 50600); /* harmony import */ var _cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @cornerstonejs/core/utilities */ 67966); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Updated the window level/width values for MPR viewports * relative to mouse movements */ class WindowSettingsInteraction { renderingEngineService; renderSettingsStore; prevPosition; get isActive() { return this.prevPosition !== undefined; } constructor(renderingEngineService, renderSettingsStore) { this.renderingEngineService = renderingEngineService; this.renderSettingsStore = renderSettingsStore; } start(mousePos) { this.prevPosition = mousePos; } update(mousePos, viewportId) { if (this.prevPosition === undefined) return; const deltas = [mousePos[0] - this.prevPosition[0], mousePos[1] - this.prevPosition[1]]; if (viewportId === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportAxisState.RIGHTMAIN) { this.update3d(deltas); } else { this.updateMPR(deltas); } this.prevPosition = mousePos; } updateMPR(deltas) { const currentSettings = this.renderSettingsStore.windowSettings(); const update = { level: currentSettings.level + deltas[0], width: currentSettings.width + deltas[1] }; const viewport = this.renderingEngineService.getViewport(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportAxisState.TOPLEFTMAIN); if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__["default"]) { const [scalarMin, scalarMax] = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.getVolumeScalarRange)(viewport); const windowWidthMax = Math.max(1, (scalarMax - scalarMin) * 2); const windowWidthMin = 1; update.level = (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(update.level, scalarMin, scalarMax); update.width = (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(update.width, windowWidthMin, windowWidthMax); } this.renderSettingsStore.updateCustomPreset(update); } update3d(deltas) { const preset = this.renderSettingsStore.volumeSettings(); if (preset.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.VolumeRenderingOption.ENDO || preset.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.VolumeRenderingOption.VASCULAR) { return; } const viewport = this.renderingEngineService.getViewport(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.ViewportAxisState.RIGHTMAIN); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_0__["default"])) return; if (preset.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_2__.VolumeRenderingOption.MIP) { this.updateMipWindow(preset, deltas, viewport); return; } const [brightnessMin, brightnessMax] = [-1, 1.5]; const [thresholdMin, thresholdMax] = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.getVolumeScalarRange)(viewport); // Brightness has a smaller range so we divide the delta const [brightnessDelta, thresholdDelta] = [deltas[0] / 200, deltas[1]]; const update = { ...preset, brightness: (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(preset.brightness + brightnessDelta, brightnessMin, brightnessMax), threshold: (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(preset.threshold + thresholdDelta, thresholdMin, thresholdMax) }; this.renderSettingsStore.updateVolumeSettings(update); } /** MIP is just a projected HU image, so drag-to-adjust follows the same width/level * convention as updateMPR above (no /200 brightness scaling, real-HU bounds), even though it * reuses fluoro/xray's brightness/threshold field names - brightness is the window level, * threshold is the window width. */ updateMipWindow(preset, deltas, viewport) { const [scalarMin, scalarMax] = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_3__.getVolumeScalarRange)(viewport); const windowWidthMax = Math.max(1, (scalarMax - scalarMin) * 2); const update = { ...preset, brightness: (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(preset.brightness + deltas[0], scalarMin, scalarMax), threshold: (0,_cornerstonejs_core_utilities__WEBPACK_IMPORTED_MODULE_1__["default"])(preset.threshold + deltas[1], 1, windowWidthMax) }; this.renderSettingsStore.updateVolumeSettings(update); } end() { this.prevPosition = undefined; } } /***/ }, /***/ 82908 /*!**************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/interactions/zoom-interaction.ts ***! \**************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ZoomInteraction: () => (/* binding */ ZoomInteraction) /* harmony export */ }); const MIN_ZOOM = 0.1; const MAX_ZOOM = 10; /** * Updates viewport's zoom values based on the provided delta */ class ZoomInteraction { viewportStore; constructor(viewportStore) { this.viewportStore = viewportStore; } update(delta) { const zoom = this.viewportStore.zoom(); const next = zoom * Math.exp(delta / 2000); this.viewportStore.updateZoom(Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, next))); } } /***/ }, /***/ 92192 /*!******************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/object3d-shell-picker.ts ***! \******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ Object3dShellPicker: () => (/* binding */ Object3dShellPicker) /* harmony export */ }); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /** * Ranks the Object3D shells under a screen point, best candidate first. * * The shell is the solid picking proxy (a filled cylinder for HollowCylinder, * the convex hull for STL), so a ray that passes through a hole still resolves * to the model. Shared by click-selection and hover so the two always agree on * what is under the cursor. The silhouette test fast-rejects via the projected * AABB before touching every vertex, so calling this on every hover frame is * cheap unless the cursor is actually over a model. */ class Object3dShellPicker { annotationFacade; renderingEngineService; object3DGeometryFacade; constructor(annotationFacade, renderingEngineService, object3DGeometryFacade) { this.annotationFacade = annotationFacade; this.renderingEngineService = renderingEngineService; this.object3DGeometryFacade = object3DGeometryFacade; } /** Annotation ids of every shell the screen point hits, best candidate first. */ pickShellAnnotationIds(viewportId, screenPos) { const ray = this.renderingEngineService.getWorldRay(viewportId, screenPos); if (!ray) return []; const candidates = this.getShellHits(viewportId, screenPos, ray); this.sortShellCandidates(candidates); return candidates.map(candidate => candidate.annotationId); } /** * One candidate per Object3D shell whose silhouette covers the cursor. MPR * viewports carry extra ranking fields, 3D viewports rank on depth alone. */ getShellHits(viewportId, screenPos, ray) { const sliceRange = this.renderingEngineService.getSliceTRange(viewportId); const slabAxes = sliceRange ? this.renderingEngineService.cameraSlabPlaneAxes(viewportId) : undefined; if (sliceRange && !slabAxes) return []; const project = world => this.renderingEngineService.worldToCanvas(viewportId, [world[0], world[1], world[2]]); const candidates = []; for (const annotation of this.annotationFacade.annotations()) { if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_0__.annotationIsObject3D)(annotation) || annotation.hidden) continue; const geometry = this.object3DGeometryFacade.getGeometry(annotation.id); const shell = geometry?.shell; if (!shell) continue; const userMatrix = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.buildObject3dTransform)(annotation, geometry.centroid); if (!(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.silhouetteContainsClick)(shell, userMatrix, project, screenPos)) continue; const tEnter = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.aabbCentreDepth)(shell.bounds, userMatrix, ray); candidates.push(slabAxes ? { annotationId: annotation.id, area2d: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.projectedAabbArea)(shell.bounds, userMatrix, slabAxes), kind: 'mpr', tEnter, volume3d: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_1__.aabbVolume)(shell.bounds) } : { annotationId: annotation.id, kind: 'volume3d', tEnter }); } return candidates; } /** Sorts in place. MPR ranks on smallest projected 2D AABB, then smaller 3D volume. */ sortShellCandidates(candidates) { if (candidates[0]?.kind === 'mpr') { candidates.sort((a, b) => a.area2d - b.area2d || a.volume3d - b.volume3d); } else { candidates.sort((a, b) => b.tEnter - a.tEnter); } } } /***/ }, /***/ 46184 /*!*************************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-interaction/viewport-interaction.service.ts ***! \*************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ViewportInteractionService: () => (/* binding */ ViewportInteractionService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 33242); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_updaters__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/updaters */ 84249); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _colors_colors_service__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../colors/colors.service */ 39298); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../viewport-ids */ 85309); /* harmony import */ var _interactions_annotation_create_interaction__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./interactions/annotation-create-interaction */ 34837); /* harmony import */ var _interactions_annotation_select_interaction__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./interactions/annotation-select-interaction */ 59821); /* harmony import */ var _interactions_hover_interaction__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./interactions/hover-interaction */ 50295); /* harmony import */ var _interactions_object3d_drag_interaction__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./interactions/object3d-drag-interaction */ 38112); /* harmony import */ var _interactions_object3d_rotation_interaction__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./interactions/object3d-rotation-interaction */ 50892); /* harmony import */ var _interactions_pan_interaction__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./interactions/pan-interaction */ 64974); /* harmony import */ var _interactions_scroll_interaction__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./interactions/scroll-interaction */ 22526); /* harmony import */ var _interactions_twist_interaction__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./interactions/twist-interaction */ 66646); /* harmony import */ var _interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./interactions/wheel-quality-interaction */ 78730); /* harmony import */ var _interactions_window_settings_interaction__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./interactions/window-settings-interaction */ 76371); /* harmony import */ var _interactions_zoom_interaction__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./interactions/zoom-interaction */ 82908); /* harmony import */ var _object3d_shell_picker__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./object3d-shell-picker */ 92192); // 2x the default pick tolerance (see RenderingEngineService.getScreenPositionActor) - // mirrors AnnotationCreateInteraction's FIRST_POINT_HIT_RADIUS for the click-to-close // check, so hovering and clicking agree on what counts as "on" the first point. const FIRST_POINT_HIT_RADIUS = 10; const LEFT_MOUSE_BUTTON = 0; const MIDDLE_MOUSE_BUTTON = 1; const RIGHT_MOUSE_BUTTON = 2; /** Maps `MouseEvent.button` values to the corresponding `MouseEvent.buttons` bitmask. */ const BUTTONS_BITMASK = { [LEFT_MOUSE_BUTTON]: 1, [MIDDLE_MOUSE_BUTTON]: 4, [RIGHT_MOUSE_BUTTON]: 2 }; class ViewportInteractionService { annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.AnnotationFacade); colorsService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_colors_colors_service__WEBPACK_IMPORTED_MODULE_11__.ColorsService); interactionModeService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_12__.InteractionModeService); renderingEngineService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_4__.RenderingEngineService); contextMenuSubject = new rxjs__WEBPACK_IMPORTED_MODULE_2__.Subject(); renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.renderSettingsStore); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.viewportStore); volumeViewerStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.volumeViewerStore); object3DGeometryFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_8__.Object3DGeometryFacade); // Interactions annotationCreate = new _interactions_annotation_create_interaction__WEBPACK_IMPORTED_MODULE_14__.AnnotationCreateInteraction(this.annotationFacade, this.colorsService, this.renderingEngineService, this.viewportStore); object3dShellPicker = new _object3d_shell_picker__WEBPACK_IMPORTED_MODULE_25__.Object3dShellPicker(this.annotationFacade, this.renderingEngineService, this.object3DGeometryFacade); annotationSelect = new _interactions_annotation_select_interaction__WEBPACK_IMPORTED_MODULE_15__.AnnotationSelectInteraction(this.annotationFacade, this.renderingEngineService, this.viewportStore, this.object3dShellPicker); hover = new _interactions_hover_interaction__WEBPACK_IMPORTED_MODULE_16__.HoverInteraction(this.renderingEngineService, this.object3dShellPicker); object3DRotation = new _interactions_object3d_rotation_interaction__WEBPACK_IMPORTED_MODULE_18__.Object3DRotationInteraction(this.annotationFacade, this.renderingEngineService, this.renderSettingsStore, this.object3DGeometryFacade); object3DDrag = new _interactions_object3d_drag_interaction__WEBPACK_IMPORTED_MODULE_17__.Object3DDragInteraction(this.annotationFacade); scroll = new _interactions_scroll_interaction__WEBPACK_IMPORTED_MODULE_20__.ScrollInteraction(this.renderingEngineService, this.viewportStore); pan = new _interactions_pan_interaction__WEBPACK_IMPORTED_MODULE_19__.PanInteraction(this.renderingEngineService, this.viewportStore); twist = new _interactions_twist_interaction__WEBPACK_IMPORTED_MODULE_21__.TwistInteraction(this.viewportStore); wheelQuality = new _interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_22__.WheelQualityInteraction(this.renderSettingsStore); windowSettings = new _interactions_window_settings_interaction__WEBPACK_IMPORTED_MODULE_23__.WindowSettingsInteraction(this.renderingEngineService, this.renderSettingsStore); zoom = new _interactions_zoom_interaction__WEBPACK_IMPORTED_MODULE_24__.ZoomInteraction(this.viewportStore); constructor() { // Electron-only macOS trackpad twist. const onTrackpadRotate = globalThis.electronAPI?.onTrackpadRotate; if (!onTrackpadRotate) return; const unsubscribe = onTrackpadRotate(({ clientX, clientY, rotation }) => { const viewportId = this.viewportAtPoint(clientX, clientY); if (viewportId) this.twist.update(rotation, viewportId); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(unsubscribe); } viewportAtPoint(clientX, clientY) { for (const [id, vp] of Object.entries(this.volumeViewerStore.registeredViewports())) { const element = vp.element; if (!element) continue; const rect = element.getBoundingClientRect(); if (clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom) { return id; } } return undefined; } /** Enter-to-finish for annotation creation (splines) - see AnnotationCreateInteraction.completeIfValid. * Only trusts the tracked mouse position when the pointer is currently over the same * viewport the spline is being created in - otherwise it's either the untouched [0, 0, 0] * default (no mousemove yet) or a stale position from a different viewport, so completion * falls back to the already-confirmed points instead of appending a bogus one. */ completeAnnotationCreationIfValid(annotation) { if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(annotation)) { // Mirrors the click path's closure rule (splineBeingCreated/isFirstPointHit): if the // hover-preview already shows the loop closing on the first point, finish with the // existing points instead of appending a near-duplicate point next to point 0. const hovered = this._hoveredAnnotation(); const closingFirstPoint = annotation.points.length > 1 && (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsClosedSpline)(annotation) && hovered?.annotationId === annotation.id && hovered.pointIndex === 0; if (closingFirstPoint) { this.annotationCreate.completeIfValid(annotation); return; } const worldPos = this.mouseMoveViewportId === this.creationViewportId ? this._mouseWorldPosition() : undefined; if (worldPos) { this.annotationCreate.completeSplineWithCurrentPosition(annotation, worldPos); } else { this.annotationCreate.completeIfValid(annotation); } return; } this.annotationCreate.completeIfValid(annotation); } /** Only relevant while creating a closed spline - see HoverInteraction.handle's * expandedFirstPointCheck for why this needs a wider radius than the flat default. */ closedSplineFirstPointHoverCheck() { const interactionMode = this.interactionModeService.interactionMode(); if (interactionMode.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_6__.InteractionModeType.CREATE) return undefined; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsClosedSpline)(interactionMode.annotation)) return undefined; return { annotationId: interactionMode.annotation.id, hitRadius: FIRST_POINT_HIT_RADIUS }; } openContextMenu$ = this.contextMenuSubject.asObservable(); lastClick; currentScreenPos = [0, 0]; _mouseWorldPosition = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)([0, 0, 0], ...(ngDevMode ? [{ debugName: "_mouseWorldPosition" }] : [])); get mouseWorldPosition() { return this._mouseWorldPosition; } _hoveredAnnotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(undefined, { ...(ngDevMode ? { debugName: "_hoveredAnnotation" } : {}), // Adding equality function so that we don't send out unnecessary updates // if the same value is found over multiple mousemove events equal: (a, b) => a?.annotationId === b?.annotationId && a?.pointIndex === b?.pointIndex }); get hoveredAnnotation() { return this._hoveredAnnotation; } _dragDetails = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)({}, ...(ngDevMode ? [{ debugName: "_dragDetails" }] : [])); dragDetails = this._dragDetails; /** * Cursor style for the viewport based on interaction state */ viewportCursor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.computed)(() => { if (this.object3DRotation.isRotating()) return 'all-scroll'; const dragId = this._dragDetails().annotationId; if (dragId) { const dragged = this.annotationFacade.getAnnotationById(dragId); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsObject3D)(dragged) && !dragged.locked) return 'grabbing'; } const hovered = this._hoveredAnnotation(); if (hovered?.annotationId) { const annotation = this.annotationFacade.getAnnotationById(hovered.annotationId); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsObject3D)(annotation) && !annotation.locked) return 'grab'; } return ''; }, ...(ngDevMode ? [{ debugName: "viewportCursor" }] : [])); get draggingId() { return this._dragDetails().annotationId; } get draggingIndex() { return this._dragDetails().pointIndex; } mousedownViewportId; mouseMoveViewportId; creationViewportId; mousedownButton; rightMousedownViewportId; rightDragMoved = false; suppressNextContextMenu = false; lastGestureRotation = 0; lastGestureScale = 1; pendingGestureRotation = 0; pendingGestureScale = 1; gestureViewportId; gestureFrame; gestureActive = false; /** * Handles viewport click events and determines interaction type. * Should be called on mousedown to capture click position and detect double-clicks. * * @returns Object containing click info and whether it was a double-click */ handleViewportMouseDown(event, viewportId) { const screenPos = [event.offsetX, event.offsetY]; this.mousedownViewportId = viewportId; this.mousedownButton = event.button; // Clear any stale suppression from a previous gesture. // // Example: A right-drag sets `suppressNextContextMenu` on mouseup, but on macOS // the `contextmenu` event fires on mousedown (before that mouseup), so the flag it meant // to suppress has already passed, leaving it stranded `true` and wrongly suppressing the // NEXT gesture's context menu. mousedown fires before contextmenu, so resetting // here lands before this gesture's menu is evaluated. this.suppressNextContextMenu = false; // Right-click (camera rotate/pan) always affects the 3D volume render. // Left-click in AXIAL/SAGITTAL moves the crosshair which causes the 3D viewport to re-render. // Left-click in REFORMAT/CORONAL only changes the crosshair position without re-rendering // the 3D volume itself, so those are excluded. const leftClickAffects3d = event.button === LEFT_MOUSE_BUTTON && !_viewport_ids__WEBPACK_IMPORTED_MODULE_13__.NON_DEGRADING_VIEWPORT_ID_LIST.includes(viewportId); if (event.button === RIGHT_MOUSE_BUTTON || leftClickAffects3d) { this.renderSettingsStore.setLowQuality(true); } if (event.button === RIGHT_MOUSE_BUTTON) { this.rightMousedownViewportId = viewportId; this.rightDragMoved = false; if (event.ctrlKey) { this.windowSettings.start(screenPos); return; } if (!this.object3DRotation.tryStartDrag(event, viewportId)) { this.pan.start(screenPos); } return; } if (event.button !== LEFT_MOUSE_BUTTON) return undefined; const currentClick = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.clickInfo)(event); const previousClick = this.lastClick; const wasDoubleClick = !!previousClick && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.isDoubleClick)(previousClick, currentClick); this.lastClick = currentClick; this.currentScreenPos = screenPos; return { isDoubleClick: wasDoubleClick }; } /** * The volume was clicked while in creation mode */ handleAnnotationCreationClick(viewportId, annotationBeingCreated, isDoubleClick) { this.creationViewportId = viewportId; const details = this.annotationCreate.handle(this.currentScreenPos, viewportId, annotationBeingCreated, isDoubleClick); if (details) { this._dragDetails.set(details); } } handleAddPointClick(viewportId, annotationId, isDoubleClick) { if (isDoubleClick) { this.interactionModeService.clearMode(); return; } const worldPos = this.renderingEngineService.getWorldPosition(viewportId, this.currentScreenPos); if (!worldPos) { return; } const annotation = this.annotationFacade.getAnnotationById(annotationId); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsSpline)(annotation)) { // If already hovering on an existing point, don't add new one - // instead drag that existing point const hovered = this._hoveredAnnotation(); if (hovered?.annotationId === annotation.id && hovered.pointIndex !== undefined) { this.handleAnnotationSelectionClick(viewportId, false); return; } const path = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_7__.getSplinePath)(annotation); const snappedPos = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.snapPositionToSpline)(worldPos, path); const { addedAt, points } = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_10__.addPointToSpline)(annotation.points, path, snappedPos); this.annotationFacade.updateAnnotation({ ...annotation, points }); // Only drag newly created point if actually touching it if (gl_matrix__WEBPACK_IMPORTED_MODULE_3__.distance(snappedPos, worldPos) < 3) { this._dragDetails.set({ annotationId, pointIndex: addedAt }); } } } /** An actor or the volume was clicked while not in creation mode. */ handleAnnotationSelectionClick(viewportId, multiselect = false) { const previouslySelected = new Set(this.annotationFacade.selectedIds()); const details = this.annotationSelect.handle(this.currentScreenPos, viewportId, multiselect); if (!details) return undefined; // Object3D needs a second mousedown before drag arms, and locked objects // never arm. Both conditions apply only to Object3D annotations. const annotation = this.annotationFacade.getAnnotationById(details.annotationId); if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsObject3D)(annotation) && (annotation.locked || !previouslySelected.has(details.annotationId))) return details; this._dragDetails.set(details); return details; } /** * W/L drag for the CPR carriers: they are bare mounts with no `lib-volume-viewport` to * route through, and the full mouse-move path would hit-test annotations they exclude. */ startWindowSettingsDrag(screenPos) { this.windowSettings.start(screenPos); } updateWindowSettingsDrag(screenPos, viewportId) { if (this.windowSettings.isActive) this.windowSettings.update(screenPos, viewportId); } handleViewportMouseMove(event, viewportId) { if (this.cancelledPhantomButton(event)) return; const screenPos = [event.offsetX, event.offsetY]; if (this.handleActiveInteractionMove(screenPos, viewportId)) return; if (this.object3DRotation.updateDrag(event, viewportId)) return; const worldPos = this.renderingEngineService.getWorldPosition(viewportId, screenPos); if (!worldPos) return; this._mouseWorldPosition.set(worldPos); this.mouseMoveViewportId = viewportId; // Crosshair is only moved by a left-button drag in its origin viewport. if (this.mousedownViewportId === viewportId && this.mousedownButton === LEFT_MOUSE_BUTTON) { this.setCrosshairPos(worldPos); } const draggingId = this.draggingId; if (!draggingId) { // We only need to worry about hovers if we're not dragging something this.hover.handle([event.offsetX, event.offsetY], viewportId, this._hoveredAnnotation, this.closedSplineFirstPointHoverCheck()); return; } if (this.mousedownViewportId !== viewportId || this.mousedownButton !== LEFT_MOUSE_BUTTON) { return; } this.handleDragMove(draggingId, worldPos); } handleActiveInteractionMove(screenPos, viewportId) { if (this.pan.isActive) { if (this.mousedownViewportId === viewportId) this.pan.update(screenPos, viewportId); return true; } if (this.windowSettings.isActive) { if (this.mousedownViewportId === viewportId) this.windowSettings.update(screenPos, viewportId); return true; } return false; } handleDragMove(draggingId, worldPos) { const beingCreated = this.annotationFacade.annotationBeingCreated(); const toUpdate = this.annotationFacade.getAnnotationById(draggingId) ?? (beingCreated?.id === draggingId ? beingCreated : undefined); if (!toUpdate) { this._dragDetails.set({}); return; } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationHasPoints)(toUpdate) && this.draggingIndex !== undefined) { this.updatePoints(toUpdate, this.draggingIndex, worldPos, beingCreated); } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationIsObject3D)(toUpdate)) { this.object3DDrag.update(toUpdate.id, [...worldPos]); return; } if ((0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_5__.annotationHasPosition)(toUpdate)) { this.annotationFacade.updateAnnotation((0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_9__.move)(toUpdate, [...worldPos])); } } updatePoints(toUpdate, index, worldPos, beingCreated) { if (toUpdate.points[index]) { const update = (0,_tomoverse_updaters__WEBPACK_IMPORTED_MODULE_9__.movePoint)(toUpdate, index, [...worldPos]); if (toUpdate === beingCreated) { this.annotationFacade.creatingAnnotation(update); } else { this.annotationFacade.updateAnnotation(update); } } } handleContextMenu(outputEvent, viewportId) { if (outputEvent.key) { this.contextMenuSubject.next(`${viewportId}:${outputEvent.key}`); return; } if (this.suppressNextContextMenu) { this.suppressNextContextMenu = false; return; } const event = outputEvent.event; const screenPos = [event.offsetX, event.offsetY]; const actor = this.renderingEngineService.getScreenPositionActor(viewportId, screenPos); if (actor) { // Update context menu items const { annotationId, pointIndex } = this.getActorAnnotationDetails(actor) ?? {}; if (annotationId) { if (pointIndex === undefined) { this.contextMenuSubject.next(annotationId); } else { this.contextMenuSubject.next(`${annotationId}:${pointIndex}`); } return; } } // Open viewport-specific menu this.openViewportMenu(); } openViewportMenu() { this.contextMenuSubject.next('viewport'); } handleMouseUp() { const rightClickLostOrigin = this.mousedownButton === RIGHT_MOUSE_BUTTON && this.rightMousedownViewportId === undefined; const shouldOpenContextMenu = this.mousedownButton === RIGHT_MOUSE_BUTTON && !this.rightDragMoved && !rightClickLostOrigin; if (!shouldOpenContextMenu && this.mousedownButton === RIGHT_MOUSE_BUTTON) { this.suppressNextContextMenu = true; } this.resetAllInteractions(); return { shouldOpenContextMenu }; } /** * Cancels all in-flight interactions without emitting a context-menu signal. * Used on `window:blur`, where no `mouseup` will fire. */ cancelInteractions() { this.discardPendingGesture(); this.resetAllInteractions(); } /** * When wee still believe a button is pressed, but the OS-reported buttons bitmask says otherwise. * Must be bound to `window:mousemove` so we also catch re-entry outside the viewport. * Returns `true` if a phantom-press was found and interactions were cancelled */ handleGlobalMouseMove(event) { if (this.mousedownButton === RIGHT_MOUSE_BUTTON) { this.rightDragMoved = true; } this.cancelledPhantomButton(event); } cancelledPhantomButton(event) { if (this.mousedownButton === undefined) return false; const bit = BUTTONS_BITMASK[this.mousedownButton]; // eslint-disable-next-line sonarjs/bitwise-operators -- event.buttons is a genuine bitmask if (bit === undefined || (event.buttons & bit) !== 0) return false; this.cancelInteractions(); return true; } resetAllInteractions() { const wasInteracting = this.mousedownButton !== undefined; this.pan.end(); this.windowSettings.end(); this.object3DRotation.cancel(); this.object3DDrag.end(); this._dragDetails.set({}); this.mousedownButton = undefined; this.rightMousedownViewportId = undefined; this.mousedownViewportId = undefined; if (wasInteracting) { this.renderSettingsStore.setLowQuality(false); } } setCrosshairPos(pos) { this.viewportStore.updateIntersection(pos); } getActorAnnotationDetails(actor) { const properties = actor?.get('annotationId', 'pointIndex'); if (properties?.annotationId === undefined) { return; } return properties; } handleWheel(event, viewportId) { // Suppress default to avoid triggering full-page zoom. event.preventDefault(); this.wheelQuality.start(); // Pinch gestures on a touchpad are reported as wheel events with ctrlKey set. // macOS reports pinch-out as negative deltaY and pinch-in as positive. // Consumed without dispatch while a Safari GestureEvent is in flight, so // double-handling doesn't zoom twice and fall-through doesn't scroll slices. if (event.ctrlKey) { if (this.gestureActive) return; // Native expectation is pinch-out → zoom in, so we negate. const delta = event.deltaMode === WheelEvent.DOM_DELTA_PIXEL ? -event.deltaY * 7 : -Math.sign(event.deltaY) * 500; this.zoom.update(delta); return; } // Shift+wheel rotates the slice plane about its view normal. if (event.shiftKey) { // Browsers translate Shift+wheel on a mouse to horizontal scroll, // so fall back to deltaX when deltaY is zero. const rawDelta = event.deltaY === 0 ? event.deltaX : event.deltaY; const delta = event.deltaMode === WheelEvent.DOM_DELTA_PIXEL ? rawDelta * 0.0375 : Math.sign(rawDelta) * 0.15; this.twist.update(delta, viewportId); return; } const scrollDelta = event.deltaMode === WheelEvent.DOM_DELTA_PIXEL ? event.deltaY * 0.0075 : Math.sign(event.deltaY) * 1; this.scroll.update(scrollDelta, viewportId); } /** * Safari trackpad gesture (twist + pinch). Dispatches are coalesced to one per * animation frame; a fixed-interval throttle aliases against the ~60Hz * gesturechange stream and stutters. */ handleGestureStart(event) { const gesture = event; this.lastGestureRotation = gesture.rotation; this.lastGestureScale = gesture.scale; this.gestureActive = true; // Engage interaction LOD before the first dispatch, matching the wheel path. this.wheelQuality.start(); } handleGestureChange(event, viewportId) { const gesture = event; this.pendingGestureRotation = gesture.rotation; this.pendingGestureScale = gesture.scale; this.gestureViewportId = viewportId; if (this.gestureFrame !== undefined) return; this.gestureFrame = requestAnimationFrame(() => { this.gestureFrame = undefined; this.dispatchGestureDeltas(); }); } handleGestureEnd() { if (this.gestureFrame !== undefined) { cancelAnimationFrame(this.gestureFrame); this.gestureFrame = undefined; this.dispatchGestureDeltas(); } this.gestureActive = false; } // Unlike handleGestureEnd, cancellation must not flush the pending delta. discardPendingGesture() { if (this.gestureFrame !== undefined) { cancelAnimationFrame(this.gestureFrame); this.gestureFrame = undefined; } this.gestureActive = false; this.gestureViewportId = undefined; } dispatchGestureDeltas() { if (this.gestureViewportId === undefined) return; this.wheelQuality.start(); const deltaRotation = this.pendingGestureRotation - this.lastGestureRotation; const deltaScale = Math.log(this.lastGestureScale / this.pendingGestureScale); this.lastGestureRotation = this.pendingGestureRotation; this.lastGestureScale = this.pendingGestureScale; if (deltaRotation !== 0) this.twist.update(-deltaRotation, this.gestureViewportId); if (deltaScale !== 0) this.zoom.update(-deltaScale * 2000); } static ɵfac = function ViewportInteractionService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewportInteractionService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: ViewportInteractionService, factory: ViewportInteractionService.ɵfac }); } /***/ }, /***/ 86026 /*!**********************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-overlay/crosshair/crosshair.component.ts ***! \**********************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CrosshairComponent: () => (/* binding */ CrosshairComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../viewport-ids */ 85309); /* harmony import */ var _viewport_interaction_interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../viewport-interaction/interactions/wheel-quality-interaction */ 78730); /* harmony import */ var _window_details_window_details_service__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../window-details/window-details.service */ 99360); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @angular/core */ 14975); /* eslint-disable @angular-eslint/component-selector */ const _c0 = ["lib-crosshair", ""]; function CrosshairComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](0, "line", 1)(1, "line", 1)(2, "line", 2)(3, "line", 2)(4, "circle", 3); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); const arm_r2 = ctx_r0.shortArmLength(); const shortGap_r3 = ctx_r0.shortArmGap(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", -arm_r2)("x2", -shortGap_r3)("stroke-width", ctx_r0.shortArmStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", shortGap_r3)("x2", arm_r2)("stroke-width", ctx_r0.shortArmStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.vColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", -arm_r2)("y2", -shortGap_r3)("stroke-width", ctx_r0.shortArmStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.vColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", shortGap_r3)("y2", arm_r2)("stroke-width", ctx_r0.shortArmStrokeWidth()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("fill", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("r", ctx_r0.centreDotRadius()); } } function CrosshairComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](0, "rect")(1, "line", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementStart"](2, "line", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomListener"]("mouseover", function CrosshairComponent_Conditional_2_Template_line_mouseover_2_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover("v")); })("mouseout", function CrosshairComponent_Conditional_2_Template_line_mouseout_2_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover(undefined)); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](3, "line", 2); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementStart"](4, "line", 4); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomListener"]("mouseover", function CrosshairComponent_Conditional_2_Template_line_mouseover_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover("v")); })("mouseout", function CrosshairComponent_Conditional_2_Template_line_mouseout_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover(undefined)); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](5, "line", 1); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementStart"](6, "line", 5); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomListener"]("mouseover", function CrosshairComponent_Conditional_2_Template_line_mouseover_6_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover("h")); })("mouseout", function CrosshairComponent_Conditional_2_Template_line_mouseout_6_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover(undefined)); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](7, "line", 1); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementStart"](8, "line", 5); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomListener"]("mouseover", function CrosshairComponent_Conditional_2_Template_line_mouseover_8_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover("h")); })("mouseout", function CrosshairComponent_Conditional_2_Template_line_mouseout_8_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵresetView"](ctx_r0.axisHover(undefined)); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElement"](9, "line", 1)(10, "line", 2); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵnextContext"](); const length_r5 = ctx_r0.lineLength(); const gap_r6 = ctx_r0.middleGap(); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x", -length_r5)("y", -length_r5)("width", length_r5 * 2)("height", length_r5 * 2)("fill", ctx_r0.rectFill()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.vColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", -length_r5)("y2", -gap_r6)("stroke-width", ctx_r0.vSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", -length_r5)("y2", -gap_r6 + ctx_r0.hitWidth() / 2)("stroke-width", ctx_r0.hitWidth())("stroke", "transparent"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.vColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", gap_r6)("y2", length_r5)("stroke-width", ctx_r0.vSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", gap_r6 - ctx_r0.hitWidth() / 2)("y2", length_r5)("stroke-width", ctx_r0.hitWidth())("stroke", "transparent"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", -length_r5)("x2", -gap_r6)("stroke-width", ctx_r0.hSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", -length_r5)("x2", -gap_r6 + ctx_r0.hitWidth() / 2)("stroke-width", ctx_r0.hitWidth())("stroke", "transparent"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("stroke", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", gap_r6)("x2", length_r5)("stroke-width", ctx_r0.hSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", gap_r6 - ctx_r0.hitWidth() / 2)("x2", length_r5)("stroke-width", ctx_r0.hitWidth())("stroke", "transparent"); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("opacity", 0.2)("stroke", ctx_r0.hColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("x1", -gap_r6)("x2", gap_r6)("stroke-width", ctx_r0.scaledSize()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵstyleProp"]("opacity", 0.2)("stroke", ctx_r0.vColor()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("y1", -gap_r6)("y2", gap_r6)("stroke-width", ctx_r0.scaledSize()); } } // The additional tolerance to add to the hit area outside of the visible line. const HIT_TOLERANCE_PX = 30; class CrosshairComponent { axis = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "axis" }] : [])); viewportId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(undefined, ...(ngDevMode ? [{ debugName: "viewportId" }] : [])); position = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "position" }] : [])); rotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(0, ...(ngDevMode ? [{ debugName: "rotation" }] : [])); size = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(2, ...(ngDevMode ? [{ debugName: "size" }] : [])); hColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('var(--p-app-viewport-axis-axial)', ...(ngDevMode ? [{ debugName: "hColor" }] : [])); vColor = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)('var(--p-app-viewport-axis-sagittal)', ...(ngDevMode ? [{ debugName: "vColor" }] : [])); compact = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(false, ...(ngDevMode ? [{ debugName: "compact" }] : [])); // When in creation / add points mode, turn off crosshair interactivity // so that it doesn't accidentally steal clicks etc. interactionMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_6__.InteractionModeService).interactionMode; rotationQuality = new _viewport_interaction_interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_8__.WheelQualityInteraction((0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.renderSettingsStore)); enabled = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const interactionMode = this.interactionMode(); return interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.InteractionModeType.SELECT; }, ...(ngDevMode ? [{ debugName: "enabled" }] : [])); windowDetails = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_window_details_window_details_service__WEBPACK_IMPORTED_MODULE_9__.WindowDetailsService); screenWidth = this.windowDetails.screenWidth; screenHeight = this.windowDetails.screenHeight; devicePixelRatio = this.windowDetails.devicePixelRatio; scaledSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.size() / this.devicePixelRatio(), ...(ngDevMode ? [{ debugName: "scaledSize" }] : [])); lineLength = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const width = this.screenWidth(); const height = this.screenHeight(); return Math.hypot(width, height); }, ...(ngDevMode ? [{ debugName: "lineLength" }] : [])); hitWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => HIT_TOLERANCE_PX / this.devicePixelRatio(), ...(ngDevMode ? [{ debugName: "hitWidth" }] : [])); hoverAxis = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "hoverAxis" }] : [])); hSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const baseSize = this.scaledSize(); const hoverAxis = this.hoverAxis(); return hoverAxis === 'h' ? baseSize + 2 : baseSize; }, ...(ngDevMode ? [{ debugName: "hSize" }] : [])); vSize = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const baseSize = this.scaledSize(); const hoverAxis = this.hoverAxis(); return hoverAxis === 'v' ? baseSize + 2 : baseSize; }, ...(ngDevMode ? [{ debugName: "vSize" }] : [])); middleGap = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { return 80 / this.devicePixelRatio(); }, ...(ngDevMode ? [{ debugName: "middleGap" }] : [])); shortArmLength = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => 18 / this.devicePixelRatio(), ...(ngDevMode ? [{ debugName: "shortArmLength" }] : [])); shortArmGap = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => 4 / this.devicePixelRatio(), ...(ngDevMode ? [{ debugName: "shortArmGap" }] : [])); shortArmStrokeWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.scaledSize() * 0.5, ...(ngDevMode ? [{ debugName: "shortArmStrokeWidth" }] : [])); // 2px against the default 3px crosshair width, matching the reticle in the reformation demo. centreDotRadius = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.scaledSize() * (2 / 3), ...(ngDevMode ? [{ debugName: "centreDotRadius" }] : [])); rectFill = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)('none', ...(ngDevMode ? [{ debugName: "rectFill" }] : [])); lastAngle; viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore); transform = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { const [x, y] = this.position(); const rotation = this.rotation(); return `translate(${x} ${y}) rotate(${rotation})`; }, ...(ngDevMode ? [{ debugName: "transform" }] : [])); axisHover(axis) { this.hoverAxis.set(axis); } mouseDown(event) { // Only left-click rotates the crosshair. if (event.button !== 0) return; event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); this.lastAngle = this.mouseAngle(event); this.rectFill.set('transparent'); } mouseMove(event) { const startAngle = this.lastAngle; if (startAngle === undefined) { return; } event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); const newAngle = this.mouseAngle(event); const deltaAngle = startAngle - newAngle; this.lastAngle = newAngle; const viewportId = this.viewportId(); if (viewportId && !_viewport_ids__WEBPACK_IMPORTED_MODULE_7__.NON_DEGRADING_VIEWPORT_ID_LIST.includes(viewportId)) { this.rotationQuality.start(); } this.viewportStore.rotateCrosshair(this.axis(), deltaAngle); } mouseUp() { this.lastAngle = undefined; this.rectFill.set('none'); } mouseAngle(event) { const { offsetX, offsetY } = event; const [x, y] = this.position(); const dx = offsetX - x; const dy = offsetY - y; return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.rad2deg)(Math.atan2(dy, dx)); } static ɵfac = function CrosshairComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CrosshairComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdefineComponent"]({ type: CrosshairComponent, selectors: [["", "lib-crosshair", ""]], inputs: { axis: [1, "axis"], viewportId: [1, "viewportId"], position: [1, "position"], rotation: [1, "rotation"], size: [1, "size"], hColor: [1, "hColor"], vColor: [1, "vColor"], compact: [1, "compact"] }, attrs: _c0, decls: 3, vars: 3, consts: [[3, "mousedown", "mousemove", "mouseup"], ["y1", "0", "y2", "0", "pointer-events", "none"], ["x1", "0", "x2", "0", "pointer-events", "none"], ["cx", "0", "cy", "0", "pointer-events", "none"], ["x1", "0", "x2", "0", 3, "mouseover", "mouseout"], ["y1", "0", "y2", "0", 3, "mouseover", "mouseout"]], template: function CrosshairComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementStart"](0, "g", 0); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomListener"]("mousedown", function CrosshairComponent_Template_g_mousedown_0_listener($event) { return ctx.mouseDown($event); })("mousemove", function CrosshairComponent_Template_g_mousemove_0_listener($event) { return ctx.mouseMove($event); })("mouseup", function CrosshairComponent_Template_g_mouseup_0_listener() { return ctx.mouseUp(); }); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditionalCreate"](1, CrosshairComponent_Conditional_1_Template, 5, 23)(2, CrosshairComponent_Conditional_2_Template, 11, 55); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵdomElementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵattribute"]("pointer-events", ctx.enabled() && !ctx.compact() ? "painted" : "none")("transform", ctx.transform()); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_10__["ɵɵconditional"](ctx.compact() ? 1 : 2); } }, encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 71848 /*!*******************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/viewport-overlay/viewport-overlay.component.ts ***! \*******************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ ViewportOverlay: () => (/* binding */ ViewportOverlay) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _crosshair_crosshair_component__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./crosshair/crosshair.component */ 86026); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["svgRoot"]; function ViewportOverlay_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](0, "g", 2); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("size", ctx_r0.crosshairSize())("axis", ctx_r0.viewportAxis())("viewportId", ctx_r0.viewportId())("position", ctx_r0.crosshairCenter())("rotation", ctx_r0.crosshairRotation())("hColor", ctx_r0.crosshairColors().h)("vColor", ctx_r0.crosshairColors().v)("compact", ctx_r0.compact()); } } class ViewportOverlay { viewportId = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "viewportId" }] : [])); viewportAxis = _angular_core__WEBPACK_IMPORTED_MODULE_0__.input.required(...(ngDevMode ? [{ debugName: "viewportAxis" }] : [])); cameraDetails = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(...(ngDevMode ? [undefined, { debugName: "cameraDetails" }] : [])); crosshairRotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(0, ...(ngDevMode ? [{ debugName: "crosshairRotation" }] : [])); crosshairColors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)({ h: 'var(--p-app-viewport-axis-axial)', v: 'var(--p-app-viewport-axis-sagittal)' }, ...(ngDevMode ? [{ debugName: "crosshairColors" }] : [])); compact = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.input)(false, ...(ngDevMode ? [{ debugName: "compact" }] : [])); svgRoot = _angular_core__WEBPACK_IMPORTED_MODULE_0__.viewChild.required('svgRoot'); renderingEngine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_3__.RenderingEngineService); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.viewportStore); orchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_5__.VolumeViewerOrchestrator); crosshairSize = this.viewportStore.crosshairSize; constructor() { setTimeout(() => this.checkForViewport(), 10); } showCrosshairs = this.viewportStore.showCrosshairs; // TODO: Find better way to trigger the crosshair update after // the viewport is initialized checkForViewport() { const viewportId = this.viewportId(); const viewport = this.renderingEngine.getActiveViewports().find(viewport => viewport.id === viewportId); if (viewport) { this.viewportStore.updateIntersection([...this.viewportStore.intersection()]); } else { setTimeout(() => this.checkForViewport(), 10); } } crosshairCenter = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this.orchestrator.cacheBuster(); this.orchestrator.crosshairCacheBuster(); this.cameraDetails(); // Works like a cache buster currently const viewportId = this.viewportId(); const svg = this.svgRoot().nativeElement; const intersection = this.viewportStore.intersection(); const viewport = this.renderingEngine.getActiveViewports().find(viewport => viewport.id === viewportId); if (!viewport) { return [svg.clientWidth / 2, svg.clientHeight / 2]; } return viewport.worldToCanvas([...intersection]); }, ...(ngDevMode ? [{ debugName: "crosshairCenter" }] : [])); static ɵfac = function ViewportOverlay_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewportOverlay)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵdefineComponent"]({ type: ViewportOverlay, selectors: [["lib-viewport-overlay"]], viewQuery: function ViewportOverlay_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵviewQuerySignal"](ctx.svgRoot, _c0, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵqueryAdvance"](); } }, inputs: { viewportId: [1, "viewportId"], viewportAxis: [1, "viewportAxis"], cameraDetails: [1, "cameraDetails"], crosshairRotation: [1, "crosshairRotation"], crosshairColors: [1, "crosshairColors"], compact: [1, "compact"] }, decls: 3, vars: 1, consts: [["svgRoot", ""], [1, "absolute", "z-[1]", "h-full", "w-full", "overflow-hidden"], ["lib-crosshair", "", 3, "size", "axis", "viewportId", "position", "rotation", "hColor", "vColor", "compact"]], template: function ViewportOverlay_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵnamespaceSVG"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "svg", 1, 0); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditionalCreate"](2, ViewportOverlay_Conditional_2_Template, 1, 8, ":svg:g", 2); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditional"](ctx.showCrosshairs() ? 2 : -1); } }, dependencies: [_crosshair_crosshair_component__WEBPACK_IMPORTED_MODULE_6__.CrosshairComponent], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 60538 /*!********************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/volume-rendering-popover.service.ts ***! \********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VolumeRenderingPopoverService: () => (/* binding */ VolumeRenderingPopoverService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./viewport-ids */ 85309); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./volume-viewer-orchestrator.service */ 66035); class VolumeRenderingPopoverService { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_6__.getLogger)(VolumeRenderingPopoverService.name); viewerOrchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_8__.VolumeViewerOrchestrator); renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_4__.renderSettingsStore); engine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_2__.RenderingEngineService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_1__.TranslateService); clippingRangeMin = 0; clippingRangeMax = 150; sliceGap = 1; seriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)('', ...(ngDevMode ? [{ debugName: "seriesUid" }] : [])); getVolumeScalarRange = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.getVolumeScalarRange; onDragStart = () => this.viewerOrchestrator.decrease3dViewportImageQuality(); onDragEnd = () => this.viewerOrchestrator.increase3dViewportImageQuality(); get scalarRange() { return this.getVolumeScalarRange((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.getViewport)(this.engine.ENGINE_ID, _viewport_ids__WEBPACK_IMPORTED_MODULE_7__.VIEWPORT_IDS.REFORMAT)); } getVolumeRenderingFormConfig() { const seriesWindow = this.viewerOrchestrator.seriesWindowState(this.seriesUid()); if (!seriesWindow) { this.log.error(`Series window state not found for series UID: ${this.seriesUid()}`); return []; } const options = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(Object.values(_tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS).map(({ label, selectedPreset: value }) => ({ label, value })), ...(ngDevMode ? [{ debugName: "options" }] : [])); const defaultOption = this.renderSettingsStore.volumeSettings(); const currentOption = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(defaultOption ?? _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.FLUOROSCOPIC], ...(ngDevMode ? [{ debugName: "currentOption" }] : [])); let presetSpecific = []; switch (currentOption().selectedPreset) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.ENDO: { presetSpecific = this.getEndovascularSliders(defaultOption); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.FLUOROSCOPIC: case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.XRAY: { presetSpecific = this.getFluoroscopyXraySliders(defaultOption); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.MIP: { presetSpecific = this.getMipSliders(defaultOption); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.VASCULAR: { presetSpecific = this.getVascularSliders(defaultOption); break; } } return [...this.getPresetSelectConfig(options, defaultOption), ...presetSpecific, ...this.getClippingSliders(defaultOption)]; } getPresetSelectConfig(options, defaultOption) { return [{ defaultValue: defaultOption.selectedPreset, label: 'volumeRenderingSettings.preset', name: 'selectedPreset', onChange: form => { const selectedPresetValue = form.selectedPreset().value(); this.renderSettingsStore.selectVolumePreset(selectedPresetValue); const preset = this.renderSettingsStore.volumeSettings(); if (!preset) return; }, options, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SELECT }]; } getFluoroscopyXraySliders(defaultOption) { const presetDefault = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[defaultOption.selectedPreset]; return [{ defaultValue: defaultOption.threshold ?? 0, label: 'volumeRenderingSettings.threshold', max: this.scalarRange[1], min: this.scalarRange[0], name: 'threshold', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ threshold: form.threshold?.().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.threshold?.().value.set(presetDefault.threshold); this.renderSettingsStore.updateVolumeSettings({ threshold: presetDefault.threshold }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.brightness ?? 0, disabled: this.renderSettingsStore.volumeSettings()?.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.ENDO, hasDivider: true, label: 'volumeRenderingSettings.brightness', max: 1.5, min: -1, name: 'brightness', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ brightness: form.brightness?.().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.brightness?.().value.set(presetDefault.brightness); this.renderSettingsStore.updateVolumeSettings({ brightness: presetDefault.brightness }); }, step: 0.01, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }]; } /** MIP just projects the highest HU along each ray, so the result is a plain HU image - windowed * with width/level like any other CT image (MPR included), not the attenuation curve fluoro/ * xray use. Reuses their threshold/brightness field names under the hood (threshold = window * width, brightness = window level), but the sliders are labeled Window width/level since * that's what they actually are; bounds are MIP-specific, mirroring the MPR window drag * interaction's own (window-settings-interaction.ts) rather than fluoro/xray's ranges. */ getMipSliders(defaultOption) { const presetDefault = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.MIP]; const [scalarMin, scalarMax] = this.scalarRange; const windowWidthMax = Math.max(1, (scalarMax - scalarMin) * 2); return [{ defaultValue: defaultOption.threshold ?? 0, label: 'volumeRenderingSettings.windowWidth', max: windowWidthMax, min: 1, name: 'threshold', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ threshold: form.threshold?.().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.threshold?.().value.set(presetDefault.threshold); this.renderSettingsStore.updateVolumeSettings({ threshold: presetDefault.threshold }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.brightness ?? 0, hasDivider: true, label: 'volumeRenderingSettings.windowLevel', max: scalarMax, min: scalarMin, name: 'brightness', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ brightness: form.brightness?.().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.brightness?.().value.set(presetDefault.brightness); this.renderSettingsStore.updateVolumeSettings({ brightness: presetDefault.brightness }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }]; } getEndovascularSliders(defaultOption) { const presetDefault = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.ENDO]; return [{ defaultValue: defaultOption.airTissueThreshold ?? 0, label: 'volumeRenderingSettings.airTissueThreshold', max: form => form.tissueBloodThreshold?.().value() ?? 0, min: this.scalarRange[0], name: 'airTissueThreshold', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ airTissueThreshold: form.airTissueThreshold?.().value() ?? 0 }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.airTissueThreshold?.().value.set(presetDefault.airTissueThreshold); this.renderSettingsStore.updateVolumeSettings({ airTissueThreshold: presetDefault.airTissueThreshold }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.tissueBloodThreshold ?? 0, label: 'volumeRenderingSettings.tissueBloodThreshold', max: form => form.bloodCalciumThreshold?.().value() ?? 0, min: form => form.airTissueThreshold?.().value() ?? 0, name: 'tissueBloodThreshold', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ tissueBloodThreshold: form.tissueBloodThreshold?.().value() ?? 0 }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.tissueBloodThreshold?.().value.set(presetDefault.tissueBloodThreshold); this.renderSettingsStore.updateVolumeSettings({ tissueBloodThreshold: presetDefault.tissueBloodThreshold }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.bloodCalciumThreshold ?? 0, hasDivider: true, label: 'volumeRenderingSettings.bloodCalciumThreshold', max: this.scalarRange[1], min: form => form.tissueBloodThreshold?.().value() ?? 0, name: 'bloodCalciumThreshold', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ bloodCalciumThreshold: form.bloodCalciumThreshold?.().value() ?? 0 }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { form.bloodCalciumThreshold?.().value.set(presetDefault.bloodCalciumThreshold); this.renderSettingsStore.updateVolumeSettings({ bloodCalciumThreshold: presetDefault.bloodCalciumThreshold }); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }]; } getVascularSliders(defaultOption) { const presetDefault = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VolumeRenderingOption.VASCULAR]; // While previewing, the tissue-blood/blood-calcium sliders drive the segmentation's // minHU/maxHU bounds instead of the color-ramp thresholds — before preview and // after accept, they drive the color ramp as usual. const isPreviewing = this.viewerOrchestrator.vascularSegmentationState() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VascularSegmentationState.PREVIEWING; return [{ defaultValue: (isPreviewing ? defaultOption.minHU : defaultOption.tissueBloodThreshold) ?? 0, label: 'volumeRenderingSettings.tissueBloodThreshold', // Stays strictly below bloodCalciumThreshold — equal thresholds collapse the // CLUT remap (see remapClutToThresholds) to a single degenerate x-value. max: form => (form.bloodCalciumThreshold?.().value() ?? 0) - 1, min: this.scalarRange[0], name: 'tissueBloodThreshold', onChange: form => { const value = form.tissueBloodThreshold?.().value() ?? 0; if (isPreviewing) { this.renderSettingsStore.updateVolumeSettings({ minHU: value }); this.livePreviewFromSettings(); return; } this.renderSettingsStore.updateVolumeSettings({ tissueBloodThreshold: value, vascularThresholdsAutoTuned: true }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, onSlideEnd: () => this.rePreviewIfPreviewing(), resetEvent: form => { if (isPreviewing) { form.tissueBloodThreshold?.().value.set(presetDefault.minHU); this.renderSettingsStore.updateVolumeSettings({ minHU: presetDefault.minHU }); this.rePreviewIfPreviewing(); return; } // Prefer this session's histogram-computed default over the static preset, // so "reset" restores the scan-specific starting point once one exists. const resetValue = defaultOption.vascularSessionDefaultTissueBloodThreshold ?? presetDefault.tissueBloodThreshold; form.tissueBloodThreshold?.().value.set(resetValue); this.renderSettingsStore.updateVolumeSettings({ tissueBloodThreshold: resetValue, // A deliberate reset — must not look "untouched" and re-trigger the auto-tune. vascularThresholdsAutoTuned: true }); }, tooltip: this.translate.instant(isPreviewing ? 'volumeRenderingSettings.tissueBloodThresholdPreviewTooltip' : 'volumeRenderingSettings.tissueBloodThresholdTooltip'), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: (isPreviewing ? defaultOption.maxHU : defaultOption.bloodCalciumThreshold) ?? 0, hasDivider: false, label: 'volumeRenderingSettings.bloodCalciumThreshold', max: this.scalarRange[1], // Stays strictly above tissueBloodThreshold — see the matching comment there. min: form => (form.tissueBloodThreshold?.().value() ?? 0) + 1, name: 'bloodCalciumThreshold', onChange: form => { const value = form.bloodCalciumThreshold?.().value() ?? 0; if (isPreviewing) { this.renderSettingsStore.updateVolumeSettings({ maxHU: value }); this.livePreviewFromSettings(); return; } this.renderSettingsStore.updateVolumeSettings({ bloodCalciumThreshold: value, vascularThresholdsAutoTuned: true }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, onSlideEnd: () => this.rePreviewIfPreviewing(), resetEvent: form => { if (isPreviewing) { form.bloodCalciumThreshold?.().value.set(presetDefault.maxHU); this.renderSettingsStore.updateVolumeSettings({ maxHU: presetDefault.maxHU }); this.rePreviewIfPreviewing(); return; } // Prefer this session's histogram-computed default over the static preset, // so "reset" restores the scan-specific starting point once one exists. const resetValue = defaultOption.vascularSessionDefaultBloodCalciumThreshold ?? presetDefault.bloodCalciumThreshold; form.bloodCalciumThreshold?.().value.set(resetValue); this.renderSettingsStore.updateVolumeSettings({ bloodCalciumThreshold: resetValue, // A deliberate reset — must not look "untouched" and re-trigger the auto-tune. vascularThresholdsAutoTuned: true }); }, tooltip: this.translate.instant(isPreviewing ? 'volumeRenderingSettings.bloodCalciumThresholdPreviewTooltip' : 'volumeRenderingSettings.bloodCalciumThresholdTooltip'), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.outlierOpacity ?? 0, // Only takes effect once a mask is applied — the shader doesn't // consult it before then (pre-mask/previewing all voxels render // through the normal CT ramp). disabled: this.viewerOrchestrator.vascularSegmentationState() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VascularSegmentationState.APPLIED, hasDivider: true, label: 'volumeRenderingSettings.outlierOpacity', max: 1, min: 0, name: 'outlierOpacity', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ outlierOpacity: form.outlierOpacity?.().value() ?? 0 }); }, resetEvent: form => { form.outlierOpacity?.().value.set(presetDefault.outlierOpacity); this.renderSettingsStore.updateVolumeSettings({ outlierOpacity: presetDefault.outlierOpacity }); }, step: 0.01, tooltip: this.translate.instant('volumeRenderingSettings.outlierOpacityTooltip'), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, ...this.getVascularSegmentationButtons()]; } rePreviewIfPreviewing() { if (this.viewerOrchestrator.vascularSegmentationState() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VascularSegmentationState.PREVIEWING) { this.viewerOrchestrator.previewVascularMask(); } } /** The onChange handlers write the store first, so current settings carry * the dragged value. */ livePreviewFromSettings() { const settings = this.renderSettingsStore.volumeSettings(); if (!('minHU' in settings)) return; this.viewerOrchestrator.previewVascularMaskLive({ clusterSize: settings.clusterSize, erosionRadius: settings.erosionRadius, gridStep: settings.gridStep, maxHU: settings.maxHU, minHU: settings.minHU }); } getVascularSegmentationButtons() { const state = this.viewerOrchestrator.vascularSegmentationState(); if (state === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VascularSegmentationState.APPLIED) { return [{ defaultValue: 0, hasDivider: true, label: 'volumeRenderingSettings.revertSegmentation', name: 'revertSegmentation', onClick: () => this.viewerOrchestrator.revertVascularMask(), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.BUTTON }]; } if (state === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.VascularSegmentationState.PREVIEWING) { const computing = this.viewerOrchestrator.vascularMaskComputing(); return [{ defaultValue: 0, disabled: computing, hasDivider: false, label: 'volumeRenderingSettings.acceptSegmentation', name: 'acceptSegmentation', onClick: () => this.viewerOrchestrator.acceptVascularMask(), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.BUTTON }, { defaultValue: 0, disabled: computing, hasDivider: true, label: 'volumeRenderingSettings.refuseSegmentation', name: 'refuseSegmentation', onClick: () => this.viewerOrchestrator.refuseVascularMask(), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.BUTTON }]; } return [{ defaultValue: 0, hasDivider: true, label: 'volumeRenderingSettings.previewSegmentation', name: 'previewSegmentation', onClick: () => this.viewerOrchestrator.previewVascularMask(), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.BUTTON }]; } getClippingSliders(defaultOption) { const presetDefault = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_5__.VOLUME_RENDERING_PRESETS[defaultOption.selectedPreset]; return [{ defaultValue: Math.abs(defaultOption.distalDepth), label: 'volumeRenderingSettings.distalDepth', max: this.clippingRangeMax, // Store is the negated magnitude; floor at sliceGap so an unrepresentable 0 can't desync it from the display. min: this.sliceGap, name: 'distalDepth', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ distalDepth: -form.distalDepth().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { const { distalDepth } = presetDefault; this.renderSettingsStore.updateVolumeSettings({ distalDepth }); form.distalDepth().value.set(Math.abs(distalDepth)); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.proximalDepth, label: 'volumeRenderingSettings.proximalDepth', max: this.clippingRangeMax, min: this.clippingRangeMin, name: 'proximalDepth', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ proximalDepth: form.proximalDepth().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { const { proximalDepth } = presetDefault; this.renderSettingsStore.updateVolumeSettings({ proximalDepth }); form.proximalDepth().value.set(proximalDepth); }, step: 2, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }, { defaultValue: defaultOption.imageQuality, label: 'volumeRenderingSettings.imageQuality', max: 110, min: 0, name: 'imageQuality', onChange: form => { this.renderSettingsStore.updateVolumeSettings({ imageQuality: form.imageQuality().value() }); }, onDragEnd: this.onDragEnd, onDragStart: this.onDragStart, resetEvent: form => { const { imageQuality } = presetDefault; this.renderSettingsStore.updateVolumeSettings({ imageQuality }); form.imageQuality().value.set(imageQuality); }, step: 0.1, type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_3__.SettingsPopoverField.SLIDER }]; } static ɵfac = function VolumeRenderingPopoverService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || VolumeRenderingPopoverService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: VolumeRenderingPopoverService, factory: VolumeRenderingPopoverService.ɵfac }); } /***/ }, /***/ 66035 /*!**********************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/volume-viewer-orchestrator.service.ts ***! \**********************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VolumeViewerOrchestrator: () => (/* binding */ VolumeViewerOrchestrator) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @cornerstonejs/core */ 50600); /* harmony import */ var _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @cornerstonejs/core */ 38277); /* harmony import */ var _kitware_vtk_js_Rendering_OpenGL_VolumeMapper__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @kitware/vtk.js/Rendering/OpenGL/VolumeMapper */ 54143); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! gl-matrix */ 87396); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxdb */ 99984); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @tomoverse/selectors */ 27531); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _work_session_work_session_service__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../work-session/work-session.service */ 82757); /* harmony import */ var _camera_animation_service__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./camera-animation.service */ 76045); /* harmony import */ var _cpr_cpr_config__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./cpr/cpr-config */ 17924); /* harmony import */ var _provide_volume_viewer__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./provide-volume-viewer */ 21321); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./viewport-ids */ 85309); /* harmony import */ var _viewport_interaction_interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./viewport-interaction/interactions/wheel-quality-interaction */ 78730); const VASCULAR_REAPPLY_ERROR = 'Failed to re-apply vascular mask'; // minHU/maxHU are the segmentation-inclusive bounds, not the ramp's own color-transition // points - they need to stay wider than tissueBloodThreshold/bloodCalciumThreshold or // voxels just outside the ramp but still legitimately tissue/blood/calcium get excluded // from segmentation entirely. Margins match the static preset's own relationship (170 vs // 215, 1000 vs 588) so a per-scan auto-tuned ramp gets the same proportional headroom. const VASCULAR_MIN_HU_MARGIN = 45; const VASCULAR_MAX_HU_MARGIN = 412; class VolumeViewerOrchestrator { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_16__.getLogger)(VolumeViewerOrchestrator.name); engine = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.RenderingEngineService); state = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_14__.volumeViewerStore); loader = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.VolumeLoaderService); status = this.state.status; imageIdsError = this.state.imageIdsError; viewportStates = this.state.viewportStates; isCachingSource = this.loader.isCachingSource; renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_14__.renderSettingsStore); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_14__.viewportStore); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_14__.AnnotationFacade); cameraAnimation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_camera_animation_service__WEBPACK_IMPORTED_MODULE_18__.CameraAnimationService); workSessionService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_work_session_work_session_service__WEBPACK_IMPORTED_MODULE_17__.WorkSessionService); workSessionLoaded$ = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_3__.toObservable)(this.workSessionService.workSessionLoaded); volumeLoaderService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_11__.VolumeLoaderService); cleanupFunctions = []; rotationQuality = new _viewport_interaction_interactions_wheel_quality_interaction__WEBPACK_IMPORTED_MODULE_22__.WheelQualityInteraction(this.renderSettingsStore); effectsReady = false; _cacheBuster = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "_cacheBuster" }] : [])); get cacheBuster() { return this._cacheBuster; } _crosshairCacheBuster = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "_crosshairCacheBuster" }] : [])); get crosshairCacheBuster() { return this._crosshairCacheBuster; } _annotationScaleCacheBuster = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "_annotationScaleCacheBuster" }] : [])); get annotationScaleCacheBuster() { return this._annotationScaleCacheBuster; } forceRerender() { this._cacheBuster.update(version => version + 1); } cameraRendered = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "cameraRendered" }] : [])); // The canvas keeps its default black until volumeSettingsEffect first paints it, which waits on // the work session and the volume. Until then the preset says nothing about what is on screen. volumeBackgroundPainted = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "volumeBackgroundPainted" }] : [])); volumeBackgroundIsLight = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.volumeBackgroundPainted() && this.renderSettingsStore.volumeSettings().selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.FLUOROSCOPIC, ...(ngDevMode ? [{ debugName: "volumeBackgroundIsLight" }] : [])); resetCameraRendered() { this.cameraRendered.set(false); } renderStoredCameras() { const viewportCamera = this.viewportStore.viewportCameras(); const { distalDepth, proximalDepth } = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.renderSettingsStore.volumeSettings()); for (const [viewportId, camera] of Object.entries(viewportCamera)) { const viewport = this.engine.getViewport(viewportId); viewport?.setCamera({ ...camera }); if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"] && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.hasVolumeActor)(viewport)) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.adjustProximalAndDistalClippingPlanes)(viewport, proximalDepth, distalDepth, false); } } this.engine.renderAll(); this.cameraRendered.set(true); } constructor() { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_provide_volume_viewer__WEBPACK_IMPORTED_MODULE_20__.VOLUME_VIEWER_OPTIONS, { optional: true }); this.engine.init().catch(error => this.log.error('Engine init failed', error)); } initEffects() { if (this.effectsReady) return; this.registerContextLostEvents(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.assertInInjectionContext)(this.initEffects); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const preset = this.renderSettingsStore.volumeSettings.selectedPreset(); const maximized = this.reformatMaximized(); const previewing = this.vascularSegmentationState() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING; (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { if (preset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) { this.idleImageQuality.set(maximized || previewing ? 70 : 90); } else { this.idleImageQuality.set(100); } }); }); // Keep the persisted enum in sync with the live signal, so save/reload has an // accurate record of where the segmentation flow currently is. (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const state = this.vascularSegmentationState(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { const settings = this.renderSettingsStore.volumeSettings(); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; this.renderSettingsStore.updateVolumeSettings({ vascularSegmentationState: state }); }); }); const cameraEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this._cacheBuster(); const ready = this.workSessionService.workSessionLoaded(); this.viewportStore.viewportCameras(); if (!ready) { return; } this.renderStoredCameras(); // The crosshair overlay projects through a live `worldToCanvas` that no signal reports. this._crosshairCacheBuster.update(version => version + 1); }, ...(ngDevMode ? [{ debugName: "cameraEffect" }] : [])); // Only update the headlight when the camera actually rotates (not on every mouse move). // Calling updateLightsGeometryToFollowCamera inside cameraEffect fires on every // intersection change (crosshair move), which runs on every mouse move and causes // light.modified() to mark VTK state dirty every frame, causing annotation creation flicker. const lightEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this._cacheBuster(); const ready = this.workSessionService.workSessionLoaded(); this.viewportStore.viewportAngulations(); this.viewportStore.isPosterior(); const selectedPreset = this.renderSettingsStore.volumeSettings.selectedPreset(); if (!ready) return; const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"] && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.hasVolumeActor)(viewport)) { viewport.getRenderer().updateLightsGeometryToFollowCamera?.(); if (selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.ENDO) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.raiseViewportKeyLight)(viewport); } const overlayRenderer = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.getAnnotationOverlayRenderer)(viewport.id); if (overlayRenderer) { for (const light of overlayRenderer.getLights()) { light.setLightTypeToHeadLight(); } overlayRenderer.updateLightsGeometryToFollowCamera?.(); } // Headlights exist only on the REFORMAT renderer; cameraEffect renders the MPRs. this.engine.renderViewports([_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT]); } }, ...(ngDevMode ? [{ debugName: "lightEffect" }] : [])); const volumeSettingsEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this._cacheBuster(); const ready = this.workSessionService.workSessionLoaded(); const settings = this.renderSettingsStore.volumeSettings(); const { distalDepth, proximalDepth, selectedPreset: presetName } = settings; const { brightness, presetSpecificSettings, threshold } = this.resolvePresetRenderParams(settings); // Will only change when volumeSettings change anyway const darkMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.renderSettingsStore.volumeIsDarkMode()); if (!ready) { return; } const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; const bg = darkMode ? 0 : 1; this.handleVascularPresetSwitch(viewport, presetName); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.maybeAutoTuneVascularThresholds(viewport, settings)); // On first run after session load, re-apply if segmentation was previously accepted if (this._lastPreset === undefined && presetName === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR && this.shouldReapplyVascularMask(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE, settings)) { (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { this.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.APPLIED); this.runVascularMask('apply').catch(error => this.log.error(VASCULAR_REAPPLY_ERROR, error)); }); } this.engine.updateVolume3dViewportWindow({ brightness, lighting: presetSpecificSettings, presetName, render: true, threshold, thresholds: presetSpecificSettings, volume3dViewport: viewport, widths: presetSpecificSettings }); if (presetName === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.XRAY || presetName === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.MIP) { viewport.getRenderer().setBackground(0, 0, 0); } else if (presetName === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.FLUOROSCOPIC) { viewport.getRenderer().setBackground(1, 1, 1); } else { viewport.getRenderer().setBackground(bg, bg, bg); } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.adjustProximalAndDistalClippingPlanes)(viewport, proximalDepth, distalDepth, false); viewport.render(); this.volumeBackgroundPainted.set(true); this._lastPreset = presetName; }, ...(ngDevMode ? [{ debugName: "volumeSettingsEffect" }] : [])); // Separated from volumeSettingsEffect so that setLowQuality(true/false) on mousedown // does not re-trigger the full preset re-application and cause the 3D surface to flash. const qualityEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { const ready = this.workSessionService.workSessionLoaded(); const imageQuality = this.renderSettingsStore.volumeSettings.imageQuality(); this.renderSettingsStore.volumeSettings.selectedPreset(); const forceLowQuality = this.renderSettingsStore.forceLowQuality(); if (!ready) return; const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; const degrade = forceLowQuality && imageQuality < 100; if (degrade) { this.swapToLodVolume(viewport); } else { this.restoreFullResVolume(viewport); } this.scheduleQualityRender(viewport, degrade); }, ...(ngDevMode ? [{ debugName: "qualityEffect" }] : [])); const windowEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this._cacheBuster(); const ready = this.workSessionService.workSessionLoaded(); const windowSettings = this.renderSettingsStore.windowSettings(); if (!ready) { return; } this.engine.updateMPRWindow(windowSettings.width, windowSettings.level); }, ...(ngDevMode ? [{ debugName: "windowEffect" }] : [])); const zoomEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.effect)(() => { this._cacheBuster(); const zoom = this.viewportStore.zoom(); const { distalDepth, proximalDepth } = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.renderSettingsStore.volumeSettings()); for (const viewport of this.engine.getActiveViewports()) { // The CPR carriers are orchestrator-unregistered and hold their own fixed-FOV // cameras; `setZoom` rescales off the fit-to-canvas camera and would drop them // to whole-volume zoom until their next explicit camera write. if ((0,_cpr_cpr_config__WEBPACK_IMPORTED_MODULE_19__.isCprCarrierViewportId)(viewport.id)) continue; viewport.setZoom(zoom); if (viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"] && (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.hasVolumeActor)(viewport)) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.adjustProximalAndDistalClippingPlanes)(viewport, proximalDepth, distalDepth, false); } } this.engine.renderAll(); // Ensure the crosshair updates this._crosshairCacheBuster.update(version => version + 1); this._annotationScaleCacheBuster.update(version => version + 1); }, ...(ngDevMode ? [{ debugName: "zoomEffect" }] : [])); (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_1__.DestroyRef).onDestroy(() => { cameraEffect.destroy(); lightEffect.destroy(); qualityEffect.destroy(); volumeSettingsEffect.destroy(); windowEffect.destroy(); zoomEffect.destroy(); this.cameraAnimation.cancel(); this.cleanup(); }); this.effectsReady = true; } /** Whether the loaded series appeared multiphase but could not be separated. */ wasSeriesUnseparable(seriesUid, studyUid, storeUid) { return this.state.wasSeriesUnseparable(studyUid, seriesUid, storeUid); } seriesPhases(seriesUid) { return this.state.seriesPhasesState(seriesUid); } phaseSelection(seriesUid) { return this.state.phaseSelectionState(seriesUid); } setPhaseSelection(seriesUid, availablePhaseIds, activePhaseId) { this.state.setPhaseSelection(seriesUid, { activePhaseId, availablePhaseIds }); } switchActiveVolume(fromPhaseId, toPhaseId) { this.workSessionService.switchActiveVolume(fromPhaseId, toPhaseId); this.reapplyVascularStateForPhaseSwitch().catch(error => this.log.error(VASCULAR_REAPPLY_ERROR, error)); } /** * workSessionService.switchActiveVolume (just above) already swaps the whole * renderSettingsStore snapshot for the new phase, so its persisted minHU/maxHU/ * tissueBloodThreshold/etc. round-trip correctly on their own. What doesn't follow that * swap: vascularSegmentationState is a single live signal here, not derived from the * store, so it still reflects the phase being switched away from; and the GPU mask * itself is attached to the volume/mapper the caller's setActiveVolume just replaced, * so there's nothing to visually show for the new phase yet even once the signal is * corrected. Re-sync the signal and reapply/restore the mask to match the new phase's * own persisted state - mirroring handleVascularPresetSwitch's "switching to vascular" * branch, but triggered by a phase change with the preset held constant, which * handleVascularPresetSwitch's _lastPreset comparison never sees. */ reapplyVascularStateForPhaseSwitch() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const settings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this.renderSettingsStore.volumeSettings()); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; // Re-sync the live signal to the new phase's persisted state regardless of whether a // REFORMAT viewport exists right now - reattachVascularMaskAfterViewportRebuild reads // this same signal later if/when the viewport (re)builds, and needs it to already // reflect the new phase rather than whichever one was active when this ran. Only the // GPU reapplication below actually needs a live viewport. const segState = settings.vascularSegmentationState; _this.vascularSegmentationState.set(segState); const viewport = _this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; _this._vascularRunGeneration++; _this.cancelTrailingExactRePreview(); _this._livePreviewPending = undefined; // Cancel rather than wait out a full-resolution exact run left over from the old phase - // it can take seconds, and the phase switch shouldn't stall on it. if (_this._maskRunning) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cancelVascularFullRun)(); // Bumping the generation above only marks any in-flight runVascularMask/drainLivePreview // tick as stale for the next time IT checks - it doesn't stop it mid-flight, and once it // does notice, it still runs its own now-stale cleanup (discardStaleVascularResult), which // unconditionally detaches whatever mask is currently attached. Drain every such call // fully - not just whichever one happens to be tracked most recently, and including any // pending-mode continuation one chains into on completion - before attaching the new // phase's mask below, or a stale cleanup can land afterward and rip out what we just // attached, even a mask restored instantly from the exact cache. while (_this._activeVascularOperations.size > 0) { yield Promise.all(_this._activeVascularOperations); } if (segState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING) { _this.runMaskUnlessCached(viewport, 'preview'); return; } if (_this.shouldReapplyVascularMask(segState, settings)) { _this.runMaskUnlessCached(viewport, 'apply'); } })(); } get requestedActiveVolume() { return this.state.requestedActiveVolume; } clearRequestedActiveVolume() { this.state.requestActiveVolume(undefined); } whenWorkSessionLoaded() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this2.workSessionService.workSessionLoaded()) return; yield (0,rxjs__WEBPACK_IMPORTED_MODULE_4__.firstValueFrom)(_this2.workSessionLoaded$.pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_5__.filter)(Boolean))); })(); } loadSeries(seriesUid, studyUid, storeUid, selectedPhaseIds) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const imageIds = yield _this3.state.loadSeries(studyUid, seriesUid, storeUid, selectedPhaseIds); if (imageIds.length === 0) { _this3.state.setStatus('idle'); } return imageIds; } catch (error) { _this3.log.error('Failed to load series images', error); _this3.state.setStatus('error'); _this3.state.setImageIdsError(error); return []; } })(); } /** * Building the MPR/3D volumes from cached image binaries (loadVolumeImages) has no * error handling of its own upstream - an unhandled rejection here used to leave * status stuck at 'loading' forever (only a full page reload recovered), instead of * surfacing the same error state loadSeries already reports. */ reportVolumeLoadError(error) { this.log.error('Failed to load volume images', error); this.state.setStatus('error'); this.state.setImageIdsError(error); } resetForSeriesChange() { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this4.workSessionService.resetWorkSessionLoaded(); const viewports = _this4.state.registeredViewports(); for (const viewportId of Object.keys(viewports)) { _this4.engine.disable(viewportId); } _this4.volumeBackgroundPainted.set(false); _this4.state.resetForSeriesChange(); _this4.viewportStore.resetState(); _this4.resetVascularState(); yield _this4.engine.init(); })(); } resetVascularState() { this._vascularRunGeneration++; // A live worker would keep the previous study's volume resident indefinitely. (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.releaseVascularWorkers)(); this.cancelTrailingExactRePreview(); this._livePreviewPending = undefined; this.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE); this.vascularMaskComputing.set(false); this._maskRunning = false; this._pendingMaskMode = undefined; this._lastPreset = undefined; } setActiveVolume(volumeIds) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this5.engine.setActiveVolume(volumeIds); })(); } reapplyVolumeRenderSettings() { const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; const settings = this.renderSettingsStore.volumeSettings(); const { distalDepth, proximalDepth, selectedPreset: presetName } = settings; const { brightness, presetSpecificSettings, threshold } = this.resolvePresetRenderParams(settings); this.engine.updateVolume3dViewportWindow({ brightness, lighting: presetSpecificSettings, presetName, render: false, threshold, thresholds: presetSpecificSettings, volume3dViewport: viewport, widths: presetSpecificSettings }); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.adjustProximalAndDistalClippingPlanes)(viewport, proximalDepth, distalDepth, false); } // Bumped here since this is the one call site both the initial load and every // phase switch route through once their volume is ready (see loadSeries's // caller and onSelectVolume in volume-viewer.component.ts) - the pixel-range // computeds below key off it so they re-read the new volume's real range // instead of returning a stale value cached from before the load/switch. _volumeRangeRevision = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(0, ...(ngDevMode ? [{ debugName: "_volumeRangeRevision" }] : [])); setVolumeCenter(volumeId) { this._volumeRangeRevision.update(revision => revision + 1); const volume = volumeId ? _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_7__["default"].getVolume(volumeId) : (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.getPrimaryImageVolume)(); if (volume) { const { dimensions, direction, origin, spacing } = volume; const halfInMM = gl_matrix__WEBPACK_IMPORTED_MODULE_9__.fromValues((dimensions[0] * spacing[0] - 1) / 2, (dimensions[1] * spacing[1] - 1) / 2, (dimensions[2] * spacing[2] - 1) / 2); const rotated = gl_matrix__WEBPACK_IMPORTED_MODULE_9__.transformMat3(gl_matrix__WEBPACK_IMPORTED_MODULE_9__.create(), halfInMM, direction); const center = gl_matrix__WEBPACK_IMPORTED_MODULE_9__.add(gl_matrix__WEBPACK_IMPORTED_MODULE_9__.create(), origin, rotated); this.viewportStore.setVolumeDetails([center[0], center[1], center[2]]); } } registerContextLostEvents() { const offscreenCanvas = this.engine.getRenderWindow()?.getCanvas(); if (!offscreenCanvas) { this.log.warn('Offscreen canvas not found, skipping context lost event registration'); return; } const contextLostHandler = event => { event.preventDefault(); // enables the webglcontextrestored event to be delivered this.engine.destroy(); }; const contextRestoredHandler = /*#__PURE__*/function () { var _ref = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { globalThis.location.reload(); }); return function contextRestoredHandler() { return _ref.apply(this, arguments); }; }(); offscreenCanvas.addEventListener('webglcontextlost', contextLostHandler, false); offscreenCanvas.addEventListener('webglcontextrestored', contextRestoredHandler, false); this.cleanupFunctions.push(() => { offscreenCanvas.removeEventListener('webglcontextlost', contextLostHandler, false); offscreenCanvas.removeEventListener('webglcontextrestored', contextRestoredHandler, false); }); } registerViewport(element, options, seriesUid) { this.state.registerViewport(element, options, seriesUid); } deregisterViewport(viewportId) { this.state.deregisterViewport(viewportId); } increase3dViewportImageQuality() { // Let qualityEffect restore sample distance AND fluoro opacity together in one render. this.renderSettingsStore.setLowQuality(false); } decrease3dViewportImageQuality() { // Use this flag instead of directly setting the quality // so that we can easily restore the configured value this.renderSettingsStore.setLowQuality(true); } _qualityRenderScheduled = false; // Whether the OpenGL mapper's _animationRateSubscription has been registered yet. // It registers on the first renderPieceStart call; we do one synchronous VTK render // to guarantee it exists before invokeAnimationFrameRateUpdate sets _lastScale. _isdSubscriptionReady = false; swapToLodVolume(viewport) { const actor = viewport.getActors()[0]?.actor; if (!actor) return; const imageQuality = this.renderSettingsStore.volumeSettings.imageQuality(); const factor = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.computeImageSampleDistance)(imageQuality); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.applyImageSampleDistance)(actor, factor); } restoreFullResVolume(viewport) { const actor = viewport.getActors()[0]?.actor; if (!actor) return; (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.applyImageSampleDistance)(actor, 1); // eslint-disable-next-line @typescript-eslint/no-explicit-any (0,_kitware_vtk_js_Rendering_OpenGL_VolumeMapper__WEBPACK_IMPORTED_MODULE_8__.setForceFBOQuality)(actor.getMapper(), false); this._isdSubscriptionReady = false; } // Schedules a render via requestAnimationFrame so that rapid signal changes (e.g. slider // dragging) coalesce into a single GPU draw per vsync instead of one per signal tick. scheduleQualityRender(viewport, degrade) { if (this._qualityRenderScheduled) return; this._qualityRenderScheduled = true; requestAnimationFrame(() => { this._qualityRenderScheduled = false; if (degrade) { this.renderWithForcedAnimation(viewport); } else { viewport.render(); } }); } renderWithForcedAnimation(viewport) { const actor = viewport.getActors()[0]?.actor; // eslint-disable-next-line @typescript-eslint/no-explicit-any const mapper = actor?.getMapper?.(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const renderer = viewport.getRenderer(); const vtkWindow = renderer?.getVTKWindow?.(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const rwi = vtkWindow?.getInteractor?.(); if (!rwi || !mapper) { viewport.render(); return; } // For the first degraded render the OpenGL mapper's _animationRateSubscription hasn't been // registered yet (it registers inside renderPieceStart on first call). Drive one synchronous // VTK render here — bypassing Cornerstone's async pipeline — solely to register it. // NOTE: we intentionally do NOT call requestAnimation before this. requestAnimation sets // isAnimating=true which causes publicAPI.render() to skip forceRender() entirely, blocking // all Cornerstone-triggered renders. Keep isAnimating=false throughout. if (!this._isdSubscriptionReady) { renderer.setDraw(true); vtkWindow.render(); renderer.setDraw(false); this._isdSubscriptionReady = true; } // Set _lastScale = ISD² on the OpenGL mapper so the next renderPieceStart sees // _lastScale > 1.5 and activates _useSmallViewport → FBO downscaling. rwi.invokeAnimationFrameRateUpdate({}); // Signal renderPieceStart to activate FBO for ALL renders until restoreFullResVolume clears it. // We can't set properties on the logic mapper directly — VTK freezes publicAPI objects. // The flag stays set so every Cornerstone render fired during a drag also uses FBO. (0,_kitware_vtk_js_Rendering_OpenGL_VolumeMapper__WEBPACK_IMPORTED_MODULE_8__.setForceFBOQuality)(mapper, true); // Schedule through Cornerstone's normal pipeline so the blit to the visible canvas happens. viewport.render(); } /** * Animate the camera to an annotation. */ goToAnnotation(id) { const annotation = this.annotationFacade.getAnnotationById(id); if (!annotation || !(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.isRenderable)(annotation)) return; const normal = (0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.getNormal)(annotation); this.cameraAnimation.animateToPosition((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.getCentroid)(annotation), normal, { onSettle: () => this.increase3dViewportImageQuality(), onStart: () => this.decrease3dViewportImageQuality() }); } moveCrosshairToAnnotation(id) { const annotation = this.annotationFacade.getAnnotationById(id); if (!annotation || !(0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.isRenderable)(annotation)) return; this.viewportStore.updateIntersection((0,_tomoverse_selectors__WEBPACK_IMPORTED_MODULE_13__.getCentroid)(annotation)); } seriesWindowState(seriesUid) { return this.state.seriesWindowState(seriesUid); } streamSeriesCacheProgress(seriesUid, storeUid) { return this.volumeLoaderService.streamSeriesCacheProgress(seriesUid, storeUid); } viewportsToEnable = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.state.viewportStates().filter(viewport => !!viewport.element && !viewport.isInitialized), { ...(ngDevMode ? { debugName: "viewportsToEnable" } : {}), equal: rxdb__WEBPACK_IMPORTED_MODULE_10__.deepEqual }); enableViewports(viewportConfig, volumeIds) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const promises = viewportConfig.map(/*#__PURE__*/function () { var _ref2 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* ({ element, id, type }) { if (!element) throw new Error(`No element for viewport ${id}`); const volumeId = type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.ViewportType.VOLUME_3D ? volumeIds.volume3dId : volumeIds.mprVolumeId; yield _this6.engine.enable(element, { id, type, volumeId }); return id; }); return function (_x) { return _ref2.apply(this, arguments); }; }()); return Promise.all(promises); })(); } completeViewports(enabledIds) { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this7.state.markViewportsInitialized(enabledIds); _this7.state.setStatus('ready'); _this7.engine.setViewportsReady(); if (enabledIds.includes(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT)) { _this7.reattachVascularMaskAfterViewportRebuild(); } })(); } // Re-enabling a viewport rebuilds its actor, dropping any attached GPU mask. reattachVascularMaskAfterViewportRebuild() { const segState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.vascularSegmentationState()); if (segState === 'none') return; const settings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.renderSettingsStore.volumeSettings()); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.isVascularGpuMaskAttached)(viewport)) return; this.runMaskUnlessCached(viewport, segState === 'previewing' ? 'preview' : 'apply'); } showVolumeRenderPanel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "showVolumeRenderPanel" }] : [])); toggleVolumeRenderPanel() { this.showVolumeRenderPanel.update(v => !v); } closeVolumeRenderPanel() { this.showVolumeRenderPanel.set(false); } showCtSettings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "showCtSettings" }] : [])); setCtSettingsVisible(open) { this.showCtSettings.set(open); } idleImageQuality = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(90, ...(ngDevMode ? [{ debugName: "idleImageQuality" }] : [])); reformatMaximized = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "reformatMaximized" }] : [])); setReformatMaximized(maximized) { this.reformatMaximized.set(maximized); } getVolumeScalarRangeForViewport(viewport) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.getVolumeScalarRange)(viewport); } volumeMaxPixelValue = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this._volumeRangeRevision(); const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return 3071; const [, max] = this.getVolumeScalarRangeForViewport(viewport); return max; }, ...(ngDevMode ? [{ debugName: "volumeMaxPixelValue" }] : [])); volumeMinPixelValue = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => { this._volumeRangeRevision(); const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return -1024; const [min] = this.getVolumeScalarRangeForViewport(viewport); return min; }, ...(ngDevMode ? [{ debugName: "volumeMinPixelValue" }] : [])); showRenderQualityDevPanel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "showRenderQualityDevPanel" }] : [])); toggleRenderQualityDevPanel() { this.showRenderQualityDevPanel.update(v => !v); } closeRenderQualityDevPanel() { this.showRenderQualityDevPanel.set(false); } showEndoDevPanel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "showEndoDevPanel" }] : [])); toggleEndoDevPanel() { const opening = !this.showEndoDevPanel(); this.showEndoDevPanel.set(opening); if (opening) { this.renderSettingsStore.selectVolumePreset(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.ENDO); } } closeEndoDevPanel() { this.showEndoDevPanel.set(false); } editOrientationTargetId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "editOrientationTargetId" }] : [])); isEditingOrientation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.editOrientationTargetId() !== undefined, ...(ngDevMode ? [{ debugName: "isEditingOrientation" }] : [])); openEditOrientation(annotationId) { this.editOrientationTargetId.set(annotationId); } closeEditOrientation() { this.editOrientationTargetId.set(undefined); } isSettingsPanelOpen = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.isEditingOrientation() || this.showVolumeRenderPanel() || this.showCtSettings(), ...(ngDevMode ? [{ debugName: "isSettingsPanelOpen" }] : [])); vascularMaskComputing = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "vascularMaskComputing" }] : [])); vascularSegmentationState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE, ...(ngDevMode ? [{ debugName: "vascularSegmentationState" }] : [])); vascularSegmentationApplied = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.computed)(() => this.vascularSegmentationState() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE, ...(ngDevMode ? [{ debugName: "vascularSegmentationApplied" }] : [])); _maskRunning = false; _pendingMaskMode; _lastPreset; showVascularDevPanel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "showVascularDevPanel" }] : [])); toggleVascularDevPanel() { const opening = !this.showVascularDevPanel(); this.showVascularDevPanel.set(opening); if (opening) { this.renderSettingsStore.selectVolumePreset(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR); } } closeVascularDevPanel() { this.showVascularDevPanel.set(false); } handleVascularPresetSwitch(viewport, presetName) { const segState = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.vascularSegmentationState()); const settings = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.renderSettingsStore.volumeSettings()); const switchingAway = presetName !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR && this._lastPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR; const switchingTo = presetName === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR && this._lastPreset !== undefined && this._lastPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR; if (switchingAway) { this._vascularRunGeneration++; if (segState !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.restoreVascularForPresetSwitch)(viewport); } if (!switchingTo) return; if (segState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING) { this.runMaskUnlessCached(viewport, 'preview'); return; } if (this.shouldReapplyVascularMask(segState, settings)) { this.runMaskUnlessCached(viewport, 'apply'); } } runMaskUnlessCached(viewport, mode) { const reapplied = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.instantlyReapplyVascularMask)(viewport, mode === 'preview' ? 'preview' : 'applied'); // A cached low-res live-preview result may reapply instantly (no flash), // but it must still be refreshed by an exact run. if (!reapplied || !(0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.isVascularGpuMaskExact)(viewport)) { this.runVascularMask(mode).catch(error => this.log.error(VASCULAR_REAPPLY_ERROR, error)); } } shouldReapplyVascularMask(segState, settings) { return segState === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.APPLIED || 'hasAcceptedSegmentation' in settings && settings.hasAcceptedSegmentation; } /** Bumped on refuse, revert, preset switch away, and series reset; a worker * result whose captured generation no longer matches must not re-attach. */ _vascularRunGeneration = 0; /** The mask function already attached the stale result — detach it, dropping * the label cache when the segmentation was explicitly discarded. */ discardStaleVascularResult(viewport) { if ((0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.vascularSegmentationState()) === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE) { this.restoreVascularMask(viewport); } else { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.restoreVascularForPresetSwitch)(viewport); } } /** Re-applies the vascular window settings and advances the segmentation * state — unless the run went stale, in which case the attach is undone. */ finishVascularRun(viewport, mode, generation) { if (generation !== this._vascularRunGeneration) { this.discardStaleVascularResult(viewport); return; } const currentSettings = this.renderSettingsStore.volumeSettings(); const { brightness, presetSpecificSettings, threshold } = this.resolvePresetRenderParams(currentSettings); this.engine.updateVolume3dViewportWindow({ brightness, lighting: presetSpecificSettings, presetName: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR, render: true, threshold, thresholds: presetSpecificSettings, volume3dViewport: viewport, widths: presetSpecificSettings }); this.vascularSegmentationState.set(mode === 'preview' ? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING : _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.APPLIED); } /** Entering preview fresh: snapshot the current color-ramp thresholds so revert can * restore this exact "initial" state later (accept overwrites the live ramp). * minHU/maxHU are seeded from the ramp the first time ever, and again any time the * ramp has moved since the last preview entry (e.g. the user reset/adjusted * tissueBloodThreshold/bloodCalciumThreshold in general mode) - detected by comparing * against that last-entry snapshot. Otherwise the popover's mode-aware sliders own * minHU/maxHU directly, so re-previewing after a revert/refuse with an untouched ramp * resumes from whatever was last tuned while previewing instead of reseeding over it. */ seedVascularPreviewEntry(mode, settings) { if (mode !== 'preview') return settings; if (!('minHU' in settings)) return settings; if (this.vascularSegmentationState() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE) return settings; const rampChangedSinceLastEntry = settings.tissueBloodThreshold !== settings.vascularPreviewEntryTissueBloodThreshold || settings.bloodCalciumThreshold !== settings.vascularPreviewEntryBloodCalciumThreshold; const patch = { vascularPreviewEntryBloodCalciumThreshold: settings.bloodCalciumThreshold, vascularPreviewEntryTissueBloodThreshold: settings.tissueBloodThreshold }; if (!settings.vascularPreviewBoundsSeeded || rampChangedSinceLastEntry) { patch.maxHU = settings.bloodCalciumThreshold + VASCULAR_MAX_HU_MARGIN; patch.minHU = settings.tissueBloodThreshold - VASCULAR_MIN_HU_MARGIN; patch.vascularPreviewBoundsSeeded = true; } this.renderSettingsStore.updateVolumeSettings(patch); return this.renderSettingsStore.volumeSettings(); } /** Every runVascularMask/drainLivePreview call currently in flight - see * reapplyVascularStateForPhaseSwitch, which must wait for ALL of them (not just * whichever call happened to run most recently - see trackVascularOperation) to fully * settle, including each one's own now-stale cleanup, before touching the mask itself. */ _activeVascularOperations = new Set(); /** Registers `run` in _activeVascularOperations for its lifetime. A single shared "latest * call" field would get overwritten by a second call that starts (and, via the * `_maskRunning` guard, often finishes near-instantly by just queuing a pending mode) * while an earlier, genuinely long-running call is still in flight - losing track of the * one that actually matters. Tracking every active call in a set instead means none of * them can be dropped just because another one started later. Entries never reject: a * waiter only needs to know each one is *done*, not how it ended. */ trackVascularOperation(run) { const settled = run.catch(() => { // Swallowed on purpose - see this method's doc comment above. }); this._activeVascularOperations.add(settled); settled.then(() => this._activeVascularOperations.delete(settled)); return run; } runVascularMask(mode) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this8.trackVascularOperation(_this8.runVascularMaskWork(mode)); })(); } runVascularMaskWork(mode) { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this9._maskRunning) { _this9._pendingMaskMode = mode; return; } let settings = _this9.renderSettingsStore.volumeSettings(); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; if (!('minHU' in settings)) return; const viewport = _this9.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; settings = _this9.seedVascularPreviewEntry(mode, settings); if (!('minHU' in settings)) return; _this9._maskRunning = true; _this9.vascularMaskComputing.set(true); // Drop any queued live tick and the trailing re-run so they don't // overwrite the exact result with a low-res one. _this9._livePreviewPending = undefined; _this9.cancelTrailingExactRePreview(); const generation = _this9._vascularRunGeneration; try { if (mode === 'preview') { yield _this9.paintApproximateFirstPreview(viewport, { clusterSize: settings.clusterSize, erosionRadius: settings.erosionRadius, gridStep: settings.gridStep, maxHU: settings.maxHU, minHU: settings.minHU }); } const maskFunction = mode === 'preview' ? _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.previewVascularRegionMask : _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.applyVascularRegionMask; const success = yield maskFunction(viewport, settings.minHU, settings.maxHU, undefined, settings.gridStep, settings.clusterSize, settings.erosionRadius); if (success) { _this9.finishVascularRun(viewport, mode, generation); } } finally { _this9._maskRunning = false; const pending = _this9._pendingMaskMode; _this9._pendingMaskMode = undefined; if (pending) { _this9.runVascularMask(pending).catch(error => _this9.log.error(VASCULAR_REAPPLY_ERROR, error)); } else { _this9.vascularMaskComputing.set(false); } } })(); } previewVascularMask() { return this.runVascularMask('preview'); } /** Paints the approximate low-res result before the exact run, so the first * preview isn't seconds of unchanged render. Awaited: 'previewing' must be * entered before the exact run starts so drags go live while it computes. */ paintApproximateFirstPreview(viewport, parameters) { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.isVascularGpuMaskAttached)(viewport)) return; const livePainted = yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.previewVascularRegionMaskLive)(viewport, parameters).catch(() => false); if (livePainted) _this0.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING); })(); } _livePreviewPending; _livePreviewRunning = false; _trailingExactRePreview; /** Live re-segmentation while a slider drags. Ticks coalesce — at most one * preview request in flight, on a worker isolated from exact runs. */ previewVascularMaskLive(parameters) { if (this.vascularSegmentationState() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING) return; const settings = this.renderSettingsStore.volumeSettings(); if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; // Dragging supersedes an in-flight exact run — cancel it (the rejected // promise clears the spinner); slide-end or the trailing re-run computes exact. if (this._maskRunning) (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.cancelVascularFullRun)(); this._livePreviewPending = parameters; this.drainLivePreview().catch(error => this.log.error(VASCULAR_REAPPLY_ERROR, error)); } drainLivePreview() { var _this1 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { return _this1.trackVascularOperation(_this1.drainLivePreviewWork()); })(); } drainLivePreviewWork() { var _this10 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this10._livePreviewRunning) return; _this10._livePreviewRunning = true; try { while (_this10._livePreviewPending) { const parameters = _this10._livePreviewPending; _this10._livePreviewPending = undefined; const viewport = _this10.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) break; const generation = _this10._vascularRunGeneration; yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.previewVascularRegionMaskLive)(viewport, parameters).catch(() => false); // Refused/reverted/preset-switched while this tick computed — undo the attach. if (generation !== _this10._vascularRunGeneration) { _this10.discardStaleVascularResult(viewport); return; } } } finally { _this10._livePreviewRunning = false; } _this10.scheduleTrailingExactRePreview(); })(); } /** Keyboard slider input never fires onSlideEnd, so every drained tick arms * a trailing exact re-run; a slide-end or newer tick supersedes it. */ scheduleTrailingExactRePreview() { this.cancelTrailingExactRePreview(); this._trailingExactRePreview = setTimeout(() => { this._trailingExactRePreview = undefined; if (this._maskRunning || this._livePreviewRunning || this._livePreviewPending) return; if (this.vascularSegmentationState() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.PREVIEWING) return; this.previewVascularMask().catch(error => this.log.error(VASCULAR_REAPPLY_ERROR, error)); }, 700); } cancelTrailingExactRePreview() { if (this._trailingExactRePreview === undefined) return; clearTimeout(this._trailingExactRePreview); this._trailingExactRePreview = undefined; } /** Resolves after the browser's paint for the next two frames, so a signal * flip made just before this actually reaches the screen before further * (blocking) work runs. */ waitForNextFrame() { const nextFrame = () => new Promise(resolve => requestAnimationFrame(() => resolve())); return nextFrame().then(nextFrame); } acceptVascularMask() { var _this11 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const viewport = _this11.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; if (!_this11.commitVascularPreview(viewport)) return; // Refining thresholds walks every voxel on the main thread — reuse the // same spinner the preview computation shows, and wait for it to // actually paint before that blocking work starts. _this11.vascularMaskComputing.set(true); yield _this11.waitForNextFrame(); try { _this11.refineVascularThresholdsIfPossible(viewport); const settings = _this11.renderSettingsStore.volumeSettings(); const { brightness, presetSpecificSettings, threshold } = _this11.resolvePresetRenderParams(settings); _this11.engine.updateVolume3dViewportWindow({ brightness, lighting: presetSpecificSettings, presetName: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR, render: true, threshold, thresholds: presetSpecificSettings, volume3dViewport: viewport, widths: presetSpecificSettings }); _this11.renderSettingsStore.updateVolumeSettings({ hasAcceptedSegmentation: true }); _this11.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.APPLIED); } catch (error) { _this11.log.error(VASCULAR_REAPPLY_ERROR, error); } finally { _this11.vascularMaskComputing.set(false); } })(); } refuseVascularMask() { const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; this._vascularRunGeneration++; this.restoreVascularMask(viewport); viewport.render(); this.renderSettingsStore.updateVolumeSettings({ hasAcceptedSegmentation: false }); this.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE); } revertVascularMask() { const viewport = this.engine.getViewport(_viewport_ids__WEBPACK_IMPORTED_MODULE_21__.VIEWPORT_IDS.REFORMAT); if (!(viewport instanceof _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_6__["default"])) return; this._vascularRunGeneration++; this.restoreVascularMask(viewport); const settings = this.renderSettingsStore.volumeSettings(); if (settings.selectedPreset === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) { const defaults = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.VOLUME_RENDERING_PRESETS[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR]; this.renderSettingsStore.updateVolumeSettings({ // Restore the exact ramp from right before preview last started; fall back to // this session's histogram-computed default, then the static preset, for the // (unexpected) case preview was never actually entered. bloodCalciumThreshold: settings.vascularPreviewEntryBloodCalciumThreshold ?? settings.vascularSessionDefaultBloodCalciumThreshold ?? defaults.bloodCalciumThreshold, hasAcceptedSegmentation: false, tissueBloodThreshold: settings.vascularPreviewEntryTissueBloodThreshold ?? settings.vascularSessionDefaultTissueBloodThreshold ?? defaults.tissueBloodThreshold, // A deliberate reset — must not look "untouched" and re-trigger the auto-tune. vascularThresholdsAutoTuned: true }); } else { viewport.render(); } this.vascularSegmentationState.set(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VascularSegmentationState.NONE); } // Seams over the @tomoverse/utils helpers so tests can spy on them; Vitest's barrel mock doesn't reliably intercept the bare imports on CI. commitVascularPreview(viewport) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.acceptVascularPreview)(viewport); } restoreVascularMask(viewport) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.restoreVascularRegionMask)(viewport); } computeAutoVascularThresholds(volume) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.computeAutoVascularThresholdsForVolume)(volume); } refineVascularThresholdsFromMask(volume) { return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.computeVascularThresholdsFromMask)(volume); } /** Seeds a per-scan starting ramp from the volume's own HU histogram the first * time Vascular mode is selected — gated on `vascularThresholdsAutoTuned` rather * than comparing against the static default, so a deliberate reset-to-default * (which also lands on those exact numbers) is never mistaken for "untouched" * and re-triggers the heuristic. */ maybeAutoTuneVascularThresholds(viewport, settings) { if (settings.selectedPreset !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_12__.VolumeRenderingOption.VASCULAR) return; if (settings.vascularThresholdsAutoTuned) return; const volume = _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_7__["default"].getVolume(viewport.getVolumeId()); if (!volume) return; const computed = this.computeAutoVascularThresholds(volume); if (!computed) { this.renderSettingsStore.updateVolumeSettings({ vascularThresholdsAutoTuned: true }); return; } this.renderSettingsStore.updateVolumeSettings({ ...computed, // Becomes this session's reset target, so "reset" restores the scan-specific // starting point instead of the generic static preset from then on. vascularSessionDefaultBloodCalciumThreshold: computed.bloodCalciumThreshold, vascularSessionDefaultTissueBloodThreshold: computed.tissueBloodThreshold, vascularThresholdsAutoTuned: true }); } /** Tightens the ramp to the accepted mask's own vessel-voxel HU range — * the authoritative signal at accept time, so it always overrides whatever * was there before (default, auto-tuned, or user-adjusted). */ refineVascularThresholdsIfPossible(viewport) { const volume = _cornerstonejs_core__WEBPACK_IMPORTED_MODULE_7__["default"].getVolume(viewport.getVolumeId()); if (!volume) return; const refined = this.refineVascularThresholdsFromMask(volume); if (!refined) return; this.renderSettingsStore.updateVolumeSettings({ ...refined, vascularThresholdsAutoTuned: true }); } isPosterior = this.viewportStore.isPosterior; updateIsPosterior(isPosterior) { this.viewportStore.updatePosterior(isPosterior); } ccAngle = this.viewportStore.primaryViewportAngulations.cc; rlAngle = this.viewportStore.primaryViewportAngulations.rl; cameraRlChanged(newValueRL) { this.rotationQuality.start(); this.viewportStore.updateAngulations({ rl: newValueRL }); } cameraCcChanged(newValueCC) { this.rotationQuality.start(); this.viewportStore.updateAngulations({ cc: newValueCC }); } resetAngulations() { this.viewportStore.resetAngulations(); this.viewportStore.resetCrosshairPosition(); } copyAngulations(viewportAxisState) { const angulationsForViewport = this.viewportStore.viewportAngulations()[viewportAxisState]; if (!angulationsForViewport) { this.log.warn(`Viewport with id ${viewportAxisState} not found or has no angulations`); return; } const angulationsString = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_15__.formatAngulationtxt)(angulationsForViewport, this.viewportStore.isPosterior()); navigator.clipboard.writeText(angulationsString).catch(error => this.log.error(`Could not copy angulations: ${error}`)); } resolvePresetRenderParams(settings) { return { brightness: 'brightness' in settings ? settings.brightness : 0, presetSpecificSettings: 'tissueBloodThreshold' in settings ? settings : undefined, threshold: 'threshold' in settings ? settings.threshold : 0 }; } cleanup() { for (const cleanupFunction of this.cleanupFunctions) cleanupFunction(); this.cleanupFunctions.length = 0; } } /***/ }, /***/ 28828 /*!***********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/volume-viewer.component.ts ***! \***********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ VolumeViewerComponent: () => (/* binding */ VolumeViewerComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_accordion__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! primeng/accordion */ 45913); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_contextmenu__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! primeng/contextmenu */ 94635); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_menu__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! primeng/menu */ 64204); /* harmony import */ var primeng_select__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/select */ 6989); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../annotation-card/annotation-card.component */ 86628); /* harmony import */ var _annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../annotation-menu/annotation-menu-item.service */ 39860); /* harmony import */ var _annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../annotation-menu/components/annotation-menu-item.component */ 45731); /* harmony import */ var _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ../annotation-menu/components/annotation-menu.component */ 13609); /* harmony import */ var _annotation_menu_menu_tracker_service__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! ../annotation-menu/menu-tracker.service */ 61487); /* harmony import */ var _chamber_chamber_service__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! ../chamber/chamber.service */ 16592); /* harmony import */ var _interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! ../interaction-mode/interaction-mode.service */ 72754); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _protocols__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! ../protocols */ 61632); /* harmony import */ var _s_curve_graph_s_curve_graph_component__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! ../s-curve-graph/s-curve-graph.component */ 1336); /* harmony import */ var _window_window_service__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! ../window/window.service */ 26914); /* harmony import */ var _annotation_actors_annotation_actors_service__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ./annotation-actors/annotation-actors.service */ 12100); /* harmony import */ var _cpr_cpr_config__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./cpr/cpr-config */ 17924); /* harmony import */ var _cpr_cpr_workspace_component__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./cpr/cpr-workspace.component */ 11095); /* harmony import */ var _cpr_cpr_service__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./cpr/cpr.service */ 26144); /* harmony import */ var _ct_popover_service__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./ct-popover.service */ 20974); /* harmony import */ var _endo_dev_panel_endo_dev_panel_component__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! ./endo-dev-panel/endo-dev-panel.component */ 50108); /* harmony import */ var _orientation_form_config__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! ./orientation-form-config */ 1894); /* harmony import */ var _render_quality_dev_panel_render_quality_dev_panel_component__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ./render-quality-dev-panel/render-quality-dev-panel.component */ 33032); /* harmony import */ var _vascular_dev_panel_vascular_dev_panel_component__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ./vascular-dev-panel/vascular-dev-panel.component */ 74278); /* harmony import */ var _viewport_ids__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ./viewport-ids */ 85309); /* harmony import */ var _viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ./viewport-interaction/viewport-interaction.service */ 46184); /* harmony import */ var _viewport_overlay_viewport_overlay_component__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! ./viewport-overlay/viewport-overlay.component */ 71848); /* harmony import */ var _volume_rendering_popover_service__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! ./volume-rendering-popover.service */ 60538); /* harmony import */ var _volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! ./volume-viewer-orchestrator.service */ 66035); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = ["ctxMenu"]; const _c1 = ["alignMenu"]; const _c2 = () => ({ style: "display: none" }); const _c3 = a0 => ({ root: a0 }); const _c4 = a0 => ({ $implicit: a0, includeViewportSwap: true }); const _c5 = a0 => ({ $implicit: a0, includeViewportSwap: false }); const _c6 = () => ({ root: "w-xs max-w-full" }); const _c7 = () => ({ root: "py-2" }); const _c8 = () => ({ content: "py-2 border-surface-800 border-t" }); const _c9 = (a0, a1) => ({ header: a0, content: a1, wrapper: "rounded-lg border-none" }); function VolumeViewerComponent_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "pre"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "json"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtextInterpolate"](_angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 1, ctx_r0.viewerOrchestrator.imageIdsError())); } } function VolumeViewerComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 17); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtext"](1, " Error loading volume data. "); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](2, VolumeViewerComponent_Conditional_0_Conditional_2_Template, 3, 3, "pre"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.imageIdsError() ? 2 : -1); } } function VolumeViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 22)(1, "p-select", 27); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("ngModelChange", function VolumeViewerComponent_Conditional_1_Conditional_3_Template_p_select_ngModelChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r3); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onSelectVolume($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("options", ctx_r0.phaseSelectOptions())("ngModel", ctx_r0.selectedPhaseId())("disabled", ctx_r0.isVolumeSwitching())("ariaLabel", ctx_r0.volumeWord()); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_1_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementContainer"](0); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](0, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_1_ng_container_0_Template, 1, 0, "ng-container", 29); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); const viewportBase_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](13); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("ngTemplateOutlet", viewportBase_r5)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction1"](2, _c4, ctx_r0.viewportIds.AXIAL)); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_3_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementContainer"](0); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](0, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_3_ng_container_0_Template, 1, 0, "ng-container", 29); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); const viewportBase_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](13); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("ngTemplateOutlet", viewportBase_r5)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction1"](2, _c4, ctx_r0.viewportIds.SAGITTAL)); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_5_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementContainer"](0); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](0, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_5_ng_container_0_Template, 1, 0, "ng-container", 29); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); const viewportBase_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](13); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("ngTemplateOutlet", viewportBase_r5)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction1"](2, _c5, ctx_r0.viewportIds.CORONAL)); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_7_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementContainer"](0); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](0, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_7_ng_container_0_Template, 1, 0, "ng-container", 29); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); const viewportBase_r5 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](13); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("ngTemplateOutlet", viewportBase_r5)("ngTemplateOutletContext", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction1"](2, _c5, ctx_r0.viewportIds.REFORMAT)); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_9_Template(rf, ctx) { if (rf & 1) { const _r6 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 30)(1, "div", 31)(2, "lib-viewport-button", 32); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("click", function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_9_Template_lib_viewport_button_click_2_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onToggleMaximizeViewport(ctx_r0.PanelName.S_CURVE_GRAPH)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](5, "lib-viewport-button", 33); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](6, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](7, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("click", function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_9_Template_lib_viewport_button_click_5_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r6); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.moveSCurveGraphToSidebar()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"]()()(); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](8, "div", 34)(9, "div", 35); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](10, "lib-s-curve-graph", 36); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); const maximized_r7 = ctx_r0.sCurveMaximized(); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](3, 7, maximized_r7 ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](4, 9, maximized_r7 ? "viewportButton.minimizeLabel" : "viewportButton.maximizeLabel"))("icon", maximized_r7 ? "arrow-down-left-and-arrow-up-right-to-center" : "arrow-up-right-and-arrow-down-left-from-center"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](6, 11, "viewportButton.sCurveToSidebar"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](7, 13, "viewportButton.sCurveToSidebar")); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](5); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("showDetachButton", false)("isMaximized", ctx_r0.sCurveMaximized()); } } function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_11_Template(rf, ctx) { if (rf & 1) { const _r8 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-cpr-workspace", 37); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("resizeStart", function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_11_Template_lib_cpr_workspace_resizeStart_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onResizeStart()); })("resizeEnd", function VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_11_Template_lib_cpr_workspace_resizeEnd_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r8); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](3); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onResizeEnd()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const viewportAxial_r9 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](2); const viewportSagittal_r10 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](4); const viewportCoronal_r11 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](6); const viewportReformat_r12 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](8); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("axialTemplate", viewportAxial_r9)("cameraSliderTemplate", ctx_r0.cameraSliderTemplate())("coronalTemplate", viewportCoronal_r11)("reformatTemplate", viewportReformat_r12)("sagittalTemplate", viewportSagittal_r10)("isBlur", ctx_r0.isBlur())("isInitialViewportState", ctx_r0.isInitialViewportLayout())("lastSelectedMPRViewport", ctx_r0.lastSelectedMPRViewport())("selectedMPRViewport", ctx_r0.selectedMPRViewport()); } } function VolumeViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) { const _r4 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-viewport-layout-manager", 28); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("resizeStart", function VolumeViewerComponent_Conditional_1_Conditional_4_Template_lib_viewport_layout_manager_resizeStart_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onResizeStart()); })("resizeEnd", function VolumeViewerComponent_Conditional_1_Conditional_4_Template_lib_viewport_layout_manager_resizeEnd_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onResizeEnd()); })("loaderContextMenu", function VolumeViewerComponent_Conditional_1_Conditional_4_Template_lib_viewport_layout_manager_loaderContextMenu_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r4); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.toggleViewportContextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](1, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_1_Template, 1, 4, "ng-template", null, 10, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(3, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_3_Template, 1, 4, "ng-template", null, 11, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(5, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_5_Template, 1, 4, "ng-template", null, 12, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(7, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_7_Template, 1, 4, "ng-template", null, 13, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(9, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_9_Template, 11, 15, "ng-template", null, 14, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(11, VolumeViewerComponent_Conditional_1_Conditional_4_ng_template_11_Template, 1, 9, "ng-template", null, 15, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("viewportLayout", ctx_r0.viewportLayout())("focusedMPRViewport", ctx)("selectedMPRViewport", ctx_r0.selectedMPRViewport())("isInitialViewportState", ctx_r0.isInitialViewportLayout())("lastSelectedMPRViewport", ctx_r0.lastSelectedMPRViewport())("isBlur", ctx_r0.isBlur())("loadingProgress", ctx_r0.loadingProgress())("showSCurveGraph", ctx_r0.showSCurveGraph()); } } function VolumeViewerComponent_Conditional_1_ng_template_7_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](0, "lib-annotation-menu-item", 38); } if (rf & 2) { const item_r13 = ctx.$implicit; _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("item", item_r13); } } function VolumeViewerComponent_Conditional_1_Conditional_11_Template(rf, ctx) { if (rf & 1) { const _r14 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 26)(1, "lib-settings-popover", 39); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("visibilityChange", function VolumeViewerComponent_Conditional_1_Conditional_11_Template_lib_settings_popover_visibilityChange_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r14); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.active.set($event)); })("closed", function VolumeViewerComponent_Conditional_1_Conditional_11_Template_lib_settings_popover_closed_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r14); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.closeEditOrientation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](4, "lib-settings-popover", 40); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](5, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("visibilityChange", function VolumeViewerComponent_Conditional_1_Conditional_11_Template_lib_settings_popover_visibilityChange_4_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r14); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.active.set($event)); })("closed", function VolumeViewerComponent_Conditional_1_Conditional_11_Template_lib_settings_popover_closed_4_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r14); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.closeVolumeRenderPanel()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"]()(); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("showButton", false)("draggable", true)("dragBoundary", "[data-viewer-bounds]")("externalOpen", ctx_r0.viewerOrchestrator.isEditingOrientation())("formFieldConfig", ctx_r0.orientationFormConfig())("title", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 11, "annotationMenu.editOrientation.label"))("dragHandleAriaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](3, 13, "annotationMenu.editOrientation.move")); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("showButton", false)("externalOpen", ctx_r0.viewerOrchestrator.showVolumeRenderPanel())("formFieldConfig", ctx_r0.volumeRenderFormConfig())("title", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](5, 15, "volumeRenderingSettings.title")); } } function VolumeViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "section", 20); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("mouseup", function VolumeViewerComponent_Conditional_1_Template_section_mouseup_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.handleMouseUp($event)); })("mouseup", function VolumeViewerComponent_Conditional_1_Template_section_mouseup_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.handleWindowMouseUp()); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("mousemove", function VolumeViewerComponent_Conditional_1_Template_section_mousemove_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleGlobalMouseMove($event)); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("blur", function VolumeViewerComponent_Conditional_1_Template_section_blur_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.cancelInteractions()); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"]); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](1, "div", 21, 6); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("contextmenu", function VolumeViewerComponent_Conditional_1_Template_div_contextmenu_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onContextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](3, VolumeViewerComponent_Conditional_1_Conditional_3_Template, 2, 4, "div", 22); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](4, VolumeViewerComponent_Conditional_1_Conditional_4_Template, 13, 8, "lib-viewport-layout-manager", 23); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](5, "p-contextmenu", 24, 7); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("onShow", function VolumeViewerComponent_Conditional_1_Template_p_contextmenu_onShow_5_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); ctx_r0.active.set(false); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleMouseUp()); })("onHide", function VolumeViewerComponent_Conditional_1_Template_p_contextmenu_onHide_5_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.active.set(true)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](7, VolumeViewerComponent_Conditional_1_ng_template_7_Template, 1, 1, "ng-template", null, 8, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](9, "lib-annotation-menu", 25, 9); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](11, VolumeViewerComponent_Conditional_1_Conditional_11_Template, 6, 17, "div", 26); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { let tmp_13_0; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵstyleProp"]("cursor", ctx_r0.interaction.viewportCursor()); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](3); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.hasMultiplePhases() ? 3 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"]((tmp_13_0 = ctx_r0.focusedMPRViewport()) ? 4 : -1, tmp_13_0); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("appendTo", "body")("model", ctx_r0.annotationMenuItems())("pt", ctx_r0.menuPt); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("model", ctx_r0.alignMenuItems()); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.seriesWindowState(ctx_r0.seriesUid()) ? 11 : -1); } } function VolumeViewerComponent_ng_template_2_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r15 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-viewport-button", 42); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("click", function VolumeViewerComponent_ng_template_2_Conditional_0_Template_lib_viewport_button_click_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r15); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.toggleVolumeRenderPanel()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](1, 2, "volumeRenderingSettings.buttonTooltip"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 4, "volumeRenderingSettings.buttonTooltip")); } } function VolumeViewerComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](0, VolumeViewerComponent_ng_template_2_Conditional_0_Template, 3, 6, "lib-viewport-button", 41); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.seriesWindowState(ctx_r0.seriesUid()) ? 0 : -1); } } function VolumeViewerComponent_ng_template_4_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r16 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-settings-popover", 44); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("visibilityChange", function VolumeViewerComponent_ng_template_4_Conditional_0_Template_lib_settings_popover_visibilityChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r16); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.active.set($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("formFieldConfig", ctx_r0.volumeRenderFormConfig())("buttonTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](1, 4, "volumeRenderingSettings.buttonTooltip"))("buttonAriaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 6, "volumeRenderingSettings.buttonTooltip"))("title", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](3, 8, "volumeRenderingSettings.title")); } } function VolumeViewerComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](0, VolumeViewerComponent_ng_template_4_Conditional_0_Template, 4, 10, "lib-settings-popover", 43); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.seriesWindowState(ctx_r0.seriesUid()) ? 0 : -1); } } function VolumeViewerComponent_ng_template_6_Conditional_0_Template(rf, ctx) { if (rf & 1) { const _r17 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-settings-popover", 46); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("visibilityChange", function VolumeViewerComponent_ng_template_6_Conditional_0_Template_lib_settings_popover_visibilityChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r17); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); ctx_r0.active.set($event); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.setCtSettingsVisible(!$event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("formFieldConfig", ctx_r0.ctFormConfig())("draggable", true)("dragBoundary", "[data-viewer-bounds]")("buttonTooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](1, 7, "ctImageSettings.buttonTooltip"))("buttonAriaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 9, "ctImageSettings.label"))("title", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](3, 11, "ctImageSettings.title"))("dragHandleAriaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](4, 13, "ctImageSettings.move")); } } function VolumeViewerComponent_ng_template_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](0, VolumeViewerComponent_ng_template_6_Conditional_0_Template, 5, 15, "lib-settings-popover", 45); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.seriesWindowState(ctx_r0.seriesUid()) ? 0 : -1); } } function VolumeViewerComponent_ng_template_8_Template(rf, ctx) { if (rf & 1) { const _r18 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-viewport-button", 47); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("click", function VolumeViewerComponent_ng_template_8_Template_lib_viewport_button_click_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r18); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.toggleViewportContextMenu($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("tooltip", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](1, 2, "viewportButton.settingsLabel"))("ariaLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 4, "viewportButton.settingsLabel")); } } function VolumeViewerComponent_ng_template_10_Conditional_3_Template(rf, ctx) { if (rf & 1) { const _r19 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "p-accordion", 49); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("valueChange", function VolumeViewerComponent_ng_template_10_Conditional_3_Template_p_accordion_valueChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r19); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onFloatingCardValueChange($event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](1, "lib-annotation-card", 50); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("show", function VolumeViewerComponent_ng_template_10_Conditional_3_Template_lib_annotation_card_show_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r19); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const annotation_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreadContextLet"](2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onShowAnnotation(annotation_r20.id)); })("hide", function VolumeViewerComponent_ng_template_10_Conditional_3_Template_lib_annotation_card_hide_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r19); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const annotation_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreadContextLet"](2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onHideAnnotation(annotation_r20.id)); })("goTo", function VolumeViewerComponent_ng_template_10_Conditional_3_Template_lib_annotation_card_goTo_1_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r19); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const annotation_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreadContextLet"](2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onGoToAnnotation(annotation_r20.id)); })("updateName", function VolumeViewerComponent_ng_template_10_Conditional_3_Template_lib_annotation_card_updateName_1_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r19); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const annotation_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreadContextLet"](2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onUpdateAnnotationName($event, annotation_r20.id)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const moreActionsMenu_r21 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](1); const annotation_r20 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreadContextLet"](2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction0"](7, _c6))("multiple", true)("value", ctx_r0.floatingCardValue()); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("annotation", annotation_r20)("actions", annotation_r20.moreActions)("menuTrigger", moreActionsMenu_r21)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction2"](10, _c9, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction0"](8, _c7), _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction0"](9, _c8))); } } function VolumeViewerComponent_ng_template_10_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](0, "lib-annotation-menu", null, 16); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵdeclareLet"](2); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](3, VolumeViewerComponent_ng_template_10_Conditional_3_Template, 2, 13, "p-accordion", 48); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](2); const annotation_r22 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵstoreLet"](ctx_r0.cardAnnotation()); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](annotation_r22 && !ctx_r0.viewerOrchestrator.isSettingsPanelOpen() ? 3 : -1); } } function VolumeViewerComponent_ng_template_12_Conditional_5_Template(rf, ctx) { if (rf & 1) { const _r25 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 55); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("mousedown", function VolumeViewerComponent_ng_template_12_Conditional_5_Template_div_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r25); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("wheel", function VolumeViewerComponent_ng_template_12_Conditional_5_Template_div_wheel_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r25); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](1, "lib-endo-dev-panel"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } } function VolumeViewerComponent_ng_template_12_Conditional_6_Template(rf, ctx) { if (rf & 1) { const _r26 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 55); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("mousedown", function VolumeViewerComponent_ng_template_12_Conditional_6_Template_div_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r26); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("wheel", function VolumeViewerComponent_ng_template_12_Conditional_6_Template_div_wheel_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r26); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](1, "lib-vascular-dev-panel"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } } function VolumeViewerComponent_ng_template_12_Conditional_7_Template(rf, ctx) { if (rf & 1) { const _r27 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 55); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("mousedown", function VolumeViewerComponent_ng_template_12_Conditional_7_Template_div_mousedown_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r27); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); })("wheel", function VolumeViewerComponent_ng_template_12_Conditional_7_Template_div_wheel_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r27); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"]($event.stopPropagation()); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](1, "lib-render-quality-dev-panel"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } } function VolumeViewerComponent_ng_template_12_Conditional_8_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "div", 54); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](1, "div", 56); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } } function VolumeViewerComponent_ng_template_12_Template(rf, ctx) { if (rf & 1) { const _r23 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementStart"](0, "lib-volume-viewport", 51); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](1, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](2, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipe"](3, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("viewportReady", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_viewportReady_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onViewportReady($event)); })("viewportDestroyed", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_viewportDestroyed_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.deregisterViewport($event)); })("perspectiveChange", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_perspectiveChange_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.viewerOrchestrator.updateIsPosterior($event)); })("mouseDown", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_mouseDown_0_listener($event) { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.handleViewportClick($event, id_r24)); })("mouseMove", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_mouseMove_0_listener($event) { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.handleViewportMouseMove($event, id_r24)); })("wheelScrolled", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_wheelScrolled_0_listener($event) { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleWheel($event, id_r24)); })("gestureStarted", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_gestureStarted_0_listener($event) { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleGestureStart($event)); })("gestureChanged", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_gestureChanged_0_listener($event) { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleGestureChange($event, id_r24)); })("gestureEnded", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_gestureEnded_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleGestureEnd()); })("contextMenu", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_contextMenu_0_listener($event) { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.interaction.handleContextMenu($event, id_r24)); })("toggleMaximizeViewport", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_toggleMaximizeViewport_0_listener() { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onToggleMaximizeViewport(id_r24)); })("focusedMPRViewportChange", function VolumeViewerComponent_ng_template_12_Template_lib_volume_viewport_focusedMPRViewportChange_0_listener() { const id_r24 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r23).$implicit; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r0.onFocusedMPRViewportSelect(id_r24)); }); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](4, "lib-viewport-overlay", 52); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](5, VolumeViewerComponent_ng_template_12_Conditional_5_Template, 2, 0, "div", 53); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](6, VolumeViewerComponent_ng_template_12_Conditional_6_Template, 2, 0, "div", 53); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](7, VolumeViewerComponent_ng_template_12_Conditional_7_Template, 2, 0, "div", 53); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](8, VolumeViewerComponent_ng_template_12_Conditional_8_Template, 2, 0, "div", 54); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelementEnd"](); } if (rf & 2) { const id_r24 = ctx.$implicit; const includeViewportSwap_r28 = ctx.includeViewportSwap; const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵnextContext"](); const volumeRenderTrigger_r29 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](3); const volumeRenderMaximized_r30 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](5); const ctPopoverSettings_r31 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](7); const viewportPopoverSettings_r32 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](9); const annotationCards_r33 = _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵreference"](11); const isMainMprViewport_r34 = ctx_r0.maximizedPanelId === id_r24 || ctx_r0.viewportIds.CORONAL === id_r24; _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("state", ctx_r0.getViewportStateById(id_r24))("darkMode", id_r24 !== ctx_r0.viewportIds.REFORMAT || ctx_r0.volumeIsDarkMode())("annotationCardsTemplate", isMainMprViewport_r34 && annotationCards_r33 || undefined)("settingsPopoverTemplate", isMainMprViewport_r34 && ctx_r0.viewportIds.REFORMAT !== id_r24 && ctPopoverSettings_r31 || ctx_r0.viewportIds.REFORMAT === id_r24 && ctx_r0.maximizedPanelId === id_r24 && volumeRenderMaximized_r30 || ctx_r0.viewportIds.REFORMAT === id_r24 && ctx_r0.maximizedPanelId !== id_r24 && volumeRenderTrigger_r29 || undefined)("viewportSettingsPopoverTemplate", viewportPopoverSettings_r32)("includeViewportSwap", includeViewportSwap_r28 && !ctx_r0.cprActive())("maximized", ctx_r0.isViewportMaximized(id_r24))("includeViewportMenu", id_r24 === ctx_r0.viewportIds.REFORMAT || ctx_r0.maximizedPanelId === id_r24)("angulation", ctx_r0.viewportAngulation(id_r24)())("createMode", ctx_r0.createMode())("cursor", ctx_r0.interaction.viewportCursor())("isPosterior", ctx_r0.isPosterior())("swapLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](1, 25, "viewportButton.swapLabel"))("minimizeLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](2, 27, "viewportButton.minimizeLabel"))("maximizeLabel", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpipeBind1"](3, 29, "viewportButton.maximizeLabel")); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("viewportId", id_r24)("viewportAxis", ctx_r0.viewportAxis(id_r24)())("cameraDetails", ctx_r0.viewportCameraState(id_r24)())("crosshairColors", ctx_r0.viewportAxisColors(id_r24))("crosshairRotation", ctx_r0.compactCrosshair(id_r24) ? 0 : ctx_r0.viewportCrosshairRotation(id_r24)())("compact", ctx_r0.compactCrosshair(id_r24)); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.showEndoDevPanel() && (id_r24 === ctx_r0.viewportIds.CORONAL && !ctx_r0.maximizedPanelId || ctx_r0.maximizedPanelId && id_r24 === ctx_r0.maximizedPanelId) ? 5 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.showVascularDevPanel() && (id_r24 === ctx_r0.viewportIds.CORONAL && !ctx_r0.maximizedPanelId || ctx_r0.maximizedPanelId && id_r24 === ctx_r0.maximizedPanelId) ? 6 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.showRenderQualityDevPanel() && (id_r24 === ctx_r0.viewportIds.CORONAL && !ctx_r0.maximizedPanelId || ctx_r0.maximizedPanelId && id_r24 === ctx_r0.maximizedPanelId) ? 7 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx_r0.viewerOrchestrator.vascularMaskComputing() && id_r24 === ctx_r0.viewportIds.REFORMAT ? 8 : -1); } } const REVALIDATE_MAX_ATTEMPTS = 3; const REVALIDATE_RETRY_DELAY_MS = 100; const POINTER_HEAL_SUPPRESS_MS = 1000; const MAXIMIZED_CROSSHAIR_COLOR = 'var(--p-app-viewport-maximized-crosshair)'; class VolumeViewerComponent { viewportIds = _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS; viewportIdsList = [_viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.AXIAL.valueOf(), _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.SAGITTAL.valueOf(), _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.REFORMAT.valueOf(), _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.CORONAL.valueOf()]; get ctSettingsButtonEl() { return document.querySelector(`#${_viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.CORONAL} lib-settings-popover lib-viewport-button`) ?? undefined; } ViewportAxis = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxis; PanelName = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.PanelName; log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_30__.getLogger)(_tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.VolumeViewportComponent.name); injector = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.EnvironmentInjector); windowService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_window_window_service__WEBPACK_IMPORTED_MODULE_33__.WindowService); dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_14__.DialogService); viewerOrchestrator = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_volume_viewer_orchestrator_service__WEBPACK_IMPORTED_MODULE_47__.VolumeViewerOrchestrator); interaction = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_44__.ViewportInteractionService); renderingEngineService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_17__.RenderingEngineService); dicomDatabase = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_17__.DicomDatabaseService); annotationActors = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_annotation_actors_annotation_actors_service__WEBPACK_IMPORTED_MODULE_34__.AnnotationActorsService); annotationFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.AnnotationFacade); chamberFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.ChamberFacade); chamberService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_chamber_chamber_service__WEBPACK_IMPORTED_MODULE_28__.ChamberService); protocolCreation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_protocols__WEBPACK_IMPORTED_MODULE_31__.ProtocolCreationService); renderSettingsStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.renderSettingsStore); viewportStore = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.viewportStore); measurementService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.MeasurementService); menuTracker = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_annotation_menu_menu_tracker_service__WEBPACK_IMPORTED_MODULE_27__.MenuTrackerService); ctPopoverService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_ct_popover_service__WEBPACK_IMPORTED_MODULE_38__.CtPopoverService); volumeRenderingPopoverService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_volume_rendering_popover_service__WEBPACK_IMPORTED_MODULE_46__.VolumeRenderingPopoverService); cprService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_cpr_cpr_service__WEBPACK_IMPORTED_MODULE_37__.CprService); cprSession = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.cprSessionStore); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_12__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__.TranslateService); orientationFormRefresh = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(0, ...(ngDevMode ? [{ debugName: "orientationFormRefresh" }] : [])); uiFacade = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_20__.UiFacade); volumeRenderFormConfig = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "volumeRenderFormConfig" }] : [])); orientationFormConfig = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "orientationFormConfig" }] : [])); ctFormConfig = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "ctFormConfig" }] : [])); resizeIntervalId = undefined; resizeTimeoutId = undefined; revalidateTimeoutId = undefined; debouncedPointerHeal = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.debounce)(() => this.revalidateCanvasResolution(), POINTER_HEAL_SUPPRESS_MS, true); isWindowResizing = false; isSeriesResetting = false; destroyed = false; // Per-phase volume cache: each phase's volume is built lazily on first view and kept cached // for the rest of the session (all released together on series change/destroy) - switching // back and forth between phases is a common gated/multi-phase workflow, and evicting a // phase's volume the moment it's no longer active would force a full re-decode/re-upload on // every switch back to it. phaseVolumeIds = new Map(); // Volumes discardStaleVolume couldn't safely decache immediately because a series reset was // already in progress - drained once that reset's own resetForSeriesChange call has disabled // every viewport (see loadEffect).\ inFlightPhaseLoads = new Map(); pendingStaleVolumeDiscards = []; volumeIsDarkMode = this.renderSettingsStore.volumeIsDarkMode; seriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)('', ...(ngDevMode ? [{ debugName: "seriesUid" }] : [])); studyUid = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "studyUid" }] : [])); storeUid = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "storeUid" }] : [])); otSeriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(undefined, ...(ngDevMode ? [{ debugName: "otSeriesUid" }] : [])); workSessionUid = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "workSessionUid" }] : [])); // When set, only these phases are offered and loaded. selectedPhaseIds = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(undefined, ...(ngDevMode ? [{ debugName: "selectedPhaseIds" }] : [])); layoutConfig = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "layoutConfig" }] : [])); viewportLayout = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "viewportLayout" }] : [])); focusedMPRViewport = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "focusedMPRViewport" }] : [])); selectedMPRViewport = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "selectedMPRViewport" }] : [])); isInitialViewportLayout = _angular_core__WEBPACK_IMPORTED_MODULE_2__.input.required(...(ngDevMode ? [{ debugName: "isInitialViewportLayout" }] : [])); lastSelectedMPRViewport = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportName.CORONAL, ...(ngDevMode ? [{ debugName: "lastSelectedMPRViewport" }] : [])); // The app page's camera slider, docked on the workspace's volume panel in CPR mode. cameraSliderTemplate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(...(ngDevMode ? [undefined, { debugName: "cameraSliderTemplate" }] : [])); renderingEngineId = this.renderingEngineService.ENGINE_ID; selectedPhaseId = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(undefined, ...(ngDevMode ? [{ debugName: "selectedPhaseId" }] : [])); isVolumeSwitching = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isVolumeSwitching" }] : [])); seriesPhases = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const uid = this.seriesUid(); return uid ? this.viewerOrchestrator.seriesPhases(uid) : []; }, ...(ngDevMode ? [{ debugName: "seriesPhases" }] : [])); availablePhases = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const phases = this.seriesPhases(); // Precedence: restored selection > pre-load modal > all. const stored = this.viewerOrchestrator.phaseSelection(this.seriesUid())?.availablePhaseIds; const selected = stored ?? this.selectedPhaseIds(); if (!selected || selected.length === 0) return phases; const selectedSet = new Set(selected); const filtered = phases.filter(phase => selectedSet.has(phase.id)); return filtered.length > 0 ? filtered : phases; }, ...(ngDevMode ? [{ debugName: "availablePhases" }] : [])); hasMultiplePhases = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.availablePhases().length > 1, ...(ngDevMode ? [{ debugName: "hasMultiplePhases" }] : [])); activePhaseInstanceUIDs = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const phaseId = this.selectedPhaseId(); const phase = this.availablePhases().find(p => p.id === phaseId); if (!phase) return []; return phase.imageIds.map(id => (0,_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_17__.parseImageId)(id).sopInstanceUID); }, ...(ngDevMode ? [{ debugName: "activePhaseInstanceUIDs" }] : [])); // Locale-independent phase label for DICOM export (e.g. "75%" or "120ms"). // Empty string for non-gated series or when no phase is selected. activePhaseLabel = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { if (!this.isGated()) return ''; const phaseId = this.selectedPhaseId(); const phase = this.availablePhases().find(p => p.id === phaseId); const id = phase?.identification; if (!id) return ''; if (id.rrPercent !== undefined) return `${Math.round(id.rrPercent)}%`; if (id.triggerTime !== undefined) return `${id.triggerTime}ms`; return ''; }, ...(ngDevMode ? [{ debugName: "activePhaseLabel" }] : [])); /** Structured protocol metadata; unlike activePhaseLabel this is not presentation-only. */ activePhaseSelection = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const phaseId = this.selectedPhaseId(); const phase = this.availablePhases().find(candidate => candidate.id === phaseId); if (!phase) return; const id = phase.identification; if (id?.rrPercent !== undefined) { return { phaseId: phase.id, phaseUnit: 'percent', phaseValue: String(Math.round(id.rrPercent)) }; } if (id?.triggerTime !== undefined) { return { phaseId: phase.id, phaseUnit: 'milliseconds', phaseValue: String(id.triggerTime) }; } return { phaseId: phase.id, phaseUnit: 'unlabelled', phaseValue: 'unlabelled' }; }, ...(ngDevMode ? [{ debugName: "activePhaseSelection" }] : [])); switchToPhaseByLabel(label) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!label) return; const phase = _this.availablePhases().find(p => { const id = p.identification; if (!id) return false; if (id.rrPercent !== undefined) return `${Math.round(id.rrPercent)}%` === label; if (id.triggerTime !== undefined) return `${id.triggerTime}ms` === label; return false; }); if (phase) yield _this.onSelectVolume(phase.id); })(); } switchToPhaseById(phaseId) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this2.availablePhases().some(phase => phase.id === phaseId)) { yield _this2.onSelectVolume(phaseId); return true; } return false; })(); } captureViewportPreview(size = 128) { const ids = [_viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.AXIAL, _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.SAGITTAL, _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.CORONAL]; let canvas; for (const id of ids) { const vp = this.renderingEngineService.getViewport(id.valueOf()); if (vp?.canvas) { canvas = vp.canvas; break; } } if (!canvas) return undefined; try { const offscreen = new OffscreenCanvas(size, size); const context = offscreen.getContext('2d'); if (!context) return undefined; context.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, size, size); const { data } = context.getImageData(0, 0, size, size); const rgb = new Uint8Array(size * size * 3); for (let rgbaOffset = 0, rgbOffset = 0; rgbaOffset < data.length; rgbaOffset += 4, rgbOffset += 3) { rgb[rgbOffset] = data[rgbaOffset] ?? 0; rgb[rgbOffset + 1] = data[rgbaOffset + 1] ?? 0; rgb[rgbOffset + 2] = data[rgbaOffset + 2] ?? 0; } return rgb; } catch { return undefined; } } // Gated (cardiac) when any offered phase carries identification → "Phase"; else "Volume". isGated = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.availablePhases().some(phase => phase.identification !== undefined), ...(ngDevMode ? [{ debugName: "isGated" }] : [])); // instant() is not reactive; recompute once the language file arrives or the language changes. langChange = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__.toSignal)(this.translate.onLangChange); volumeWord = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { this.langChange(); return this.translate.instant(this.isGated() ? 'multiphase.phase' : 'multiphase.volume'); }, ...(ngDevMode ? [{ debugName: "volumeWord" }] : [])); phaseSelectOptions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const word = this.volumeWord(); const triggerUnit = this.translate.instant('multiphase.triggerUnit'); return this.availablePhases().map(phase => { const base = `${word} ${phase.label}`; const detail = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.formatPhaseIdentification)(phase.identification, { triggerUnit }); return { label: detail ? `${base}: ${detail}` : base, value: phase.id }; }); }, ...(ngDevMode ? [{ debugName: "phaseSelectOptions" }] : [])); toggleMaximizeViewport = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); focusedMPRViewportChange = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); selectedMPRViewportChange = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); escPressed = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.output)(); isBlur = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(false, ...(ngDevMode ? [{ debugName: "isBlur" }] : [])); maximizedPanelId = undefined; focusedMPRViewportId = _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.CORONAL; selectedMPRViewportId = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportName.CORONAL; lastSelectedMPRViewportId = _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportName.CORONAL; initialViewportLayout = false; studySeriesKey = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const studyUid = this.studyUid(); const seriesUid = this.seriesUid(); return `${studyUid}::${seriesUid}`; }, ...(ngDevMode ? [{ debugName: "studySeriesKey" }] : [])); seriesUid$ = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__.toObservable)(this.seriesUid); storeUid$ = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__.toObservable)(this.storeUid); emptySeriesCacheProgress = { cachedCount: 0, percent: 0, totalCount: 0 }; seriesCacheProgressSubscription; seriesCacheProgress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(this.emptySeriesCacheProgress, ...(ngDevMode ? [{ debugName: "seriesCacheProgress" }] : [])); loadingProgress = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const cache = this.seriesCacheProgress(); const loading = this.viewerOrchestrator.status() === 'loading' || this.viewerOrchestrator.isCachingSource(); return { ...cache, loading }; }, ...(ngDevMode ? [{ debugName: "loadingProgress" }] : [])); annotationMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)([], ...(ngDevMode ? [{ debugName: "annotationMenuItems" }] : [])); annotationMenuItemService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_annotation_menu_annotation_menu_item_service__WEBPACK_IMPORTED_MODULE_24__.AnnotationMenuItemService); ctxMenu = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)('ctxMenu', ...(ngDevMode ? [{ debugName: "ctxMenu" }] : [])); alignMenu = _angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild.required('alignMenu'); // Only stamped while the CPR layout is rendered; it owns the carrier mounts. cprWorkspace = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.viewChild)(_cpr_cpr_workspace_component__WEBPACK_IMPORTED_MODULE_36__.CprWorkspaceComponent, ...(ngDevMode ? [{ debugName: "cprWorkspace" }] : [])); layoutBeforeCpr = undefined; cprActive = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.cprService.desiredLayout() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.CPR, ...(ngDevMode ? [{ debugName: "cprActive" }] : [])); // Derived from the authoritative viewportLayout input rather than maximizedPanelId, so it // stays correct regardless of which entry point maximized the s-curve view (the grid-tile's // own maximize button, or the shortcut from the sidebar drawer, which never touches // maximizedPanelId since that's only set by this component's own onToggleMaximizeViewport). sCurveMaximized = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.viewportLayout() === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_S_CURVE, ...(ngDevMode ? [{ debugName: "sCurveMaximized" }] : [])); /** True for the app-level maximize outside CPR, and for the workspace's own inside it. */ isViewportMaximized(viewportId) { if (!this.cprActive()) return this.maximizedPanelId === viewportId; // Unmapped viewports (the hidden MPRs) must not match an unset maximized panel. const panel = _cpr_cpr_config__WEBPACK_IMPORTED_MODULE_35__.CPR_PANEL_BY_VIEWPORT_ID[viewportId]; return panel !== undefined && this.cprSession.maximizedPanel() === panel; } freezeShortAxis() { this.cprWorkspace()?.freezeShortAxis(); } unfreezeShortAxis() { this.cprWorkspace()?.unfreezeShortAxis(); } interactionModeService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_interaction_mode_interaction_mode_service__WEBPACK_IMPORTED_MODULE_29__.InteractionModeService); interactionMode = this.interactionModeService.interactionMode; createMode = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.annotationFacade.annotationBeingCreated() !== undefined, ...(ngDevMode ? [{ debugName: "createMode" }] : [])); cardAnnotation = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const selected = this.selectedAnnotations(); if (selected.length > 1) return; return selected[0]; }, ...(ngDevMode ? [{ debugName: "cardAnnotation" }] : [])); floatingCardOpen = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(true, ...(ngDevMode ? [{ debugName: "floatingCardOpen" }] : [])); floatingCardValue = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const annotation = this.cardAnnotation(); return this.floatingCardOpen() && annotation ? [annotation.id] : []; }, ...(ngDevMode ? [{ debugName: "floatingCardValue" }] : [])); onFloatingCardValueChange(value) { this.floatingCardOpen.set(Array.isArray(value) ? value.length > 0 : value !== null && value !== undefined); } volumeIds; // When active is false, viewports will have their interactivity disabled. // This is currently used to prevent unwanted interaction while a context menu is open. active = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(true, ...(ngDevMode ? [{ debugName: "active" }] : [])); showSCurveGraph = this.uiFacade.sCurveGraphDetached; menuPt = { root: { // Prevents being able to right-click an open menu and open the native menu oncontextmenu(event) { event.preventDefault(); }, style: { position: 'fixed' } }, submenu: 'min-w-max' }; handleKeyDown(event) { if (this.menuTracker.closeTopMenu()) { return; } // Check if a dialog is open, and handle that first. Take the last one in case there is a stack of open dialogs const dialogReference = [...this.dialogService.dialogComponentRefMap.values()].at(-1); if (dialogReference) { dialogReference.instance.close(); return; } event.stopPropagation(); event.preventDefault(); if (this.cprSession.editState() === 'editing') { this.cprService.cancelEdit(); return; } if (this.protocolCreation.cancelCurrentStep()) { return; } switch (this.interactionMode().type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.ADD_POINTS: { this.interactionModeService.clearMode(); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.CREATE: { this.protocolCreation.stop(); this.annotationFacade.cancelAnnotationCreation(); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.SELECT: { this.escPressed.emit(); break; } } } handleEnterKey(event) { if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.isEditableTarget)(event.target)) return; const interactionMode = this.interactionMode(); // Adding points to an already-finished spline - there's nothing to validate (the // annotation was already complete before this mode started), so just exit it, same // as Escape does for this mode. if (interactionMode.type === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.ADD_POINTS) { event.preventDefault(); this.interactionModeService.clearMode(); return; } if (interactionMode.type !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.CREATE) return; if (!(0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_18__.annotationIsSpline)(interactionMode.annotation)) return; event.preventDefault(); this.interaction.completeAnnotationCreationIfValid(interactionMode.annotation); } handleDeleteKey(event) { if ((0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.isEditableTarget)(event.target)) return; // The spline being edited is normally the selected annotation, so this would delete the // very thing the reformation is showing. if (this.cprSession.editState() === 'editing') return; const selectedIds = this.annotationFacade.selectedIds(); if (selectedIds.length === 0) return; event.stopPropagation(); event.preventDefault(); this.annotationMenuItemService.confirmDeleteSelectedAnnotations(event.target); } constructor() { var _this3 = this; const fullscreenEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.windowService.isFullscreen(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => this.annotationFacade.cancelAnnotationCreation()); }, ...(ngDevMode ? [{ debugName: "fullscreenEffect" }] : [])); // NOTE: For an unknown reason, the 3d volume doesn't properly // display when switching tabs until interacting. // This small effect can fix that issue until we figure out the cause. const workSessionChangeEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.workSessionUid(); setTimeout(() => { this.viewerOrchestrator.forceRerender(); }, 10); }, ...(ngDevMode ? [{ debugName: "workSessionChangeEffect" }] : [])); const annotationScaleEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.viewerOrchestrator.annotationScaleCacheBuster(); this.annotationActors.refreshForViewportScaleChange(); }, ...(ngDevMode ? [{ debugName: "annotationScaleEffect" }] : [])); const loadEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.studySeriesKey(); // Trigger effect when study/series changes (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this3.isSeriesResetting = true; _this3.volumeIds = undefined; _this3.selectedPhaseId.set(undefined); _this3.isVolumeSwitching.set(false); _this3.cprService.activeVolumeId.set(undefined); _this3.annotationActors.setViewports([]); _this3.annotationFacade.clearAnnotations(); _this3.chamberFacade.clearChambers(); try { yield _this3.viewerOrchestrator.resetForSeriesChange(); // Only decache once resetForSeriesChange has disabled every viewport - decaching // first would drop a volume's data while a viewport actor could still be bound to // it mid-render. for (const volumeIds of _this3.phaseVolumeIds.values()) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); } _this3.phaseVolumeIds.clear(); for (const volumeIds of _this3.pendingStaleVolumeDiscards) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); } _this3.pendingStaleVolumeDiscards.length = 0; } finally { _this3.isSeriesResetting = false; } _this3.setup(); })); }, ...(ngDevMode ? [{ debugName: "loadEffect" }] : [])); // Bridge CprService's requested layout to the app via the maximize channel. const cprLayoutEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { const desired = this.cprService.desiredLayout(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => { if (desired === _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.CPR) { this.layoutBeforeCpr = this.viewportLayout(); this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.CPR); return; } if (this.layoutBeforeCpr !== undefined) { this.toggleMaximizeViewport.emit(this.layoutBeforeCpr); this.layoutBeforeCpr = undefined; } }); }, ...(ngDevMode ? [{ debugName: "cprLayoutEffect" }] : [])); this.openContextMenuSubscriber(); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef).onDestroy(() => { fullscreenEffect.destroy(); workSessionChangeEffect.destroy(); annotationScaleEffect.destroy(); loadEffect.destroy(); cprLayoutEffect.destroy(); }); } captureChamberFromCurrentView() { this.chamberService.createNewChamber({ angulation: this.viewportAngulation(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.MIDDLEMAIN)(), ax: this.viewportStore.ax(), crosshairRotation: this.viewportCrosshairRotation(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.MIDDLEMAIN)(), intersection: this.viewportStore.intersection(), isocenter: this.viewportStore.isocenter(), isPosterior: this.isPosterior() }); } viewportEffectReady = false; initViewportEffect() { if (this.viewportEffectReady) return; const initEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { const toInit = this.viewerOrchestrator.viewportsToEnable(); if (toInit.length > 0) { this.setup(); } }, ...(ngDevMode ? [{ debugName: "initEffect" }] : [])); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef).onDestroy(() => { initEffect.destroy(); }); this.viewportEffectReady = true; } volumeRequestEffectReady = false; initVolumeRequestEffect() { if (this.volumeRequestEffectReady) return; const requestEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { const request = this.viewerOrchestrator.requestedActiveVolume(); if (!request) return; (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => { this.viewerOrchestrator.clearRequestedActiveVolume(); this.handleVolumeRequest(request).catch(error => this.log.error('Failed to handle volume request', error)); }); }, ...(ngDevMode ? [{ debugName: "requestEffect" }] : [])); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef).onDestroy(() => { requestEffect.destroy(); }); this.volumeRequestEffectReady = true; } handleVolumeRequest(request) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (request.phaseId !== _this4.selectedPhaseId()) { yield _this4.onSelectVolume(request.phaseId); } if (_this4.destroyed) return; if (request.revealAnnotationId) { _this4.annotationFacade.selectAnnotations([request.revealAnnotationId]); _this4.viewerOrchestrator.moveCrosshairToAnnotation(request.revealAnnotationId); } if (request.revealChamberId) { _this4.chamberFacade.selectChambers([request.revealChamberId]); } })(); } // We don't initialize these effects until the volume has been loaded formEffectsReady = false; initFormEffects() { if (this.formEffectsReady) return; const ctFormUpdateEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { // Don't need the value, just need to trigger when change this.renderSettingsStore.windowSettings.name(); const seriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => this.seriesUid()); // Also track seriesWindowState so the effect re-fires once loadSeries populates it. // Guard: skip until window state is ready to avoid a premature call. if (!this.viewerOrchestrator.seriesWindowState(seriesUid)) return; this.ctPopoverService.seriesUid.set(seriesUid); this.ctFormConfig.set(this.ctPopoverService.getCtFormConfig()); }, ...(ngDevMode ? [{ debugName: "ctFormUpdateEffect" }] : [])); const volumeFormUpdateEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.renderSettingsStore.volumeSettings(); this.viewerOrchestrator.vascularSegmentationState(); this.viewerOrchestrator.vascularMaskComputing(); const seriesUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => this.seriesUid()); this.volumeRenderingPopoverService.seriesUid.set(seriesUid); this.volumeRenderFormConfig.set((0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => this.volumeRenderingPopoverService.getVolumeRenderingFormConfig())); }, ...(ngDevMode ? [{ debugName: "volumeFormUpdateEffect" }] : [])); const orientationFormUpdateEffect = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.effect)(() => { this.viewerOrchestrator.editOrientationTargetId(); this.orientationFormRefresh(); this.orientationFormConfig.set((0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => { const sliders = (0,_orientation_form_config__WEBPACK_IMPORTED_MODULE_40__.buildOrientationFormConfig)(() => this.editOrientationTarget(), annotation => this.annotationFacade.updateAnnotation(annotation), () => this.viewerOrchestrator.decrease3dViewportImageQuality(), () => this.viewerOrchestrator.increase3dViewportImageQuality()); if (sliders.length === 0) return sliders; const alignWithField = { defaultValue: '', icon: 'align-horizontal-center', label: 'annotationMenu.alignWith', name: 'alignWith', onTrigger: event => this.alignMenu().show(event), type: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.SettingsPopoverField.MENU_BUTTON }; return [alignWithField, ...sliders]; })); }, ...(ngDevMode ? [{ debugName: "orientationFormUpdateEffect" }] : [])); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef).onDestroy(() => { ctFormUpdateEffect.destroy(); volumeFormUpdateEffect.destroy(); orientationFormUpdateEffect.destroy(); }); this.formEffectsReady = true; } editOrientationTarget() { const id = this.viewerOrchestrator.editOrientationTargetId(); if (!id) return undefined; const annotation = this.annotationFacade.getAnnotationById(id); return (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_18__.annotationIsObject3D)(annotation) ? annotation : undefined; } alignMenuItems = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { const target = this.editOrientationTarget(); if (!target) return []; return this.annotationMenuItemService.alignWithItems(target, () => this.orientationFormRefresh.update(tick => tick + 1)); }, ...(ngDevMode ? [{ debugName: "alignMenuItems" }] : [])); readyToSetup = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => !!this.studyUid() && !!this.seriesUid() && this.layoutConfig().length === this.viewportStates().length, ...(ngDevMode ? [{ debugName: "readyToSetup" }] : [])); viewportStates = this.viewerOrchestrator.viewportStates; ngOnInit() { this.ctPopoverService.seriesUid.set(this.seriesUid()); this.volumeRenderingPopoverService.seriesUid.set(this.seriesUid()); this.seriesCacheProgressSubscription = (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.combineLatest)([this.seriesUid$, this.storeUid$]).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_9__.switchMap)(([seriesUid, storeUid]) => { if (!seriesUid || !storeUid) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.of)(this.emptySeriesCacheProgress); } return this.viewerOrchestrator.streamSeriesCacheProgress(seriesUid, storeUid); })).subscribe(progress => { this.seriesCacheProgress.set(progress); }); } onViewportReady(event) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { _this5.viewerOrchestrator.registerViewport(event.element, event.options, _this5.seriesUid()); _this5.viewerOrchestrator.forceRerender(); })(); } ngAfterViewInit() { this.setup(); } initVolume() { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // Only have to loadSeries once, not between layout changes if (_this6.volumeIds !== undefined) return; const initSeriesKey = _this6.studySeriesKey(); // Reopen must read the restored selection before loadSeries, else prefetch re-downloads // deselected phases. yield _this6.viewerOrchestrator.whenWorkSessionLoaded(); if (_this6.destroyed) return; const restoredSelection = _this6.viewerOrchestrator.phaseSelection(_this6.seriesUid())?.availablePhaseIds; const selectedPhaseIds = restoredSelection ?? _this6.selectedPhaseIds(); const imageIds = yield _this6.viewerOrchestrator.loadSeries(_this6.seriesUid(), _this6.studyUid(), _this6.storeUid(), selectedPhaseIds); if (_this6.viewerOrchestrator.wasSeriesUnseparable(_this6.seriesUid(), _this6.studyUid(), _this6.storeUid())) { _this6.messageService.add({ detail: _this6.translate.instant('unseparablePhases.detail'), severity: 'warn', summary: _this6.translate.instant('unseparablePhases.summary') }); } // A volume built from the flattened image set would mix phases that share slice positions into // an invalid volume, so exactly one phase is opened. const phases = _this6.availablePhases(); const restoredActiveId = _this6.viewerOrchestrator.phaseSelection(_this6.seriesUid())?.activePhaseId; const activePhase = phases.find(phase => phase.id === restoredActiveId) ?? phases[0]; const phaseId = activePhase?.id ?? 'default:0'; _this6.selectedPhaseId.set(phaseId); // Persist the resolved selection so a fresh open is captured by the work-session auto-save. _this6.viewerOrchestrator.setPhaseSelection(_this6.seriesUid(), phases.map(phase => phase.id), phaseId); let volumeIds; try { volumeIds = yield _this6.loadPhaseVolume(phaseId, activePhase?.imageIds ?? imageIds); } catch (error) { if (!_this6.isStaleLoad(initSeriesKey)) { _this6.viewerOrchestrator.reportVolumeLoadError(error); } return; } if (_this6.isStaleLoad(initSeriesKey)) { _this6.discardStaleVolume(phaseId, volumeIds); return; } _this6.volumeIds = volumeIds; _this6.cprService.activeVolumeId.set(_this6.volumeIds.mprVolumeId); _this6.measurementService.updateVolume(_this6.volumeIds.mprVolumeId); _this6.viewerOrchestrator.setVolumeCenter(_this6.volumeIds.mprVolumeId); _this6.warmPhaseVolumesInBackground(initSeriesKey, phaseId); })(); } warmPhaseVolumesInBackground(seriesKey, activePhaseId) { var _this7 = this; const phases = this.availablePhases(); const activeIndex = phases.findIndex(phase => phase.id === activePhaseId); // 1) Eagerly warm the next likely phase immediately. const likelyNext = activeIndex !== -1 && activeIndex + 1 < phases.length ? phases[activeIndex + 1] : undefined; if (likelyNext && !this.phaseVolumeIds.has(likelyNext.id)) { queueMicrotask(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this7.destroyed || _this7.isStaleLoad(seriesKey)) return; try { yield _this7.loadPhaseVolume(likelyNext.id, likelyNext.imageIds); } catch { // best-effort } })); } // 2) Warm remaining phases during idle time. const idle = globalThis.requestIdleCallback ?? (callback => globalThis.setTimeout(() => callback({ didTimeout: true, timeRemaining: () => 0 }), 50)); idle(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this7.destroyed || _this7.isStaleLoad(seriesKey)) return; for (const phase of phases) { if (phase.id === activePhaseId) continue; if (likelyNext && phase.id === likelyNext.id) continue; if (_this7.destroyed || _this7.isStaleLoad(seriesKey)) return; if (_this7.phaseVolumeIds.has(phase.id)) continue; try { yield _this7.loadPhaseVolume(phase.id, phase.imageIds); } catch { // best-effort } } }), // start soon on busy main thread { timeout: 300 }); } loadPhaseVolume(phaseId, imageIds) { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const seriesKey = _this8.studySeriesKey(); const cacheKey = `${seriesKey}::${phaseId}`; const cached = _this8.phaseVolumeIds.get(cacheKey); if (cached) return cached; const inFlight = _this8.inFlightPhaseLoads.get(cacheKey); if (inFlight) return inFlight; const loadPromise = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.loadVolumeImages)(imageIds, `${_this8.seriesUid()}-${phaseId}`).then(volumeIds => { // Only cache if still relevant (series hasn't changed) if (_this8.studySeriesKey() === seriesKey && !_this8.destroyed) { _this8.phaseVolumeIds.set(cacheKey, volumeIds); return volumeIds; } else { // Stale load - decache immediately (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); throw new Error('Series changed during load'); } }).finally(() => { _this8.inFlightPhaseLoads.delete(cacheKey); }); _this8.inFlightPhaseLoads.set(cacheKey, loadPromise); return loadPromise; })(); } /** * Whether a load captured under `capturedSeriesKey` is no longer relevant to apply - the * series was destroyed, reset, or changed to a different one while the load was in flight. */ isStaleLoad(capturedSeriesKey) { return this.destroyed || this.isSeriesResetting || this.studySeriesKey() !== capturedSeriesKey; } /** * loadPhaseVolume caches into phaseVolumeIds as soon as it resolves, before its caller gets a * chance to notice the series has already moved on - release it here instead of leaking it in * Cornerstone's cache for the rest of the session. */ discardStaleVolume(phaseId, volumeIds) { const seriesKey = this.studySeriesKey(); const cacheKey = `${seriesKey}::${phaseId}`; if (this.phaseVolumeIds.get(cacheKey) === volumeIds) { this.phaseVolumeIds.delete(cacheKey); } if (this.isSeriesResetting) { // A series reset is already tearing down viewports concurrently - decaching now could // drop this volume's data while it's still bound to one mid-render. Defer to the reset's // own cleanup, which only runs after resetForSeriesChange has disabled every viewport. this.pendingStaleVolumeDiscards.push(volumeIds); return; } (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); } onSelectVolume(phaseId) { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (phaseId === _this9.selectedPhaseId() || _this9.isVolumeSwitching()) return; const availablePhases = _this9.availablePhases(); const phase = availablePhases.find(candidate => candidate.id === phaseId); if (!phase) return; const previousPhaseId = _this9.selectedPhaseId(); const switchSeriesKey = _this9.studySeriesKey(); const cancelled = _this9.protocolCreation.cancelCurrentStep(); if (!cancelled) { _this9.annotationFacade.cancelAnnotationCreation(); } _this9.isVolumeSwitching.set(true); try { const volumeIds = yield _this9.loadPhaseVolume(phase.id, phase.imageIds); if (_this9.isStaleLoad(switchSeriesKey)) { _this9.discardStaleVolume(phase.id, volumeIds); return; } yield _this9.viewerOrchestrator.setActiveVolume(volumeIds); if (_this9.isStaleLoad(switchSeriesKey)) { _this9.discardStaleVolume(phase.id, volumeIds); return; } _this9.volumeIds = volumeIds; _this9.cprService.activeVolumeId.set(volumeIds.mprVolumeId); _this9.measurementService.updateVolume(volumeIds.mprVolumeId); _this9.viewerOrchestrator.setVolumeCenter(volumeIds.mprVolumeId); _this9.selectedPhaseId.set(phase.id); _this9.viewerOrchestrator.setPhaseSelection(_this9.seriesUid(), availablePhases.map(candidate => candidate.id), phase.id); // Persist the outgoing bundle and mirror the incoming one into the stores before rendering. if (previousPhaseId !== undefined) { _this9.viewerOrchestrator.switchActiveVolume(previousPhaseId, phase.id); } // Preset must be applied before forceRerender, else renderAll() flashes a stale, MPR-looking frame. _this9.viewerOrchestrator.reapplyVolumeRenderSettings(); _this9.viewerOrchestrator.renderStoredCameras(); _this9.viewerOrchestrator.forceRerender(); } catch (error) { if (!_this9.isStaleLoad(switchSeriesKey)) { _this9.viewerOrchestrator.reportVolumeLoadError(error); } } finally { _this9.isVolumeSwitching.set(false); } })(); } setup() { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (_this0.isSeriesResetting) return; if (!_this0.readyToSetup()) return; const viewportConfig = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.untracked)(() => _this0.viewerOrchestrator.viewportsToEnable()); const firstLoad = _this0.volumeIds === undefined; if (firstLoad) { yield _this0.initVolume(); } if (_this0.volumeIds === undefined) { return; } _this0.viewerOrchestrator.resetCameraRendered(); const enabledIds = yield _this0.viewerOrchestrator.enableViewports(viewportConfig, _this0.volumeIds); // Load may outlast the component; bail before touching the injector. if (_this0.destroyed) return; (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.runInInjectionContext)(_this0.injector, () => { _this0.initFormEffects(); _this0.viewerOrchestrator.initEffects(); _this0.annotationActors.initEffects(); _this0.initViewportEffect(); _this0.initVolumeRequestEffect(); }); _this0.viewerOrchestrator.forceRerender(); // Without this, layout changes can show stale viewports // CPR carriers must not receive MPR-space annotation actors — they'd paint over the ribbon. _this0.annotationActors.setViewports(_this0.renderingEngineService.getActiveViewports().filter(viewport => !(0,_cpr_cpr_config__WEBPACK_IMPORTED_MODULE_35__.isCprCarrierViewportId)(viewport.id))); _this0.viewerOrchestrator.completeViewports(enabledIds); })(); } onShowAnnotation(annotationId) { this.annotationMenuItemService.showAnnotation(annotationId); } onHideAnnotation(annotationId) { this.annotationMenuItemService.hideAnnotation(annotationId); } onGoToAnnotation(annotationId) { this.annotationMenuItemService.goToAnnotation(annotationId); } onUpdateAnnotationName(newName, annotationId) { this.annotationMenuItemService.updateAnnotationName(annotationId, newName); } selectedAnnotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => { return this.annotationFacade.selectedAnnotationsWithMeasurements().map(annotation => { const menuItems = this.annotationMenuItemService.menuItemsForAnnotation(annotation); const contentMenuItems = menuItems.filter(({ includeInCard }) => includeInCard); return { ...annotation, contentMenuItems, moreActions: menuItems }; }); }, ...(ngDevMode ? [{ debugName: "selectedAnnotations" }] : [])); getViewportStateById(viewportId) { const initialConfig = this.layoutConfig().find(({ id }) => id === viewportId); if (!initialConfig) { throw new Error(`Configuration not found for viewport ID: ${viewportId}. Check VIEWPORT_LAYOUT_CONFIG.`); } return initialConfig; } isPosterior = this.viewportStore.isPosterior; handleViewportClick(event, viewportId) { this.viewerOrchestrator.closeEndoDevPanel(); this.viewerOrchestrator.closeVascularDevPanel(); this.viewerOrchestrator.closeRenderQualityDevPanel(); const clickResult = this.interaction.handleViewportMouseDown(event, viewportId); if (!clickResult) return; const { isDoubleClick } = clickResult; const interactionMode = this.interactionMode(); switch (interactionMode.type) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.ADD_POINTS: { this.interaction.handleAddPointClick(viewportId, interactionMode.annotationId, isDoubleClick); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.CREATE: { this.interaction.handleAnnotationCreationClick(viewportId, interactionMode.annotation, isDoubleClick); break; } case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.InteractionModeType.SELECT: { if (isDoubleClick) { this.onToggleMaximizeViewport(viewportId); } const isMultiselect = event.ctrlKey || event.shiftKey; const details = this.interaction.handleAnnotationSelectionClick(viewportId, isMultiselect); if (details) { this.cprService.snapCursorToSpline(details, viewportId, [event.offsetX, event.offsetY]); } break; } } } onToggleMaximizeViewport(viewportId) { if (this.cprActive()) { // Workspace-internal maximize: a grid re-flow, never `LayoutType.MAXIMIZE_*`, which // would re-stamp the templates and orphan the session. const panel = _cpr_cpr_config__WEBPACK_IMPORTED_MODULE_35__.CPR_PANEL_BY_VIEWPORT_ID[viewportId]; if (panel) this.cprSession.toggleMaximizedPanel(panel); return; } if (this.viewportLayout() !== _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.DEFAULT) { this.setDefaultViewportLayout(); return; } switch (viewportId) { case _tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.PanelName.S_CURVE_GRAPH: { this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_S_CURVE); break; } case _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.AXIAL: { this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_AXIAL); break; } case _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.CORONAL: { this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_CORONAL); break; } case _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.REFORMAT: { this.refreshVolumeRenderFormConfig(); this.viewerOrchestrator.setReformatMaximized(true); this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_3D); break; } case _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.SAGITTAL: { this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.MAXIMIZE_SAGITTAL); break; } default: { this.log.error(`Unknown viewport ID: ${viewportId}. Cannot toggle maximize.`); return; } } this.maximizedPanelId = viewportId; } setDefaultViewportLayout() { if (this.maximizedPanelId === _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.REFORMAT) { this.refreshVolumeRenderFormConfig(); this.viewerOrchestrator.setReformatMaximized(false); } // Maximized and detached are independent states (TVC-1238) - this must not touch // uiFacade's detached flag; the sidebar panel hides its own s-curve copy purely from // isMaximized (see SCurvePanelComponent.showGraph), so whatever detached state the graph // had before maximizing is exactly what it returns to here. this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.DEFAULT); this.maximizedPanelId = undefined; } refreshVolumeRenderFormConfig() { this.volumeRenderFormConfig.set(this.volumeRenderingPopoverService.getVolumeRenderingFormConfig()); } onFocusedMPRViewportSelect(viewportId) { this.lastSelectedMPRViewportId = this.selectedMPRViewportId; this.focusedMPRViewportId = viewportId; if (viewportId === _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.REFORMAT) { this.log.warn('Cannot swap viewport in focus for 3D/Reformat viewport.'); return; } this.viewportStore.swapViewportAxis(viewportId); // Cornerstone's MPR viewport doesn't settle its slice state after a 90° camera flip. // Nudging the angulation by ±0.1° triggers two full camera-effect cycles which // forces both viewports to re-initialise their image planes cleanly. this.viewportStore.nudgeAngulationsToForceResettle(); } onResizeStart() { // Capture the short-axis's correct frame before resetCameraForResize zooms it. this.freezeShortAxis(); this.isBlur.set(true); this.renderingEngineService.resetCameraForResize(); // Clear any existing interval (safety check) clearInterval(this.resizeIntervalId); //Call resetCameraForResize every 1ms during resize - this avoids jellification of viewports this.resizeIntervalId = setInterval(() => this.healViewportCameras(), 1); } /** Resizes the engine, then re-fixes the CPR camera windows. */ healViewportCameras() { this.renderingEngineService.resetCameraForResize(); this.cprService.refreshShortAxisCamera(); this.cprService.refreshLongAxisCamera(); this.viewerOrchestrator.forceRerender(); } onResizeEnd() { // Clear the interval when resize ends if (this.resizeIntervalId !== undefined) { clearInterval(this.resizeIntervalId); this.resizeIntervalId = undefined; } // Clear any pending resize timeout if (this.resizeTimeoutId !== undefined) { clearTimeout(this.resizeTimeoutId); this.resizeTimeoutId = undefined; } setTimeout(() => { this.renderingEngineService.resetCameraForResize(); this.viewerOrchestrator.forceRerender(); this.revealCorrectedShortAxis(); }, 200); } // Re-impose the short-axis FOV, un-blur, then drop the frozen still one frame // later — so the corrected live render has painted before it's revealed. revealCorrectedShortAxis() { requestAnimationFrame(() => { this.cprService.refreshShortAxisCamera(); this.cprService.refreshLongAxisCamera(); requestAnimationFrame(() => { this.cprService.refreshShortAxisCamera(); this.cprService.refreshLongAxisCamera(); this.isBlur.set(false); requestAnimationFrame(() => this.unfreezeShortAxis()); }); }); } onWindowResize() { // If this is the first resize event, call onResizeStart if (!this.isWindowResizing) { this.isWindowResizing = true; this.onResizeStart(); } // Clear any existing timeout if (this.resizeTimeoutId !== undefined) { clearTimeout(this.resizeTimeoutId); } // Set a timeout to detect when resize ends (debounce) this.resizeTimeoutId = setTimeout(() => { this.isWindowResizing = false; this.onResizeEnd(); this.resizeTimeoutId = undefined; }, 150); } /** Handles a canvas-resolution mismatch after a devicePixelRatio change that produced no usable * `resize` (OS scale change, move to a differently-scaled monitor). * * Retries because Cornerstone silently drops a resize while a render is pending. */ revalidateCanvasResolution(attempt = 0) { clearTimeout(this.revalidateTimeoutId); this.revalidateTimeoutId = undefined; if (this.destroyed || this.isWindowResizing) return; if (attempt >= REVALIDATE_MAX_ATTEMPTS || !this.renderingEngineService.hasStaleCanvasResolution()) { return; } this.healViewportCameras(); this.revalidateTimeoutId = setTimeout(() => this.revalidateCanvasResolution(attempt + 1), REVALIDATE_RETRY_DELAY_MS); } handleViewportMouseMove(event, viewportId) { this.revalidateOnPointerActivity(); this.interaction.handleViewportMouseMove(event, viewportId); } /** Mouse events arrive even when the window is unfocused, so no focus or resize event * can be relied on to precede them. Check every move, heal once per movement burst. */ revalidateOnPointerActivity() { if (this.revalidateTimeoutId !== undefined || this.isWindowResizing) return; this.debouncedPointerHeal(); } onContextMenu(event) { // Suppress the browser's native context menu; our PrimeNG `ctxMenu` is // opened programmatically from `handleMouseUp` on right-clicks. event.preventDefault(); if (event.ctrlKey) { event.stopImmediatePropagation(); } } handleMouseUp(event) { const { shouldOpenContextMenu } = this.interaction.handleMouseUp(); this.cprService.releaseControlPoint(); if (shouldOpenContextMenu) { this.ctxMenu()?.show(event); } } /** A drag released outside the viewport never reaches `handleMouseUp`. */ handleWindowMouseUp() { this.interaction.handleMouseUp(); this.cprService.releaseControlPoint(); } toggleViewportContextMenu(event) { this.annotationMenuItems.set(this.annotationMenuItemService.menuItemsForViewport()); this.ctxMenu()?.toggle(event); } viewportAxis(viewportId) { return this.viewportStore.viewportAxisMapping[viewportId]; } viewportColors = { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.ALTERNATEBOTTOMLEFT]: { h: 'var(--p-app-viewport-axis-coronal)', v: 'var(--p-app-viewport-axis-axial)' }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.ALTERNATETOPLEFTMAIN]: { h: 'var(--p-app-viewport-axis-sagittal)', v: 'var(--p-app-viewport-axis-coronal)' }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.BOTTOMLEFTMAIN]: { h: 'var(--p-app-viewport-axis-coronal)', v: 'var(--p-app-viewport-axis-axial)' }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.MIDDLEMAIN]: { h: 'var(--p-app-viewport-axis-axial)', v: 'var(--p-app-viewport-axis-sagittal)' }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.RIGHTMAIN]: { h: 'var(--p-app-viewport-axis-axial)', v: 'var(--p-app-viewport-axis-sagittal)' }, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.ViewportAxisState.TOPLEFTMAIN]: { h: 'var(--p-app-viewport-axis-sagittal)', v: 'var(--p-app-viewport-axis-coronal)' } }; compactCrosshair(viewportId) { return this.isViewportMaximized(viewportId) || this.cprActive() && viewportId === _viewport_ids__WEBPACK_IMPORTED_MODULE_43__.VIEWPORT_IDS.REFORMAT; } viewportAxisColors(viewportId) { if (this.compactCrosshair(viewportId)) { return { h: MAXIMIZED_CROSSHAIR_COLOR, v: MAXIMIZED_CROSSHAIR_COLOR }; } return this.viewportColors[viewportId]; } viewportCrosshairRotation(viewportId) { return this.viewportStore.viewportCrosshairRotations[viewportId]; } viewportAngulation(viewportId) { return this.viewportStore.viewportAngulations[viewportId]; } viewportCameraState(viewportId) { return this.viewportStore.viewportCameras[viewportId]; } moveSCurveGraphToSidebar() { this.uiFacade.attachSCurveGraph(); this.uiFacade.openSidebarSection(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.SidebarSection.SCURVE); if (this.sCurveMaximized()) { this.toggleMaximizeViewport.emit(_tomoverse_enums__WEBPACK_IMPORTED_MODULE_19__.LayoutType.DEFAULT); } } ngOnDestroy() { this.destroyed = true; this.inFlightPhaseLoads.clear(); // Clean up interval if component is destroyed during resize if (this.resizeIntervalId !== undefined) { clearInterval(this.resizeIntervalId); this.resizeIntervalId = undefined; } // Clean up resize timeout if (this.resizeTimeoutId !== undefined) { clearTimeout(this.resizeTimeoutId); this.resizeTimeoutId = undefined; } if (this.revalidateTimeoutId !== undefined) { clearTimeout(this.revalidateTimeoutId); this.revalidateTimeoutId = undefined; } this.seriesCacheProgressSubscription?.unsubscribe(); this.seriesCacheProgressSubscription = undefined; // Cornerstone doesn't count volumes toward its own cache size/eviction, so nothing frees // this memory unless released explicitly. RenderingEngineService's own teardown also // purges Cornerstone's cache as a side effect, but that's a separate service on a sibling // injector scope - releasing our own volumes directly here doesn't depend on that. for (const volumeIds of this.phaseVolumeIds.values()) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); } this.phaseVolumeIds.clear(); // Safety net: releases anything discardStaleVolume deferred for an in-progress reset to // pick up, in case the component is destroyed before that reset's own cleanup runs. for (const volumeIds of this.pendingStaleVolumeDiscards) { (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.decacheVolumeIds)(volumeIds); } this.pendingStaleVolumeDiscards.length = 0; } openContextMenuSubscriber() { const subscriber = this.interaction.openContextMenu$.subscribe(key => { const [viewportId, keySuffix] = key.split(':'); if (keySuffix === 'angulationMenu' && viewportId) { this.annotationMenuItems.set(this.annotationMenuItemService.menuItemsForAngulationMenu(viewportId)); return; } if (key === 'viewport') { this.annotationMenuItems.set(this.annotationMenuItemService.menuItemsForViewport()); return; } const [annotationId, pointIndexString] = key.split(':'); if (!annotationId) return; const pointIndex = pointIndexString === undefined ? undefined : Number.parseInt(pointIndexString); const annotation = this.annotationFacade.getAnnotationById(annotationId); if (annotation) { this.annotationMenuItems.set(this.annotationMenuItemService.menuItemsForAnnotation(annotation, pointIndex)); } }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_3__.DestroyRef).onDestroy(() => { subscriber.unsubscribe(); }); } static ɵfac = function VolumeViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || VolumeViewerComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵdefineComponent"]({ type: VolumeViewerComponent, selectors: [["lib-volume-viewer"]], viewQuery: function VolumeViewerComponent_Query(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵviewQuerySignal"](ctx.ctxMenu, _c0, 5)(ctx.alignMenu, _c1, 5)(ctx.cprWorkspace, _cpr_cpr_workspace_component__WEBPACK_IMPORTED_MODULE_36__.CprWorkspaceComponent, 5); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵqueryAdvance"](3); } }, hostBindings: function VolumeViewerComponent_HostBindings(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵlistener"]("keydown.escape", function VolumeViewerComponent_keydown_escape_HostBindingHandler($event) { return ctx.handleKeyDown($event); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("keydown.enter", function VolumeViewerComponent_keydown_enter_HostBindingHandler($event) { return ctx.handleEnterKey($event); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("keydown.delete", function VolumeViewerComponent_keydown_delete_HostBindingHandler($event) { return ctx.handleDeleteKey($event); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("keydown.backspace", function VolumeViewerComponent_keydown_backspace_HostBindingHandler($event) { return ctx.handleDeleteKey($event); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"])("resize", function VolumeViewerComponent_resize_HostBindingHandler() { return ctx.onWindowResize(); }, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵresolveWindow"]); } }, inputs: { seriesUid: [1, "seriesUid"], studyUid: [1, "studyUid"], storeUid: [1, "storeUid"], otSeriesUid: [1, "otSeriesUid"], workSessionUid: [1, "workSessionUid"], selectedPhaseIds: [1, "selectedPhaseIds"], layoutConfig: [1, "layoutConfig"], viewportLayout: [1, "viewportLayout"], focusedMPRViewport: [1, "focusedMPRViewport"], selectedMPRViewport: [1, "selectedMPRViewport"], isInitialViewportLayout: [1, "isInitialViewportLayout"], lastSelectedMPRViewport: [1, "lastSelectedMPRViewport"], cameraSliderTemplate: [1, "cameraSliderTemplate"] }, outputs: { toggleMaximizeViewport: "toggleMaximizeViewport", focusedMPRViewportChange: "focusedMPRViewportChange", selectedMPRViewportChange: "selectedMPRViewportChange", escPressed: "escPressed" }, features: [_angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵProvidersFeature"]([_annotation_actors_annotation_actors_service__WEBPACK_IMPORTED_MODULE_34__.AnnotationActorsService, _viewport_interaction_viewport_interaction_service__WEBPACK_IMPORTED_MODULE_44__.ViewportInteractionService, _ct_popover_service__WEBPACK_IMPORTED_MODULE_38__.CtPopoverService, _volume_rendering_popover_service__WEBPACK_IMPORTED_MODULE_46__.VolumeRenderingPopoverService])], decls: 15, vars: 5, consts: [["volumeRenderTrigger", ""], ["volumeRenderMaximized", ""], ["ctPopoverSettings", ""], ["viewportPopoverSettings", ""], ["annotationCards", ""], ["viewportBase", ""], ["wrapper", ""], ["ctxMenu", ""], ["item", ""], ["alignMenu", ""], ["viewportAxial", ""], ["viewportSagittal", ""], ["viewportCoronal", ""], ["viewportReformat", ""], ["sCurveGraph", ""], ["cprWorkspace", ""], ["moreActionsMenu", ""], [1, "p-4", "text-center", "text-(--p-app-status-danger)"], ["data-viewer-bounds", "", 1, "h-full", "w-full", "bg-(--p-app-viewport-background)", 3, "cursor"], ["data-test-id", "volume-viewer-p-menu-hidden", 3, "pt"], ["data-viewer-bounds", "", 1, "h-full", "w-full", "bg-(--p-app-viewport-background)", 3, "mouseup", "mousemove", "blur"], [1, "relative", "h-full", "w-full", 3, "contextmenu"], [1, "pointer-events-auto", "absolute", "top-6", "left-6", "z-30"], [3, "viewportLayout", "focusedMPRViewport", "selectedMPRViewport", "isInitialViewportState", "lastSelectedMPRViewport", "isBlur", "loadingProgress", "showSCurveGraph"], [3, "onShow", "onHide", "appendTo", "model", "pt"], [3, "model"], [1, "absolute", "bottom-12", "left-1/2", "z-20", "-translate-x-1/2"], ["data-test-id", "volume-viewer-p-select-volume-selector", "optionLabel", "label", "optionValue", "value", "appendTo", "body", 3, "ngModelChange", "options", "ngModel", "disabled", "ariaLabel"], [3, "resizeStart", "resizeEnd", "loaderContextMenu", "viewportLayout", "focusedMPRViewport", "selectedMPRViewport", "isInitialViewportState", "lastSelectedMPRViewport", "isBlur", "loadingProgress", "showSCurveGraph"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], ["display", "inline-block", 1, "absolute", "bottom-0", "left-0", "z-10", "flex", "max-w-full", "flex-col", "gap-2", "py-2", "pr-2", "pl-6"], [1, "flex", "h-8", "items-center", "gap-1"], ["tooltipPosition", "top", "iconType", "prime", 3, "click", "tooltip", "ariaLabel", "icon"], ["icon", "window-minimize", "iconType", "prime", "tooltipPosition", "top", 3, "click", "tooltip", "ariaLabel"], [1, "flex", "h-full", "w-full", "items-center", "justify-center"], [1, "aspect-square", "h-full", "max-h-full", "max-w-full"], [3, "showDetachButton", "isMaximized"], [3, "resizeStart", "resizeEnd", "axialTemplate", "cameraSliderTemplate", "coronalTemplate", "reformatTemplate", "sagittalTemplate", "isBlur", "isInitialViewportState", "lastSelectedMPRViewport", "selectedMPRViewport"], [3, "item"], ["data-test-id", "volume-viewer-lib-settings-popover-orientation", 3, "visibilityChange", "closed", "showButton", "draggable", "dragBoundary", "externalOpen", "formFieldConfig", "title", "dragHandleAriaLabel"], [3, "visibilityChange", "closed", "showButton", "externalOpen", "formFieldConfig", "title"], ["tooltipPosition", "top", "iconType", "prime", "icon", "sliders-h", "iconClass", "text-lg", 3, "tooltip", "ariaLabel"], ["tooltipPosition", "top", "iconType", "prime", "icon", "sliders-h", "iconClass", "text-lg", 3, "click", "tooltip", "ariaLabel"], [3, "formFieldConfig", "buttonTooltip", "buttonAriaLabel", "title"], [3, "visibilityChange", "formFieldConfig", "buttonTooltip", "buttonAriaLabel", "title"], [3, "formFieldConfig", "draggable", "dragBoundary", "buttonTooltip", "buttonAriaLabel", "title", "dragHandleAriaLabel"], [3, "visibilityChange", "formFieldConfig", "draggable", "dragBoundary", "buttonTooltip", "buttonAriaLabel", "title", "dragHandleAriaLabel"], ["icon", "ellipsis-v", "tooltipPosition", "top", 3, "click", "tooltip", "ariaLabel"], [3, "pt", "multiple", "value"], [3, "valueChange", "pt", "multiple", "value"], ["selected", "", 3, "show", "hide", "goTo", "updateName", "annotation", "actions", "menuTrigger", "pt"], [3, "viewportReady", "viewportDestroyed", "perspectiveChange", "mouseDown", "mouseMove", "wheelScrolled", "gestureStarted", "gestureChanged", "gestureEnded", "contextMenu", "toggleMaximizeViewport", "focusedMPRViewportChange", "state", "darkMode", "annotationCardsTemplate", "settingsPopoverTemplate", "viewportSettingsPopoverTemplate", "includeViewportSwap", "maximized", "includeViewportMenu", "angulation", "createMode", "cursor", "isPosterior", "swapLabel", "minimizeLabel", "maximizeLabel"], [3, "viewportId", "viewportAxis", "cameraDetails", "crosshairColors", "crosshairRotation", "compact"], [1, "pointer-events-auto", "absolute", "right-4", "bottom-4", "z-50"], [1, "pointer-events-none", "absolute", "inset-0", "z-40", "flex", "items-center", "justify-center", "bg-(--p-app-viewport-background)/60"], [1, "pointer-events-auto", "absolute", "right-4", "bottom-4", "z-50", 3, "mousedown", "wheel"], [1, "border-surface-500", "h-8", "w-8", "animate-spin", "rounded-full", "border-4", "border-t-(--p-app-viewport-label)"]], template: function VolumeViewerComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditionalCreate"](0, VolumeViewerComponent_Conditional_0_Template, 3, 1, "div", 17)(1, VolumeViewerComponent_Conditional_1_Template, 12, 9, "section", 18); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplate"](2, VolumeViewerComponent_ng_template_2_Template, 1, 1, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(4, VolumeViewerComponent_ng_template_4_Template, 1, 1, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(6, VolumeViewerComponent_ng_template_6_Template, 1, 1, "ng-template", null, 2, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(8, VolumeViewerComponent_ng_template_8_Template, 3, 6, "ng-template", null, 3, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(10, VolumeViewerComponent_ng_template_10_Template, 4, 2, "ng-template", null, 4, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"])(12, VolumeViewerComponent_ng_template_12_Template, 9, 31, "ng-template", null, 5, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵtemplateRefExtractor"]); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵelement"](14, "p-menu", 19); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵconditional"](ctx.viewerOrchestrator.status() === "error" ? 0 : 1); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵadvance"](14); _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction1"](3, _c3, _angular_core__WEBPACK_IMPORTED_MODULE_48__["ɵɵpureFunction0"](2, _c2))); } }, dependencies: [primeng_accordion__WEBPACK_IMPORTED_MODULE_11__.Accordion, _annotation_card_annotation_card_component__WEBPACK_IMPORTED_MODULE_23__.AnnotationCardComponent, _annotation_menu_components_annotation_menu_component__WEBPACK_IMPORTED_MODULE_26__.AnnotationMenuComponent, _annotation_menu_components_annotation_menu_item_component__WEBPACK_IMPORTED_MODULE_25__.AnnotationMenuItemComponent, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_13__.ContextMenuModule, primeng_contextmenu__WEBPACK_IMPORTED_MODULE_13__.ContextMenu, _cpr_cpr_workspace_component__WEBPACK_IMPORTED_MODULE_36__.CprWorkspaceComponent, _endo_dev_panel_endo_dev_panel_component__WEBPACK_IMPORTED_MODULE_39__.EndoDevelopmentPanelComponent, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.FormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_6__.NgModel, primeng_menu__WEBPACK_IMPORTED_MODULE_15__.MenuModule, primeng_menu__WEBPACK_IMPORTED_MODULE_15__.Menu, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _render_quality_dev_panel_render_quality_dev_panel_component__WEBPACK_IMPORTED_MODULE_41__.RenderQualityDevelopmentPanelComponent, _s_curve_graph_s_curve_graph_component__WEBPACK_IMPORTED_MODULE_32__.SCurveGraphComponent, primeng_select__WEBPACK_IMPORTED_MODULE_16__.SelectModule, primeng_select__WEBPACK_IMPORTED_MODULE_16__.Select, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.SettingsPopoverComponent, _vascular_dev_panel_vascular_dev_panel_component__WEBPACK_IMPORTED_MODULE_42__.VascularDevelopmentPanelComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.ViewportButtonComponent, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.ViewportLayoutManagerComponent, _viewport_overlay_viewport_overlay_component__WEBPACK_IMPORTED_MODULE_45__.ViewportOverlay, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.VolumeViewportComponent, _angular_common__WEBPACK_IMPORTED_MODULE_1__.JsonPipe, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_10__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 48333 /*!********************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/vtk-poly-line-source.ts ***! \********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), /* harmony export */ extend: () => (/* binding */ extend), /* harmony export */ newInstance: () => (/* binding */ newInstance) /* harmony export */ }); /* harmony import */ var _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @kitware/vtk.js/Common/DataModel/PolyData */ 95765); /* harmony import */ var _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @kitware/vtk.js/macros */ 64946); /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/no-explicit-any */ function vtkPolyLineSource(publicAPI, model) { // Set our className model.classHierarchy.push('vtkPolyLineSource'); publicAPI.requestData = (inData, outData) => { const dataset = outData[0]; // Check input const pointDataType = dataset ? dataset.getPoints().getDataType() : model.pointType; const pd = dataset?.initialize() ?? _kitware_vtk_js_Common_DataModel_PolyData__WEBPACK_IMPORTED_MODULE_0__["default"].newInstance(); const modelPoints = model.points; const pointCount = modelPoints.length; const points = _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__["default"].newTypedArray(pointDataType, pointCount * 3); pd.getPoints().setData(points, 3); const lines = new Uint32Array(pointCount + 1); pd.getLines().setData(lines, 1); lines[0] = pointCount; for (const [index, point] of modelPoints.entries()) { points[index * 3] = point[0]; points[index * 3 + 1] = point[1]; points[index * 3 + 2] = point[2]; lines[index + 1] = index; } outData[0] = pd; }; } const DEFAULT_VALUES = { points: [], pointType: 'Float64Array' }; function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__["default"].obj(publicAPI, model); _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__["default"].setGet(publicAPI, model, ['points']); _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__["default"].algo(publicAPI, model, 0, 1); vtkPolyLineSource(publicAPI, model); } const newInstance = _kitware_vtk_js_macros__WEBPACK_IMPORTED_MODULE_1__["default"].newInstance(extend, 'vykPolyLineSource'); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ extend, newInstance }); /***/ }, /***/ 99360 /*!*************************************************************************************!*\ !*** ./libs/feature/src/lib/volume-viewer/window-details/window-details.service.ts ***! \*************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WindowDetailsService: () => (/* binding */ WindowDetailsService) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 87510); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! rxjs */ 57168); /** * A centralized service that listens for window resizes and exposes * Signals representing various properties. */ class WindowDetailsService { _devicePixelRatio = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(globalThis.devicePixelRatio, ...(ngDevMode ? [{ debugName: "_devicePixelRatio" }] : [])); devicePixelRatio = this._devicePixelRatio.asReadonly(); _screenHeight = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(globalThis.innerHeight, ...(ngDevMode ? [{ debugName: "_screenHeight" }] : [])); screenHeight = this._screenHeight.asReadonly(); _screenWidth = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.signal)(globalThis.innerWidth, ...(ngDevMode ? [{ debugName: "_screenWidth" }] : [])); screenWidth = this._screenWidth.asReadonly(); constructor() { const windowResize = (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.fromEvent)(globalThis, 'resize').pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_3__.debounceTime)(100), (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_1__.takeUntilDestroyed)()).subscribe(() => { this._screenWidth.set(window.innerWidth); this._screenHeight.set(window.innerHeight); this._devicePixelRatio.set(window.devicePixelRatio); }); (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_core__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(() => { windowResize.unsubscribe(); }); } static ɵfac = function WindowDetailsService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WindowDetailsService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: WindowDetailsService, factory: WindowDetailsService.ɵfac }); } /***/ }, /***/ 26914 /*!*******************************************************!*\ !*** ./libs/feature/src/lib/window/window.service.ts ***! \*******************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WindowService: () => (/* binding */ WindowService) /* harmony export */ }); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); class WindowService { document = (0,_angular_common__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_0__.DOCUMENT); isFullscreen = (0,_angular_common__WEBPACK_IMPORTED_MODULE_0__.signal)(Boolean(this.document.fullscreenElement), ...(ngDevMode ? [{ debugName: "isFullscreen" }] : [])); constructor() { const onFullscreenChange = () => { this.isFullscreen.set(Boolean(this.document.fullscreenElement)); }; this.document.addEventListener('fullscreenchange', onFullscreenChange); (0,_angular_common__WEBPACK_IMPORTED_MODULE_0__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_0__.DestroyRef).onDestroy(() => { this.document.removeEventListener('fullscreenchange', onFullscreenChange); }); } toggleFullscreen() { if (this.document.fullscreenElement) { this.document.exitFullscreen?.(); return; } this.document.documentElement.requestFullscreen?.(); } static ɵfac = function WindowService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WindowService)(); }; static ɵprov = /*@__PURE__*/_angular_common__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineInjectable"]({ token: WindowService, factory: WindowService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 76774 /*!*****************************************************************************!*\ !*** ./libs/feature/src/lib/work-session-nav/work-session-nav.component.ts ***! \*****************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionNavComponent: () => (/* binding */ WorkSessionNavComponent) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/common */ 32229); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/core */ 36973); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @angular/router */ 38709); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 90100); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 84356); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 69042); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! rxjs */ 84917); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! rxjs */ 9276); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! rxjs */ 45541); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_skeleton__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! primeng/skeleton */ 65528); /* harmony import */ var primeng_tabs__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! primeng/tabs */ 70021); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @tomoverse/ui */ 79048); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _pipes_modality_label_pipe__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../pipes/modality-label.pipe */ 18194); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @angular/core */ 14975); const _c0 = () => ({ root: "overflow-x-hidden" }); const _c1 = () => ({ transitionDuration: 0 }); const _c2 = () => ({ background: "transparent", borderWidth: 0 }); const _c3 = () => ({ background: "{amber.300}", color: "{surface.800}" }); const _c4 = a0 => ({ color: "{surface.200}", hoverColor: "{surface.200}", active: a0 }); const _c5 = a0 => ({ dark: a0 }); const _c6 = a0 => ({ padding: "0 0.5rem 0 1rem", fontWeight: 500, colorScheme: a0 }); const _c7 = (a0, a1, a2) => ({ root: a0, tablist: a1, tab: a2 }); const _c8 = () => ({ content: "overflow-x-auto no-scrollbar scroll-smooth flex-nowrap py-2", activeBar: "hidden" }); const _c9 = () => ({ root: "min-w-0 max-w-60 basis-60 border-none rounded-[var(--p-button-border-radius)]" }); const _c10 = (a0, a1, a2, a3) => ["/volume-viewer", a0, a1, a2, a3]; const _c11 = () => []; const _c12 = () => ({ background: "{app.surface.tab}" }); const _c13 = a0 => ({ root: a0 }); const _forTrack0 = ($index, $item) => $item.uid; function WorkSessionNavComponent_Conditional_1_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementContainer"](0); } } function WorkSessionNavComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](0, WorkSessionNavComponent_Conditional_1_ng_container_0_Template, 1, 0, "ng-container", 3); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); const skeleton_r1 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreference"](6); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("ngTemplateOutlet", skeleton_r1); } } function WorkSessionNavComponent_Conditional_2_ng_container_0_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementContainer"](0); } } function WorkSessionNavComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](0, WorkSessionNavComponent_Conditional_2_ng_container_0_Template, 1, 0, "ng-container", 3); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); const tabs_r2 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵreference"](4); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("ngTemplateOutlet", tabs_r2); } } function WorkSessionNavComponent_ng_template_3_For_4_Template(rf, ctx) { if (rf & 1) { const _r3 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "p-tab", 7)(1, "div", 8); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](2, "lib-work-session-tab", 9); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](3, "button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipe"](4, "translate"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵlistener"]("click", function WorkSessionNavComponent_ng_template_3_For_4_Template_button_click_3_listener($event) { const workSession_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵrestoreView"](_r3).$implicit; const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](2); return _angular_core__WEBPACK_IMPORTED_MODULE_3__["ɵɵresetView"](ctx_r4.closeTab(workSession_r4, $event)); }); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](5, "lib-icon", 11); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"]()()(); } if (rf & 2) { const workSession_r4 = ctx.$implicit; const ɵ$index_21_r6 = ctx.$index; const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](13, _c9))("routerLink", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction4"](14, _c10, workSession_r4.storeUid, workSession_r4.studyUid, workSession_r4.seriesUid, workSession_r4.uid))("value", workSession_r4.uid)("libScrollToActive", workSession_r4.uid === ctx_r4.displayedActiveUid()); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵattribute"]("data-test-id", "work-session-nav-p-tab-" + ɵ$index_21_r6); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("details", workSession_r4)("mutedTextPt", ctx_r4.cn(workSession_r4.uid === ctx_r4.displayedActiveUid() && "text-surface-600")); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵclassMap"](ctx_r4.cn(workSession_r4.uid === ctx_r4.displayedActiveUid() ? "text-surface-600 hover:bg-primary-200" : "text-muted-color hover:bg-surface-700 hover:text-surface-200")); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵattribute"]("data-test-id", "work-session-nav-button-close-" + ɵ$index_21_r6)("aria-label", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpipeBind1"](4, 11, "workSessionNav.closeTab")); } } function WorkSessionNavComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "p-tabs", 4)(1, "p-tablist", 5)(2, "div", 6); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵrepeaterCreate"](3, WorkSessionNavComponent_ng_template_3_For_4_Template, 6, 19, "p-tab", 7, _forTrack0); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"]()()(); } if (rf & 2) { const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("value", ctx_r4.displayedActiveUid())("showNavigators", false)("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](5, _c0))("dt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction3"](15, _c7, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](6, _c1), _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](7, _c2), _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction1"](13, _c6, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction1"](11, _c5, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction1"](9, _c4, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](8, _c3)))))); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("pt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](19, _c8)); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵrepeater"](ctx_r4.formattedSessions()); } } function WorkSessionNavComponent_ng_template_5_For_2_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelement"](0, "p-skeleton", 13); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵproperty"]("dt", _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction1"](2, _c13, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](1, _c12))); } } function WorkSessionNavComponent_ng_template_5_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "div", 12); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵrepeaterCreate"](1, WorkSessionNavComponent_ng_template_5_For_2_Template, 1, 4, "p-skeleton", 13, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵrepeaterTrackByIndex"]); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r4 = _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵrepeater"](_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵpureFunction0"](0, _c11).constructor(ctx_r4.sessionCount())); } } class WorkSessionNavComponent { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_23__.getLogger)(WorkSessionNavComponent.name); workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.WorkSessionDatabaseService); dicomDatabase = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.DicomDatabaseService); recentWorkSessions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_20__.RecentWorkSessionsService); router = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_6__.Router); modalityLabelPipe = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_pipes_modality_label_pipe__WEBPACK_IMPORTED_MODULE_24__.ModalityLabelPipe); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_17__.TranslateService); translationChanges$ = (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.merge)(this.translate.onLangChange, this.translate.onTranslationChange).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_14__.startWith)(undefined)); activeWorkSessionUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_2__.input)(undefined, ...(ngDevMode ? [{ debugName: "activeWorkSessionUid" }] : [])); sessionCount = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.computed)(() => this.recentWorkSessions.sessions().length, ...(ngDevMode ? [{ debugName: "sessionCount" }] : [])); isInitialLoading = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.signal)(true, ...(ngDevMode ? [{ debugName: "isInitialLoading" }] : [])); formattedSessions = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_5__.toObservable)(this.recentWorkSessions.sessions).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_15__.switchMap)(references => references.length === 0 ? (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.of)([]) : (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.combineLatest)(references.map(reference => this.sessionDetails$(reference)))), (0,rxjs__WEBPACK_IMPORTED_MODULE_16__.tap)(() => this.isInitialLoading.set(false)), (0,rxjs__WEBPACK_IMPORTED_MODULE_13__.map)(tabs => tabs.filter(details => !!details))), { initialValue: [] }); /** * The uid whose tab is shown as active. Usually the routed session, but while a * freshly opened session's tab has not rendered yet (its local document or series * metadata is still loading), the previously active tab keeps its active state so * the tab strip never shows a gap with no active tab. */ displayedActiveUid = (0,_angular_core__WEBPACK_IMPORTED_MODULE_4__.linkedSignal)({ ...(ngDevMode ? { debugName: "displayedActiveUid" } : {}), computation: ({ active, sessions }, previous) => { if (!active) return ''; if (sessions.some(session => session.uid === active)) return active; // Only hold the previous tab while it still exists. const held = previous?.value; return held && sessions.some(session => session.uid === held) ? held : ''; }, source: () => ({ active: this.activeWorkSessionUid(), sessions: this.formattedSessions() }) }); seriesMetadataCache = new Map(); seriesMetadata(reference) { const key = `${reference.storeUid}/${reference.studyUid}/${reference.seriesUid}`; let metadata = this.seriesMetadataCache.get(key); if (!metadata) { metadata = this.dicomDatabase.getSeriesCommonMetadata(reference.studyUid, reference.seriesUid, reference.storeUid).catch(error => { this.seriesMetadataCache.delete(key); this.log.error('Failed to load series metadata for a recent work session', error); }); this.seriesMetadataCache.set(key, metadata); } return metadata; } sessionDetails$(reference) { return (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.combineLatest)([this.workSessionDb.get$(reference.workSessionUid), (0,rxjs__WEBPACK_IMPORTED_MODULE_9__.from)(this.seriesMetadata(reference)), this.translationChanges$]).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_13__.map)(([session, metadata]) => { if (!session) return; const dateObject = new Date(session.createdAt); const missing = key => this.translate.instant(`workSessionNav.metadata.${key}`); return { ...session, date: dateObject.toLocaleDateString(), description: metadata?.studyDescription ?? missing('unknownStudy'), modality: metadata?.modality ? this.modalityLabelPipe.transform(metadata.modality) : missing('notAvailable'), modalityTag: metadata?.modality ?? '??', patient: { birthdate: metadata?.patientBirthDate ?? missing('unknown'), gender: metadata?.patientSex ?? 'U', mrn: metadata?.patientID ?? missing('notAvailable'), name: metadata?.patientName ?? missing('anonymous') }, time: dateObject.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) }; }), (0,rxjs__WEBPACK_IMPORTED_MODULE_12__.catchError)(error => { this.log.error('Failed to load a recent work session', error); return (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.of)(undefined); })); } closeTab(session, event) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { event.stopPropagation(); event.preventDefault(); if (session.uid === _this.activeWorkSessionUid()) { const navigated = yield _this.router.navigate(['/library']); if (!navigated) return; } _this.recentWorkSessions.remove(session.uid); })(); } cn = _tomoverse_utils__WEBPACK_IMPORTED_MODULE_22__.cn; static ɵfac = function WorkSessionNavComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionNavComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵdefineComponent"]({ type: WorkSessionNavComponent, selectors: [["lib-work-session-nav"]], inputs: { activeWorkSessionUid: [1, "activeWorkSessionUid"] }, decls: 7, vars: 1, consts: [["tabs", ""], ["skeleton", ""], [1, "flex", "w-full", "min-w-0"], [4, "ngTemplateOutlet"], [3, "value", "showNavigators", "pt", "dt"], [3, "pt"], [1, "flex", "gap-3"], [3, "pt", "routerLink", "value", "libScrollToActive"], [1, "flex", "w-full", "min-w-0", "items-center", "gap-2"], [1, "min-w-0", "flex-1", 3, "details", "mutedTextPt"], ["type", "button", 1, "flex", "size-6", "shrink-0", "cursor-pointer", "items-center", "justify-center", "rounded-md", "transition-colors", 3, "click"], ["icon", "times", 1, "text-xs"], [1, "flex", "gap-3", "py-2"], ["width", "15rem", "height", "2.8rem", "borderRadius", "var(--p-button-border-radius)", 3, "dt"]], template: function WorkSessionNavComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementStart"](0, "div", 2); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditionalCreate"](1, WorkSessionNavComponent_Conditional_1_Template, 1, 1, "ng-container")(2, WorkSessionNavComponent_Conditional_2_Template, 1, 1, "ng-container"); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplate"](3, WorkSessionNavComponent_ng_template_3_Template, 5, 20, "ng-template", null, 0, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"])(5, WorkSessionNavComponent_ng_template_5_Template, 3, 1, "ng-template", null, 1, _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵtemplateRefExtractor"]); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_25__["ɵɵconditional"](ctx.isInitialLoading() ? 1 : 2); } }, dependencies: [_angular_router__WEBPACK_IMPORTED_MODULE_7__.RouterLink, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.IconComponent, primeng_tabs__WEBPACK_IMPORTED_MODULE_19__.Tabs, primeng_tabs__WEBPACK_IMPORTED_MODULE_19__.TabList, primeng_tabs__WEBPACK_IMPORTED_MODULE_19__.Tab, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.WorkSessionTabComponent, primeng_skeleton__WEBPACK_IMPORTED_MODULE_18__.Skeleton, _angular_common__WEBPACK_IMPORTED_MODULE_1__.NgTemplateOutlet, _tomoverse_ui__WEBPACK_IMPORTED_MODULE_21__.ScrollToActiveDirective, _ngx_translate_core__WEBPACK_IMPORTED_MODULE_17__.TranslatePipe], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 2643 /*!**************************************************************************************************************!*\ !*** ./libs/feature/src/lib/work-session/create-work-session-dialog/create-work-session-dialog.component.ts ***! \**************************************************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ CreateWorkSessionDialogComponent: () => (/* binding */ CreateWorkSessionDialogComponent) /* harmony export */ }); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_forms__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/forms */ 74381); /* harmony import */ var primeng_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! primeng/button */ 94481); /* harmony import */ var primeng_checkbox__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/checkbox */ 10026); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var primeng_floatlabel__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/floatlabel */ 95717); /* harmony import */ var primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! primeng/inputtext */ 670); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @angular/core */ 14975); function CreateWorkSessionDialogComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "div", 9); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](2, "div"); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtextInterpolate"](ctx_r0.config.data == null ? null : ctx_r0.config.data.warning); } } function CreateWorkSessionDialogComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "small", 4); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtext"](1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtextInterpolate1"](" ", (ctx_r0.config.data == null ? null : ctx_r0.config.data.duplicateNameError) || "Analysis name already exists.", " "); } } function CreateWorkSessionDialogComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) { const _r2 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵgetCurrentView"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "p-button", 10); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵlistener"]("onClick", function CreateWorkSessionDialogComponent_Conditional_8_Template_p_button_onClick_0_listener() { _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵrestoreView"](_r2); const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); return _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵresetView"](ctx_r0.discard()); }); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); } if (rf & 2) { const ctx_r0 = _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵnextContext"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("label", ctx_r0.config.data == null ? null : ctx_r0.config.data.discardLabel); } } class CreateWorkSessionDialogComponent { ref = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DynamicDialogRef); config = (0,_angular_core__WEBPACK_IMPORTED_MODULE_0__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_4__.DynamicDialogConfig); form = new _angular_forms__WEBPACK_IMPORTED_MODULE_1__.FormGroup({ name: new _angular_forms__WEBPACK_IMPORTED_MODULE_1__.FormControl('', { nonNullable: true, validators: [_angular_forms__WEBPACK_IMPORTED_MODULE_1__.Validators.required, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.Validators.pattern(String.raw`.*\S.*`)] }) }); ngOnInit() { const existingNames = new Set(this.config.data?.existingNames); this.form.controls.name.addValidators(this.uniqueNameValidator(existingNames)); this.form.patchValue({ name: this.config.data?.name }); } submit() { if (!this.form.valid) return; this.ref.close({ name: this.form.controls.name.value.trim() }); } discard() { this.ref.close({ discard: true }); } close() { this.ref.close(); } uniqueNameValidator(existingNames) { return control => { const value = control.value.trim(); // eslint-disable-next-line unicorn/no-null -- Angular requires null for "no error" if (!value) return null; // eslint-disable-next-line unicorn/no-null return existingNames.has(value) ? { nameTaken: true } : null; }; } static ɵfac = function CreateWorkSessionDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CreateWorkSessionDialogComponent)(); }; static ɵcmp = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵdefineComponent"]({ type: CreateWorkSessionDialogComponent, selectors: [["lib-create-work-session-dialog"]], decls: 11, vars: 8, consts: [[1, "flex", "flex-col", "gap-5", "pt-2", 3, "ngSubmit", "formGroup"], ["variant", "on"], ["data-test-id", "create-work-session-dialog-input-name", "pInputText", "", "id", "work-session-name", "formControlName", "name", "fluid", "", "autofocus", ""], ["for", "work-session-name"], [1, "text-(--p-app-status-danger)"], [1, "flex", "justify-end", "gap-2"], ["data-test-id", "create-work-session-dialog-p-button-discard", "type", "button", "outlined", "", "severity", "danger", "size", "small", 1, "mr-auto", 3, "label"], ["data-test-id", "create-work-session-dialog-p-button-cancel", "type", "button", "outlined", "", "severity", "secondary", "size", "small", 3, "onClick", "label"], ["data-test-id", "create-work-session-dialog-p-button-submit", "type", "submit", "severity", "contrast", "size", "small", 3, "label", "disabled"], [1, "text-primary-500"], ["data-test-id", "create-work-session-dialog-p-button-discard", "type", "button", "outlined", "", "severity", "danger", "size", "small", 1, "mr-auto", 3, "onClick", "label"]], template: function CreateWorkSessionDialogComponent_Template(rf, ctx) { if (rf & 1) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](0, "form", 0); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵlistener"]("ngSubmit", function CreateWorkSessionDialogComponent_Template_form_ngSubmit_0_listener() { return ctx.submit(); }); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditionalCreate"](1, CreateWorkSessionDialogComponent_Conditional_1_Template, 3, 1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](2, "p-floatlabel", 1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](3, "input", 2); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](4, "label", 3); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtext"](5); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"]()(); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditionalCreate"](6, CreateWorkSessionDialogComponent_Conditional_6_Template, 2, 1, "small", 4); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](7, "div", 5); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditionalCreate"](8, CreateWorkSessionDialogComponent_Conditional_8_Template, 1, 1, "p-button", 6); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementStart"](9, "p-button", 7); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵlistener"]("onClick", function CreateWorkSessionDialogComponent_Template_p_button_onClick_9_listener() { return ctx.close(); }); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelement"](10, "p-button", 8); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵelementEnd"]()(); } if (rf & 2) { _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("formGroup", ctx.form); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditional"]((ctx.config.data == null ? null : ctx.config.data.warning) ? 1 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](4); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵtextInterpolate"]((ctx.config.data == null ? null : ctx.config.data.titleLabel) || "Analysis name"); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditional"](ctx.form.controls.name.touched && ctx.form.controls.name.hasError("nameTaken") ? 6 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](2); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵconditional"]((ctx.config.data == null ? null : ctx.config.data.discardLabel) ? 8 : -1); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("label", (ctx.config.data == null ? null : ctx.config.data.cancelLabel) || "Cancel"); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵadvance"](); _angular_core__WEBPACK_IMPORTED_MODULE_7__["ɵɵproperty"]("label", (ctx.config.data == null ? null : ctx.config.data.createLabel) || "Create")("disabled", ctx.form.invalid); } }, dependencies: [primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__.InputTextModule, primeng_inputtext__WEBPACK_IMPORTED_MODULE_6__.InputText, primeng_button__WEBPACK_IMPORTED_MODULE_2__.ButtonModule, primeng_button__WEBPACK_IMPORTED_MODULE_2__.Button, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.ReactiveFormsModule, _angular_forms__WEBPACK_IMPORTED_MODULE_1__["ɵNgNoValidate"], _angular_forms__WEBPACK_IMPORTED_MODULE_1__.DefaultValueAccessor, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.NgControlStatus, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.NgControlStatusGroup, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.FormGroupDirective, _angular_forms__WEBPACK_IMPORTED_MODULE_1__.FormControlName, primeng_floatlabel__WEBPACK_IMPORTED_MODULE_5__.FloatLabel, primeng_checkbox__WEBPACK_IMPORTED_MODULE_3__.CheckboxModule], encapsulation: 2, changeDetection: 0 }); } /***/ }, /***/ 35009 /*!**************************************************************************!*\ !*** ./libs/feature/src/lib/work-session/work-session-dialog.service.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionDialogService: () => (/* binding */ WorkSessionDialogService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! rxjs */ 56435); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! primeng/dynamicdialog */ 29496); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _create_work_session_dialog_create_work_session_dialog_component__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./create-work-session-dialog/create-work-session-dialog.component */ 2643); class WorkSessionDialogService { dialogService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_dynamicdialog__WEBPACK_IMPORTED_MODULE_5__.DialogService); confirmationService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_4__.ConfirmationService); workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_6__.WorkSessionDatabaseService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); confirmCloseOpenWorkSession(name) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const closeLabel = _this.translate.instant('workSession.alreadyOpen.accept'); const cancelLabel = _this.translate.instant('common.cancel'); return new Promise(resolve => { _this.confirmationService.confirm({ accept: () => resolve(true), acceptButtonProps: { label: closeLabel }, acceptLabel: closeLabel, defaultFocus: 'accept', header: _this.translate.instant('workSession.alreadyOpen.header'), icon: 'exclamation-triangle', message: _this.translate.instant('workSession.alreadyOpen.message', { name }), // Escape and the close icon reject too, so the promise always settles. reject: () => resolve(false), rejectButtonProps: { label: cancelLabel, outlined: true, severity: 'secondary' }, rejectLabel: cancelLabel }); }); })(); } unsavedWorkSessionDialog() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (dialogOverrides = {}) { return _this2.workSessionNameDialog({ createLabel: _this2.translate.instant('common.save'), discardLabel: _this2.translate.instant('workSession.unsaved.discard'), warning: _this2.translate.instant('workSession.unsaved.message'), ...dialogOverrides }, _this2.translate.instant('workSession.unsaved.header')); }).apply(this, arguments); } workSessionNameDialog() { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (dialogOverrides = {}, header) { const workSessions = yield _this3.workSessionDb.find(); const existingNames = workSessions.map(({ name }) => ({ name })); const newName = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_7__.generateUniqueName)(existingNames, 'name', _tomoverse_utils__WEBPACK_IMPORTED_MODULE_7__.ANALYSIS_BASE_NAME); const dialogReference = _this3.dialogService.open(_create_work_session_dialog_create_work_session_dialog_component__WEBPACK_IMPORTED_MODULE_8__.CreateWorkSessionDialogComponent, { closable: true, data: { cancelLabel: _this3.translate.instant('common.cancel'), createLabel: _this3.translate.instant('workSessionNav.createSession.accept'), duplicateNameError: _this3.translate.instant('workSession.import.nameExists'), existingNames: existingNames.map(({ name }) => name), name: newName, ...dialogOverrides }, header: header ?? _this3.translate.instant('workSessionNav.createSession.header'), width: '30rem' }); if (!dialogReference) return; return yield (0,rxjs__WEBPACK_IMPORTED_MODULE_2__.firstValueFrom)(dialogReference.onClose); }).apply(this, arguments); } static ɵfac = function WorkSessionDialogService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionDialogService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: WorkSessionDialogService, factory: WorkSessionDialogService.ɵfac }); } /***/ }, /***/ 50784 /*!**************************************************************************!*\ !*** ./libs/feature/src/lib/work-session/work-session-import.service.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionImportService: () => (/* binding */ WorkSessionImportService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! rxdb */ 64062); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @tomoverse/utils */ 49585); class WorkSessionImportService { workSessionDb = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_7__.WorkSessionDatabaseService); messageService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_4__.MessageService); translate = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_3__.TranslateService); document = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_1__.DOCUMENT); router = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_2__.Router); import() { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const importResult = yield _this.readAndValidateImportFile(); if (!importResult) return; const { _attachments, ...importedWorkSession } = importResult; const existingNames = yield _this.getExistingWorkSessionNames(importedWorkSession.studyUid, importedWorkSession.seriesUid, importedWorkSession.storeUid); yield (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this.saveImportedWorkSession({ ...importedWorkSession, name: _this.resolveUniqueName(importedWorkSession.name, existingNames) }, _attachments); })); _this.messageService.add({ severity: 'success', summary: _this.translate.instant('workSession.importSuccess') }); } catch (error) { _this.messageService.add({ detail: error.message, severity: 'error', sticky: true, summary: _this.translate.instant('workSession.importError') }); } })(); } readAndValidateImportFile() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const parsedJson = yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.importFromJsonFile)(_this2.document); if (!parsedJson) return; const { _attachments, ...workSession } = parsedJson; const normalizedWorkSession = _this2.normalizeWorkSession(workSession); const parseResult = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_6__.workSessionSchema.safeParse(normalizedWorkSession); if (!parseResult.success) { throw new Error(_this2.formatZodError(parseResult.error)); } return { ...parseResult.data, _attachments: _attachments ?? [] }; })(); } normalizeRenderSettings(renderSettings) { const existing = renderSettings && typeof renderSettings === 'object' ? renderSettings : {}; return { sCurveGraphFontSize: _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_S_CURVE_GRAPH_FONT_SIZE, sCurveLineWidth: _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_8__.DEFAULT_S_CURVE_LINE_WIDTH, ...existing }; } normalizeWorkSession(workSession) { const volumes = workSession['volumes']; if (!Array.isArray(volumes)) return workSession; return { ...workSession, renderSettings: this.normalizeRenderSettings(workSession['renderSettings']), volumes: volumes.map(volume => { const { renderSettings, sCurves, ...rest } = volume; return { chambers: [], sCurveRelativeMeasurements: [], ...rest, renderSettings: this.normalizeRenderSettings(renderSettings), sCurves: Array.isArray(sCurves) ? sCurves : [] }; }) }; } formatZodError(error) { return error.issues.map(issue => { const path = issue.path.map(p => typeof p === 'number' ? `[${p}]` : p).join('.').replaceAll('.[', '['); return `- ${issue.message} -> ${path || 'root'}`; }).join('\n'); } getExistingWorkSessionNames(studyUid, seriesUid, storeUid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessions = yield _this3.workSessionDb.find({ seriesUid, storeUid, studyUid }); return new Set(workSessions.map(session => session.name.trim())); })(); } resolveUniqueName(importedName, existingNames) { const name = importedName.trim(); if (name && !existingNames.has(name)) return name; const existingItems = [...existingNames].map(existing => ({ name: existing })); return (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.generateUniqueName)(existingItems, 'name', name || _tomoverse_utils__WEBPACK_IMPORTED_MODULE_9__.ANALYSIS_BASE_NAME); } saveImportedWorkSession(_x) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (data, attachments = []) { data['uid'] = crypto.randomUUID(); // Must run before the first write, or the new session reaches the backend. yield _this4.workSessionDb.markDraft(data.uid); yield _this4.workSessionDb.save(data, { attachments: yield Promise.all(attachments.map(/*#__PURE__*/function () { var _ref2 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (attachment) { return { ...attachment, data: yield (0,rxdb__WEBPACK_IMPORTED_MODULE_5__.createBlobFromBase64)(attachment.data, attachment.type) }; }); return function (_x2) { return _ref2.apply(this, arguments); }; }())) }); yield _this4.router.navigate(['/volume-viewer', data.storeUid, data.studyUid, data.seriesUid, data.uid]); }).apply(this, arguments); } } /***/ }, /***/ 5497 /*!**************************************************************************!*\ !*** ./libs/feature/src/lib/work-session/work-session-switch.service.ts ***! \**************************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionSwitchService: () => (/* binding */ WorkSessionSwitchService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _work_session_dialog_service__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./work-session-dialog.service */ 35009); const hasFormValue = value => Array.isArray(value) ? value.length > 0 : value !== undefined && value !== ''; const bundleHasWork = bundle => { if (bundle.annotations.length > 0) return true; if (bundle.chambers.length > 0) return true; if (bundle.sCurves.length > 0) return true; if (bundle.sCurveRelativeMeasurements.length > 0) return true; return bundle.protocolData.instances.some(instance => Object.values(instance.formValues ?? {}).some(value => hasFormValue(value))); }; class WorkSessionSwitchService { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_6__.getLogger)(WorkSessionSwitchService.name); workSessionDb = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__.WorkSessionDatabaseService); workSessionDialog = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_7__.WorkSessionDialogService); workSessionNavService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__.WorkSessionNavigationService); recentWorkSessions = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_5__.RecentWorkSessionsService); messageService = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_3__.MessageService); translate = (0,_angular_core__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_2__.TranslateService); // An analysis is open while its tab is, so this runs on arrival rather than on exit. confirmOpen(targetWorkSessionUid) { var _this = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const open = _this.recentWorkSessions.sessions().filter(({ workSessionUid }) => workSessionUid !== targetWorkSessionUid); for (const { workSessionUid } of open) { if (!(yield _this.closeWorkSession(workSessionUid))) return false; } return true; })(); } closeWorkSession(uid) { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // The viewer flushes its edits on the way out, so the stored document is current. const session = yield _this2.workSessionDb.get(uid); if (!session) { _this2.recentWorkSessions.remove(uid); return true; } if (!(yield _this2.workSessionDb.isDraft(uid))) { if (!(yield _this2.workSessionDialog.confirmCloseOpenWorkSession(session.name))) return false; _this2.recentWorkSessions.remove(uid); return true; } if (!session.volumes.some(bundle => bundleHasWork(bundle))) { _this2.discardDraft(uid); return true; } return _this2.confirmUnsavedDraft(session); })(); } confirmUnsavedDraft(session) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessions = yield _this3.workSessionDb.find(); const result = yield _this3.workSessionDialog.unsavedWorkSessionDialog({ existingNames: workSessions.filter(({ uid }) => uid !== session.uid).map(({ name }) => name), name: session.name, warning: _this3.translate.instant('workSession.unsaved.switchMessage') }); if (!result) return false; if (result.discard) { _this3.discardDraft(session.uid); return true; } if (!result.name) return false; yield _this3.saveDraft(session, result.name); _this3.recentWorkSessions.remove(session.uid); _this3.messageService.add({ severity: 'success', summary: _this3.translate.instant('workSession.saveSuccess') }); return true; })(); } saveDraft(session, name) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this4.workSessionDb.clearDraft(session.uid); yield _this4.workSessionDb.save(_tomoverse_contracts__WEBPACK_IMPORTED_MODULE_4__.workSessionSchema.parse({ ...session, name }), { incrementVersion: true }); yield _this4.workSessionNavService.awaitPendingSync(); })(); } discardDraft(uid) { this.recentWorkSessions.remove(uid); // Best-effort: RxDB cleanup must not keep the route guard pending. this.workSessionDb.delete(uid).catch(error => { this.log.warn('Failed to discard draft work session', error); }); } static ɵfac = function WorkSessionSwitchService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionSwitchService)(); }; static ɵprov = /*@__PURE__*/_angular_core__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: WorkSessionSwitchService, factory: WorkSessionSwitchService.ɵfac, providedIn: 'root' }); } /***/ }, /***/ 82757 /*!*******************************************************************!*\ !*** ./libs/feature/src/lib/work-session/work-session.service.ts ***! \*******************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ WorkSessionService: () => (/* binding */ WorkSessionService) /* harmony export */ }); /* harmony import */ var _Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@angular-builders/custom-webpack/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 74349); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @angular/core */ 40072); /* harmony import */ var _angular_common__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @angular/common */ 25180); /* harmony import */ var _angular_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @angular/core */ 39231); /* harmony import */ var _angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @angular/core/rxjs-interop */ 24787); /* harmony import */ var _angular_router__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @angular/router */ 1286); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! rxjs */ 98241); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! rxjs */ 57168); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! rxjs */ 8102); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! rxjs */ 12045); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! rxjs */ 59380); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! rxjs */ 38442); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! rxjs */ 9588); /* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! rxjs */ 86110); /* harmony import */ var _ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @ngx-translate/core */ 96110); /* harmony import */ var gl_matrix__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! gl-matrix */ 23988); /* harmony import */ var primeng_api__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! primeng/api */ 62751); /* harmony import */ var rxdb__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! rxdb */ 99984); /* harmony import */ var _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @tomoverse/contracts */ 19875); /* harmony import */ var _tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @tomoverse/data-access */ 42541); /* harmony import */ var _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @tomoverse/dtos */ 55492); /* harmony import */ var _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @tomoverse/enums */ 66556); /* harmony import */ var _tomoverse_store__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @tomoverse/store */ 15585); /* harmony import */ var _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @tomoverse/utils */ 49585); /* harmony import */ var _logging_utils__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ../logging/utils */ 14337); /* harmony import */ var _protocols__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ../protocols */ 61632); /* harmony import */ var _work_session_dialog_service__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! ./work-session-dialog.service */ 35009); const SAVE_SUCCESS_KEY = 'workSession.saveSuccess'; class WorkSessionService { log = (0,_logging_utils__WEBPACK_IMPORTED_MODULE_24__.getLogger)(WorkSessionService.name); document = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_1__.DOCUMENT); workSessionDb = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.WorkSessionDatabaseService); workSessionApi = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.WorkSessionApiService); authService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.AuthService); annotationFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.AnnotationFacade); chamberFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.ChamberFacade); sCurveFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.SCurveFacade); renderSettingsStore = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.renderSettingsStore); viewportStore = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.viewportStore); volumeViewerStore = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.volumeViewerStore); protocolFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.ProtocolFacade); router = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_router__WEBPACK_IMPORTED_MODULE_5__.Router); messageService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(primeng_api__WEBPACK_IMPORTED_MODULE_16__.MessageService); translate = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_ngx_translate_core__WEBPACK_IMPORTED_MODULE_14__.TranslateService); workSessionNavService = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_data_access__WEBPACK_IMPORTED_MODULE_19__.WorkSessionNavigationService); workSessionDialog = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_work_session_dialog_service__WEBPACK_IMPORTED_MODULE_26__.WorkSessionDialogService); injector = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_1__.Injector); location = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_angular_common__WEBPACK_IMPORTED_MODULE_2__.Location); geometryFacade = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.inject)(_tomoverse_store__WEBPACK_IMPORTED_MODULE_22__.Object3DGeometryFacade); activeUid = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined, ...(ngDevMode ? [{ debugName: "activeUid" }] : [])); setupEffects = []; unregisterFlushHandler; // Per-phase annotation bundles; the live annotation store mirrors the active one. volumes = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)([], ...(ngDevMode ? [{ debugName: "volumes" }] : [])); // Active phase shows live edits; the others show their held bundle. annotationGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const seriesUid = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.workSessionDbSnapshot())?.seriesUid; if (!seriesUid) return []; const phases = this.volumeViewerStore.seriesPhasesState(seriesUid); const activePhaseId = this.volumeViewerStore.phaseSelectionState(seriesUid)?.activePhaseId; const liveAnnotations = this.annotationFacade.annotations(); const order = new Map(phases.map((phase, index) => [phase.id, index])); return this.volumes().map(bundle => { const phase = phases.find(candidate => candidate.id === bundle.phaseId); return { annotations: bundle.phaseId === activePhaseId ? liveAnnotations : bundle.annotations, identification: phase?.identification, isActive: bundle.phaseId === activePhaseId, label: phase?.label ?? bundle.phaseId, phaseId: bundle.phaseId }; }).toSorted((a, b) => (order.get(a.phaseId) ?? 0) - (order.get(b.phaseId) ?? 0)); }, ...(ngDevMode ? [{ debugName: "annotationGroups" }] : [])); chamberGroups = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { const seriesUid = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.workSessionDbSnapshot())?.seriesUid; if (!seriesUid) return []; const phases = this.volumeViewerStore.seriesPhasesState(seriesUid); const activePhaseId = this.volumeViewerStore.phaseSelectionState(seriesUid)?.activePhaseId; const liveChambers = this.chamberFacade.chambers(); const order = new Map(phases.map((phase, index) => [phase.id, index])); return this.volumes().map(bundle => { const phase = phases.find(candidate => candidate.id === bundle.phaseId); return { chambers: bundle.phaseId === activePhaseId ? liveChambers : bundle.chambers, identification: phase?.identification, isActive: bundle.phaseId === activePhaseId, label: phase?.label ?? bundle.phaseId, phaseId: bundle.phaseId }; }).toSorted((a, b) => (order.get(a.phaseId) ?? 0) - (order.get(b.phaseId) ?? 0)); }, ...(ngDevMode ? [{ debugName: "chamberGroups" }] : [])); _workSessionLoaded = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "_workSessionLoaded" }] : [])); get workSessionLoaded() { return this._workSessionLoaded; } // Draft = never saved by the user; stays off the backend until the first save. _isDraft = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)(false, ...(ngDevMode ? [{ debugName: "_isDraft" }] : [])); get isDraftSession() { return this._isDraft; } annotations = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.annotationFacade.annotations(), ...(ngDevMode ? [{ debugName: "annotations" }] : [])); protocols = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.protocolFacade.exportState(), ...(ngDevMode ? [{ debugName: "protocols" }] : [])); currentName = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => this.workSessionDbSnapshot()?.name ?? '', ...(ngDevMode ? [{ debugName: "currentName" }] : [])); resetWorkSessionLoaded() { this._workSessionLoaded.set(false); } addAttachment(creator) { const uid = this.activeUid(); if (!uid) { this.log.warn('Missing workSessionUid, attachment not created!'); return; } return this.workSessionDb.addAttachment(uid, creator); } setup(workSessionUid, studyUid, seriesUid, newWorkSessionName, storeUid = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined), newWorkSessionUid = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.signal)(undefined)) { var _this = this; this.destroySetupEffects(); this.workSessionNavService.saveWorkSessionRequested.set(0); this.workSessionNavService.exportWorkSessionRequested.set(0); this.unregisterFlushHandler = this.workSessionNavService.registerFlushHandler(() => this.persistCurrentUiState({})); // Tracks which session uid has already been imported into the stores so // that DB snapshot emissions caused by our own debounced saves don't // overwrite live store state (e.g. crosshair intersection) the user has // moved since the save was queued. let lastLoadedUid; this.setupEffects.push((0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(() => this.activeUid.set(workSessionUid())), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessionData = _this.debouncedWorkSession(); if (!workSessionData) return; const attachments = yield _this.syncStlAttachments(workSessionData.uid, workSessionData.volumes.flatMap(({ annotations }) => annotations)); yield _this.workSessionDb.save(workSessionData, { attachments, incrementVersion: true }); })), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessionData = _this.workSessionDbSnapshot(); if (!workSessionData) return; if (workSessionData.uid === lastLoadedUid) return; lastLoadedUid = workSessionData.uid; _this._isDraft.set(yield _this.workSessionDb.isDraft(workSessionData.uid)); yield _this.loadWorkSessionFromDb(workSessionData); _this._workSessionLoaded.set(true); })), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const uid = workSessionUid(); if (uid === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.WORK_SESSION_NEW_KEY) { const store = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => storeUid()); if (!store) { _this.log.warn('Cannot create a work session, the storeUid route param is missing.'); return; } // Reset so importOtAnnotations (gated on workSessionLoaded) always waits // for the new session's loadWorkSessionFromDb, not a prior session's state. _this._workSessionLoaded.set(false); try { yield _this.createAndNavigate(studyUid(), seriesUid(), store, (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => newWorkSessionName()), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => newWorkSessionUid())); } catch (error) { // Without this, a failure here (schema mismatch, a slow/interrupted // load, etc.) leaves _workSessionLoaded stuck false forever - nothing // else ever flips it back, since that only happens once a session is // actually saved and re-read. Everything gated on it (camera/viewport // init included) would then hang indefinitely instead of recovering. _this.log.error('There was an error creating the work session', error); yield _this.router.navigate(['/volume-viewer']); } } })), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!_this.workSessionNavService.saveWorkSessionRequested()) return; yield (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this.saveWorkSession()); })), (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.effect)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!_this.workSessionNavService.exportWorkSessionRequested()) return; yield (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this.handleAction(() => _this.exportWorkSession(), undefined, 'workSession.exportError'); })); }))); } ngOnDestroy() { this.destroySetupEffects(); } workSessionDbSnapshot = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toObservable)(this.activeUid).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_13__.switchMap)(uid => { if (!uid || uid === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.WORK_SESSION_NEW_KEY) return (0,rxjs__WEBPACK_IMPORTED_MODULE_6__.of)(undefined); return this.workSessionDb.get$(uid); }), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.distinctUntilChanged)((a, b) => { if (a === undefined) return b === undefined; const { updatedAt, ...restA } = a; if (b === undefined) return a === undefined; const { updatedAt: _, ...restB } = b; return (0,rxdb__WEBPACK_IMPORTED_MODULE_17__.deepEqual)(restA, restB); })), { initialValue: undefined }); currentUIWorkSession = (0,_angular_core__WEBPACK_IMPORTED_MODULE_3__.computed)(() => { // No live capture until hydration completes: the stores are half-restored while a // session loads, and an autosave then would persist them over the saved bundles. if (!this._workSessionLoaded()) return; const workSessionSnapshot = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.workSessionDbSnapshot()); const protocolDefinitions = this.protocolFacade.exportState().definitions; const annotationSize = this.annotationFacade.annotationSize(); if (!workSessionSnapshot || workSessionSnapshot.uid === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.WORK_SESSION_NEW_KEY) { // Track the live stores so this recomputes once the session is saved; result is discarded. this.exportActiveBundle('default:0'); return; } const phaseSelection = this.volumeViewerStore.phaseSelectionState(workSessionSnapshot.seriesUid); const activePhaseId = phaseSelection?.activePhaseId ?? this.volumes()[0]?.phaseId ?? 'default:0'; const liveBundle = this.exportActiveBundle(activePhaseId); const held = this.volumes(); const volumes = held.some(({ phaseId }) => phaseId === activePhaseId) ? held.map(bundle => bundle.phaseId === activePhaseId ? liveBundle : bundle) : [...held, liveBundle]; const usedProtocols = new Set(volumes.flatMap(({ protocolData }) => protocolData.instances.map(({ protocolId }) => protocolId))); // Only store default definitions if they have been used const usedDefinitions = protocolDefinitions.filter(definition => { if (_protocols__WEBPACK_IMPORTED_MODULE_25__.DEFAULT_PROTOCOLS.some(({ id }) => id === definition.id)) { return usedProtocols.has(definition.id); } return true; }); return { annotationSize, phaseSelection, protocolDefinitions: usedDefinitions, uid: workSessionSnapshot.uid, volumes }; }, ...(ngDevMode ? [{ debugName: "currentUIWorkSession" }] : [])); exportActiveBundle(phaseId) { const renderSettings = this.renderSettingsStore.export(); const viewportCamera = this.viewportStore.export(); const { activeProtocolId, instances } = this.protocolFacade.exportState(); return { annotations: this.annotationFacade.annotations().map((annotation, index) => ({ ...annotation, displayOrder: index + 1 })), chambers: this.chamberFacade.chambers(), phaseId, protocolData: { activeProtocolId, instances }, renderSettings: { ...renderSettings }, sCurveRelativeMeasurements: this.sCurveFacade.relativeMeasurements(), sCurves: this.sCurveFacade.exportSCurves(), viewportCamera: { ...viewportCamera, intersection: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.vec3ToPosition)(viewportCamera.intersection), isocenter: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.vec3ToPosition)(viewportCamera.isocenter), matrix: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.mat3ToArray)(viewportCamera.matrix), volumeCenter: viewportCamera.volumeCenter ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.vec3ToPosition)(viewportCamera.volumeCenter) : undefined } }; } debouncedWorkSession = (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toSignal)((0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toObservable)(this.currentUIWorkSession).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_9__.distinctUntilKeyChanged)('uid'), (0,rxjs__WEBPACK_IMPORTED_MODULE_12__.skipWhile)(workSession => workSession.uid === _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.WORK_SESSION_NEW_KEY), (0,rxjs__WEBPACK_IMPORTED_MODULE_13__.switchMap)(initialSession => (0,_angular_core_rxjs_interop__WEBPACK_IMPORTED_MODULE_4__.toObservable)(this.currentUIWorkSession, { injector: this.injector }).pipe((0,rxjs__WEBPACK_IMPORTED_MODULE_10__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.filter)(workSession => workSession.uid === initialSession.uid), (0,rxjs__WEBPACK_IMPORTED_MODULE_7__.debounceTime)(500), (0,rxjs__WEBPACK_IMPORTED_MODULE_11__.map)(uiWorkSession => { const databaseSnapshot = this.workSessionDbSnapshot(); try { return _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.workSessionSchema.parse({ ...databaseSnapshot, annotationSize: uiWorkSession.annotationSize, phaseSelection: uiWorkSession.phaseSelection, protocolDefinitions: uiWorkSession.protocolDefinitions, schemaVersion: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.WORK_SESSION_LATEST_SCHEMA, volumes: uiWorkSession.volumes }); } catch (error) { this.log.warn('parsing workSession failed', { databaseSnapshot, uiWorkSession }); throw error; } }), (0,rxjs__WEBPACK_IMPORTED_MODULE_10__.filter)(Boolean), (0,rxjs__WEBPACK_IMPORTED_MODULE_8__.distinctUntilChanged)((previous, current) => previous.annotationSize === current.annotationSize && (0,rxdb__WEBPACK_IMPORTED_MODULE_17__.deepEqual)(previous.phaseSelection, current.phaseSelection) && (0,rxdb__WEBPACK_IMPORTED_MODULE_17__.deepEqual)(previous.protocolDefinitions, current.protocolDefinitions) && (0,rxdb__WEBPACK_IMPORTED_MODULE_17__.deepEqual)(previous.volumes, current.volumes))))), { initialValue: undefined }); saveWorkSession() { var _this2 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessionData = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this2.currentUIWorkSession()); const workSessionSnapshotData = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this2.workSessionDbSnapshot()); if (!workSessionData || !workSessionSnapshotData) { _this2.messageService.add({ severity: 'info', summary: _this2.translate.instant('workSession.nothingToSave') }); return; } // The direct API save below assumes the backend already knows the session. if (yield _this2.workSessionDb.isDraft(workSessionData.uid)) { yield _this2.saveDraft(workSessionData.uid); return; } const attachments = yield _this2.workSessionDb.getAttachments(workSessionData.uid); // Fetch the current remote version to determine which attachments are stored remotely. // For those ones, we don't need to pass the full attachment data, just the digest const currentRemote = yield _this2.workSessionApi.get(workSessionData.uid); const remoteAttachmentIds = new Set(Object.keys(currentRemote._attachments ?? {})); const _attachments = Object.fromEntries(yield Promise.all(attachments?.map(/*#__PURE__*/function () { var _ref7 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (attachment) { const attachmentRecord = { digest: attachment.digest, length: attachment.length, type: attachment.type }; if (!remoteAttachmentIds.has(attachment.id)) { attachmentRecord.data = yield attachment.getDataBase64(); } return [attachment.id, attachmentRecord]; }); return function (_x) { return _ref7.apply(this, arguments); }; }()) ?? [])); yield _this2.handleAction(/*#__PURE__*/(0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this2.workSessionApi.update(workSessionData.uid, _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.workSessionSchemaWithAttachments.parse({ ...workSessionSnapshotData, ...workSessionData, _attachments })); }), SAVE_SUCCESS_KEY, 'workSession.saveError'); })(); } saveDraft(uid) { var _this3 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const name = yield _this3.promptDraftName(uid); if (!name) return; yield _this3.finalizeDraft(uid, name); _this3.messageService.add({ severity: 'success', summary: _this3.translate.instant(SAVE_SUCCESS_KEY) }); })(); } promptDraftName(uid) { var _this4 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSessions = yield _this4.workSessionDb.find(); const currentName = workSessions.find(session => session.uid === uid)?.name; const result = yield _this4.workSessionDialog.workSessionNameDialog({ createLabel: _this4.translate.instant('common.save'), existingNames: workSessions.filter(session => session.uid !== uid).map(({ name }) => name), ...(currentName ? { name: currentName } : {}) }, _this4.translate.instant('workSession.saveDialog.header')); return result?.name; })(); } finalizeDraft(uid, name) { var _this5 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { yield _this5.workSessionDb.clearDraft(uid); yield _this5.persistCurrentUiState({ name }); _this5._isDraft.set(false); })(); } // Saves right away; the autosave lags by 500 ms and dies when the page closes. persistCurrentUiState(overrides) { var _this6 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const snapshot = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this6.workSessionDbSnapshot()); if (!snapshot) return; const uiWorkSession = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this6.currentUIWorkSession()); const workSessionData = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.workSessionSchema.parse({ ...snapshot, ...(uiWorkSession ? { annotationSize: uiWorkSession.annotationSize, phaseSelection: uiWorkSession.phaseSelection, protocolDefinitions: uiWorkSession.protocolDefinitions, volumes: uiWorkSession.volumes } : {}), schemaVersion: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.WORK_SESSION_LATEST_SCHEMA, ...overrides }); const attachments = yield _this6.syncStlAttachments(workSessionData.uid, workSessionData.volumes.flatMap(({ annotations }) => annotations)); yield _this6.workSessionDb.save(workSessionData, { attachments, incrementVersion: true }); })(); } // Keeps the stored document current for whoever closes this analysis later. flushOnExit() { var _this7 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { // After sign-out the flush would never resolve and would block the exit. if (!(0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this7.authService.isAuthenticated())) return; if (!(0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this7.workSessionDbSnapshot())) return; yield _this7.workSessionNavService.flushPendingChanges(); })(); } // Closing the app takes the tab with it, so unsaved work is settled here. confirmAppClose() { var _this8 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!(0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this8.authService.isAuthenticated())) return true; const snapshot = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => _this8.workSessionDbSnapshot()); if (!snapshot) return true; const { name, uid } = snapshot; // A flush after the draft flow would write a discarded draft straight back. if (yield _this8.workSessionDb.isDraft(uid)) return _this8.confirmDraftExit({ name, uid }); yield _this8.workSessionNavService.flushPendingChanges(); return true; })(); } confirmDraftExit(draft) { var _this9 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { if (!_this9.hasUnsavedWork()) { // Empty drafts are deleted without asking. _this9.discardDraft(draft.uid); return true; } const workSessions = yield _this9.workSessionDb.find(); const result = yield _this9.workSessionDialog.unsavedWorkSessionDialog({ existingNames: workSessions.filter(session => session.uid !== draft.uid).map(({ name }) => name), name: draft.name }); if (!result) return false; if (result.discard) { _this9.discardDraft(draft.uid); return true; } if (!result.name) return false; yield _this9.finalizeDraft(draft.uid, result.name); yield _this9.workSessionNavService.awaitPendingSync(); _this9.messageService.add({ severity: 'success', summary: _this9.translate.instant(SAVE_SUCCESS_KEY) }); return true; })(); } // Camera/render tweaks don't count. hasUnsavedWork() { return (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => { const held = this.volumes(); if (this.annotationFacade.annotations().length > 0) return true; if (held.some(bundle => bundle.annotations.length > 0)) return true; if (this.chamberFacade.chambers().length > 0) return true; if (held.some(bundle => bundle.chambers.length > 0)) return true; if (this.sCurveFacade.sCurves().length > 0) return true; if (held.some(bundle => bundle.sCurves.length > 0)) return true; if (this.sCurveFacade.relativeMeasurements().length > 0) return true; if (held.some(bundle => bundle.sCurveRelativeMeasurements.length > 0)) return true; const formValueSets = [...this.protocolFacade.exportState().instances.map(({ formValues }) => formValues), ...held.flatMap(bundle => bundle.protocolData.instances.map(({ formValues }) => formValues))]; return formValueSets.some(formValues => Object.values(formValues ?? {}).some(value => Array.isArray(value) ? value.length > 0 : value !== undefined && value !== '')); }); } // Keep the marker: it also stops the deletion reaching the backend. Deletion is best-effort // because RxDB cleanup must not keep the route guard pending after the user chose Discard. discardDraft(uid) { this._isDraft.set(false); this.workSessionDb.delete(uid).catch(error => { this.log.warn('Failed to discard draft work session', error); }); } createAndNavigate(studyUid, seriesUid, storeUid, newName, uid) { var _this0 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const userId = _this0.authService.currentUser()?.accountId; if (!userId) { // Must throw, not return - the caller's catch block is what recovers // `_workSessionLoaded` from the `false` it's set to right before this call. throw new Error('Cannot create a work session: no signed-in user.'); } const workSessions = yield _this0.workSessionDb.find(); const now = new Date().toISOString(); const existingNames = workSessions.map(({ name }) => ({ name })); const generatedName = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.generateUniqueName)(existingNames, 'name', _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.ANALYSIS_BASE_NAME); const name = newName ?? generatedName; // Preserve query params (e.g. otSeriesUid) across the redirect from the temporary "new" session id; // key the starting bundle to the first selected phase (?phases=), the viewer's initial active volume. const queryString = _this0.router.url.split('?')[1] ?? ''; const initialPhaseId = new URLSearchParams(queryString).get('phases')?.split(',')[0] ?? 'default:0'; const renderSettings = { forceLowQuality: false, sCurveGraphFontSize: _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_20__.DEFAULT_S_CURVE_GRAPH_FONT_SIZE, sCurveLineWidth: _tomoverse_dtos__WEBPACK_IMPORTED_MODULE_20__.DEFAULT_S_CURVE_LINE_WIDTH, selectedVolumePresetName: 'CT-Cardiac3', selectedWindowPresetName: 'Default 1', volumeRenderPresets: [], // Will be populated on first load windowPresets: [] // Will be populated on first load }; const viewportCamera = { ax: 0, cameraDistance: -10, intersection: [0, 0, 0], isocenter: [0, 0, 0], isPosterior: false, matrix: _tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.INIT_CAMERA_MATRIX, showCrosshairs: true, viewportAxisMapping: { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATEBOTTOMLEFT]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATETOPLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.AXIAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.BOTTOMLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.MIDDLEMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.RIGHTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.TOPLEFTMAIN]: _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.AXIAL }, volumeCenter: undefined, zoom: 1 }; const sessionData = { annotationSize: 2, createdAt: now, createdByUid: userId, name, protocolDefinitions: [], renderSettings, schemaVersion: _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.WORK_SESSION_LATEST_SCHEMA, seriesUid, storeUid, studyUid, uid: uid ?? crypto.randomUUID(), updatedAt: now, updatedByUid: userId, version: 1, viewportCamera, volumes: [{ annotations: [], chambers: [], phaseId: initialPhaseId, protocolData: { instances: [] }, renderSettings, sCurveRelativeMeasurements: [], sCurves: [], viewportCamera }] }; const validatedSession = _tomoverse_contracts__WEBPACK_IMPORTED_MODULE_18__.workSessionSchema.parse(sessionData); // Must run before the first write, or the new session reaches the backend. yield _this0.workSessionDb.markDraft(validatedSession.uid); _this0._isDraft.set(true); yield _this0.workSessionDb.save(validatedSession); _this0.location.replaceState(`/volume-viewer/${storeUid}/${studyUid}/${seriesUid}/${validatedSession.uid}`, queryString); yield _this0.router.navigate(['/volume-viewer', storeUid, studyUid, seriesUid, validatedSession.uid], { queryParamsHandling: 'preserve', // Marks this as the create flow redirect so the route reuse strategy // keeps the viewer component alive instead of recreating it. state: { [_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.WORK_SESSION_CREATED_STATE_KEY]: true } }); })(); } loadWorkSessionFromDb(workSession) { var _this1 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { const { phaseSelection, volumes } = workSession; _this1.volumes.set(volumes); // A session always reopens on the first offered phase; only which phases are offered // survives the reload, not which one was active. const firstPhaseId = phaseSelection?.availablePhaseIds[0]; const activeBundle = volumes.find(({ phaseId }) => phaseId === firstPhaseId) ?? volumes[0]; if (phaseSelection) { _this1.volumeViewerStore.setPhaseSelection(workSession.seriesUid, { ...phaseSelection, activePhaseId: activeBundle?.phaseId ?? phaseSelection.activePhaseId }); } _this1.hydrateSessionSettings(workSession); // STL geometries are session-level attachments; load them before annotations that reference them. yield _this1.populateStlGeometries(workSession.uid); if (activeBundle) { _this1.hydrateActiveBundle(activeBundle); } _this1.protocolFacade.import({ activeProtocolId: activeBundle?.protocolData.activeProtocolId ?? activeBundle?.protocolData.instances[0]?.protocolId ?? _protocols__WEBPACK_IMPORTED_MODULE_25__.DEFAULT_PROTOCOLS[0]?.id, definitions: workSession.protocolDefinitions ?? [], instances: activeBundle?.protocolData.instances ?? [] }); // Add defaults as well for (const protocol of _protocols__WEBPACK_IMPORTED_MODULE_25__.DEFAULT_PROTOCOLS) { _this1.protocolFacade.addProtocol(protocol, true); } } catch (error) { _this1.log.error(`There was an error loading the work session`, error); yield _this1.router.navigate(['/volume-viewer']); } })(); } hydrateSessionSettings(session) { this.annotationFacade.setAnnotationSize(session.annotationSize); } hydrateActiveBundle(bundle) { const { annotations, chambers, protocolData, renderSettings, sCurveRelativeMeasurements, sCurves, viewportCamera } = bundle; this.renderSettingsStore.import({ ...renderSettings, volumeRenderPresets: renderSettings.volumeRenderPresets.map(p => ({ ...p })), windowPresets: renderSettings.windowPresets.map(p => ({ ...p })) }); this.renderSettingsStore.selectWindowPreset(renderSettings.selectedWindowPresetName); this.viewportStore.import({ ...viewportCamera, intersection: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.parsePosition)(viewportCamera.intersection), isocenter: (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.parsePosition)(viewportCamera.isocenter), matrix: this.parseMatrix(viewportCamera.matrix), viewportAxisMapping: { [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATEBOTTOMLEFT]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATEBOTTOMLEFT] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATETOPLEFTMAIN]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.ALTERNATETOPLEFTMAIN] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.AXIAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.BOTTOMLEFTMAIN]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.BOTTOMLEFTMAIN] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.SAGITTAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.MIDDLEMAIN]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.MIDDLEMAIN] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.RIGHTMAIN]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.RIGHTMAIN] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.CORONAL, [_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.TOPLEFTMAIN]: viewportCamera.viewportAxisMapping[_tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxisState.TOPLEFTMAIN] ?? _tomoverse_enums__WEBPACK_IMPORTED_MODULE_21__.ViewportAxis.AXIAL }, volumeCenter: viewportCamera.volumeCenter ? (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.parsePosition)(viewportCamera.volumeCenter) : undefined }); this.annotationFacade.loadAnnotations(annotations.map(({ displayOrder, ...annotation }) => annotation)); this.chamberFacade.loadChambers(chambers); // Spline-derived stubs get reconciled against the just-loaded annotations by the // s-curve store's own reactive sync effect, so this must come after loadAnnotations. this.sCurveFacade.importSCurves(sCurves); this.sCurveFacade.reorderRelativeMeasurements(sCurveRelativeMeasurements); this.protocolFacade.import({ activeProtocolId: protocolData.activeProtocolId, instances: protocolData.instances }); } requestActiveVolume(phaseId, revealAnnotationId) { this.volumeViewerStore.requestActiveVolume({ phaseId, revealAnnotationId }); } requestActiveChamberVolume(phaseId, revealChamberId) { this.volumeViewerStore.requestActiveVolume({ phaseId, revealChamberId }); } switchActiveVolume(fromPhaseId, toPhaseId) { if (fromPhaseId === toPhaseId) return; const protocolDefinitions = (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(() => this.protocolFacade.exportState().definitions); const savedFrom = this.exportActiveBundle(fromPhaseId); const held = this.volumes().some(({ phaseId }) => phaseId === fromPhaseId) ? this.volumes().map(bundle => bundle.phaseId === fromPhaseId ? savedFrom : bundle) : [...this.volumes(), savedFrom]; // A first-visit phase inherits the current render settings and camera with no annotations, and empty protocol instances. const target = held.find(({ phaseId }) => phaseId === toPhaseId) ?? { ...this.exportActiveBundle(toPhaseId), annotations: [], chambers: [], protocolData: { instances: protocolDefinitions.map(({ id }) => ({ placeholderMappings: {}, protocolId: id })) }, sCurveRelativeMeasurements: [], sCurves: [] }; this.volumes.set(held.some(({ phaseId }) => phaseId === toPhaseId) ? held : [...held, target]); this.hydrateActiveBundle(target); } populateStlGeometries(uid) { var _this10 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const lookup = {}; const attachments = yield _this10.workSessionDb.getAttachments(uid); const stlAttachments = attachments?.filter(attachment => attachment.id.startsWith('stl:')) ?? []; for (const attachment of stlAttachments) { try { const blob = yield attachment.getData(); const geometry = yield (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.readObject3DGeometryBlob)(blob); if (geometry) { lookup[attachment.id] = geometry; } } catch (error) { console.warn(`Failed to populate geometry for ${attachment.id}`, error); } } _this10.geometryFacade.importStlGeometry(lookup); })(); } exportWorkSession() { var _this11 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const workSession = _this11.workSessionDbSnapshot(); if (!workSession) { throw new Error(`Current work session data not found.`); } try { const attachments = yield _this11.workSessionDb.getAttachments(workSession.uid); const fileName = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.formatExportFileName)(workSession.name); (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.exportToJsonFile)(_this11.document, { ...workSession, _attachments: yield Promise.all((attachments ?? []).map(/*#__PURE__*/function () { var _ref9 = (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (attachment) { return { data: yield attachment.getDataBase64(), digest: attachment.digest, id: attachment.id, length: attachment.length, type: attachment.type }; }); return function (_x2) { return _ref9.apply(this, arguments); }; }())) }, fileName); } catch (error) { console.error('Failed to export', error); throw error; } })(); } parseMatrix(matrix) { return gl_matrix__WEBPACK_IMPORTED_MODULE_15__.fromValues(matrix[0] ?? 0, matrix[1] ?? 0, matrix[2] ?? 0, matrix[3] ?? 0, matrix[4] ?? 0, matrix[5] ?? 0, matrix[6] ?? 0, matrix[7] ?? 0, matrix[8] ?? 0); } handleAction(action, successKey, errorKey) { var _this12 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { try { yield (0,_angular_common__WEBPACK_IMPORTED_MODULE_1__.untracked)(action); if (successKey) { _this12.messageService.add({ severity: 'success', summary: _this12.translate.instant(successKey) }); } } catch { if (errorKey) { _this12.messageService.add({ severity: 'error', summary: _this12.translate.instant(errorKey) }); } } })(); } destroySetupEffects() { this.unregisterFlushHandler?.(); this.unregisterFlushHandler = undefined; for (const effectReference of this.setupEffects) { effectReference.destroy(); } this.setupEffects = []; } syncStlAttachments(uid, annotations) { var _this13 = this; return (0,_Users_jakewalsh_Documents_projects_tomoverse_tvct_clinical_node_modules_angular_builders_custom_webpack_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { const stlAnnotations = annotations.filter(annotation => (0,_tomoverse_dtos__WEBPACK_IMPORTED_MODULE_20__.annotationIsStl)(annotation)); if (stlAnnotations.length === 0) return []; const currentAttachments = yield _this13.workSessionDb.getAttachments(uid); if (!currentAttachments) return; const attachments = []; const usedGeometryIds = new Set(stlAnnotations.map(stl => stl.geometryId)); const geometries = _this13.geometryFacade.exportStlGeometry(); for (const [geometryId, geometry] of Object.entries(geometries)) { // If geometry is not being used by any annotations, we can remove it if (!usedGeometryIds.has(geometryId)) continue; const existing = currentAttachments.find(att => att.id === geometryId); if (existing) { // Already present, we reuse existing data attachments.push({ data: yield existing.getData(), id: geometryId, type: existing.type }); } else { const blob = (0,_tomoverse_utils__WEBPACK_IMPORTED_MODULE_23__.makeObject3DGeometryBlob)(geometry); attachments.push({ data: blob, id: geometryId, type: blob.type }); } } return attachments; })(); } static ɵfac = function WorkSessionService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || WorkSessionService)(); }; static ɵprov = /*@__PURE__*/_angular_common__WEBPACK_IMPORTED_MODULE_1__["ɵɵdefineInjectable"]({ token: WorkSessionService, factory: WorkSessionService.ɵfac }); } /***/ }, /***/ 16352 /*!****************************************!*\ !*** ./libs/post-process/src/index.ts ***! \****************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ MASK_FBO_KEY: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.MASK_FBO_KEY), /* harmony export */ MASK_PREVIEW_PASS_ID: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.MASK_PREVIEW_PASS_ID), /* harmony export */ MaskPreviewPass: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.MaskPreviewPass), /* harmony export */ OUTLINE_PASS_ID: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.OUTLINE_PASS_ID), /* harmony export */ OutlineEffectPass: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.OutlineEffectPass), /* harmony export */ vtkPostProcessPipeline: () => (/* reexport safe */ _lib__WEBPACK_IMPORTED_MODULE_0__.vtkPostProcessPipeline) /* harmony export */ }); /* harmony import */ var _lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib */ 59356); /***/ }, /***/ 19088 /*!**************************************************!*\ !*** ./libs/post-process/src/lib/debug/index.ts ***! \**************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ captureExtendedSnapshot: () => (/* reexport safe */ _post_process_state_debug__WEBPACK_IMPORTED_MODULE_0__.captureExtendedSnapshot), /* harmony export */ diagnoseDirtyState: () => (/* reexport safe */ _post_process_state_debug__WEBPACK_IMPORTED_MODULE_0__.diagnoseDirtyState), /* harmony export */ diagnoseExtendedDrift: () => (/* reexport safe */ _post_process_state_debug__WEBPACK_IMPORTED_MODULE_0__.diagnoseExtendedDrift), /* harmony export */ reportDirtyState: () => (/* reexport safe */ _post_process_state_debug__WEBPACK_IMPORTED_MODULE_0__.reportDirtyState) /* harmony export */ }); /* harmony import */ var _post_process_state_debug__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./post-process-state-debug */ 55966); /***/ }, /***/ 55966 /*!*********************************************************************!*\ !*** ./libs/post-process/src/lib/debug/post-process-state-debug.ts ***! \*********************************************************************/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ captureExtendedSnapshot: () => (/* binding */ captureExtendedSnapshot), /* harmony export */ diagnoseDirtyState: () => (/* binding */ diagnoseDirtyState), /* harmony export */ diagnoseExtendedDrift: () => (/* binding */ diagnoseExtendedDrift), /* harmony export */ reportDirtyState: () => (/* binding */ reportDirtyState) /* harmony export */ }); /* harmony import */ var _gl_state__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../gl-state */ 86334); // WebGLBuffer/WebGLTexture instances have no human-readable identity; // without a stable id every log line prints `