@acorex/modules 21.0.0-next.59 → 21.0.0-next.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assessment-management/README.md +4 -4
- package/fesm2022/{acorex-modules-assessment-management-acorex-modules-assessment-management-o8aFazwA.mjs → acorex-modules-assessment-management-acorex-modules-assessment-management-DlhSQ0cB.mjs} +3608 -367
- package/fesm2022/acorex-modules-assessment-management-acorex-modules-assessment-management-DlhSQ0cB.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-assessment-case.entity-yrc_Yybq.mjs → acorex-modules-assessment-management-assessment-case.entity-B6C2PRZw.mjs} +43 -28
- package/fesm2022/acorex-modules-assessment-management-assessment-case.entity-B6C2PRZw.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-assessment-session-answers-view.util-BUQa_TSY.mjs → acorex-modules-assessment-management-assessment-session-answers-view.util-BRdwcIvw.mjs} +2 -2
- package/fesm2022/{acorex-modules-assessment-management-assessment-session-answers-view.util-BUQa_TSY.mjs.map → acorex-modules-assessment-management-assessment-session-answers-view.util-BRdwcIvw.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-assessment-management-assessment-session.entity-Cwf30iuu.mjs → acorex-modules-assessment-management-assessment-session.entity-DquzZNaQ.mjs} +19 -3
- package/fesm2022/acorex-modules-assessment-management-assessment-session.entity-DquzZNaQ.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-fill-assessment-session.command-CJieLR5g.mjs → acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs} +2 -2
- package/fesm2022/acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-preview-question.command-D0-FB1HH.mjs → acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs} +2 -2
- package/fesm2022/acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-preview-questionnaire.command-wqPNgv7q.mjs → acorex-modules-assessment-management-preview-questionnaire.command-S-8MDeB7.mjs} +2 -2
- package/fesm2022/{acorex-modules-assessment-management-preview-questionnaire.command-wqPNgv7q.mjs.map → acorex-modules-assessment-management-preview-questionnaire.command-S-8MDeB7.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DYyUhSWd.mjs → acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-wdHMGBxi.mjs} +2 -2
- package/fesm2022/acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-wdHMGBxi.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-question-bank-item.entity-DUf2ceKY.mjs → acorex-modules-assessment-management-question-bank-item.entity-1Pm9O0kv.mjs} +2 -2
- package/fesm2022/{acorex-modules-assessment-management-question-bank-item.entity-DUf2ceKY.mjs.map → acorex-modules-assessment-management-question-bank-item.entity-1Pm9O0kv.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-assessment-management-questionnaire-viewer-popup.component-Cy5ElBmU.mjs → acorex-modules-assessment-management-questionnaire-viewer-popup.component-Dwx0y7WY.mjs} +9 -121
- package/fesm2022/acorex-modules-assessment-management-questionnaire-viewer-popup.component-Dwx0y7WY.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-questionnaire.entity-RWSkzNbA.mjs → acorex-modules-assessment-management-questionnaire.entity-BI_jc4C6.mjs} +12 -36
- package/fesm2022/acorex-modules-assessment-management-questionnaire.entity-BI_jc4C6.mjs.map +1 -0
- package/fesm2022/{acorex-modules-assessment-management-view-case-last-session-answers.command-NTuDdoYk.mjs → acorex-modules-assessment-management-view-case-last-session-answers.command-Ds-QGMPy.mjs} +3 -3
- package/fesm2022/{acorex-modules-assessment-management-view-case-last-session-answers.command-NTuDdoYk.mjs.map → acorex-modules-assessment-management-view-case-last-session-answers.command-Ds-QGMPy.mjs.map} +1 -1
- package/fesm2022/{acorex-modules-assessment-management-view-session-answers.command-0btGV66_.mjs → acorex-modules-assessment-management-view-session-answers.command-COTVoRRG.mjs} +3 -3
- package/fesm2022/{acorex-modules-assessment-management-view-session-answers.command-0btGV66_.mjs.map → acorex-modules-assessment-management-view-session-answers.command-COTVoRRG.mjs.map} +1 -1
- package/fesm2022/acorex-modules-assessment-management-view-session-outcomes.command-2buH7ydV.mjs +239 -0
- package/fesm2022/acorex-modules-assessment-management-view-session-outcomes.command-2buH7ydV.mjs.map +1 -0
- package/fesm2022/acorex-modules-assessment-management.mjs +1 -1
- package/fesm2022/acorex-modules-common.mjs +1 -0
- package/fesm2022/acorex-modules-common.mjs.map +1 -1
- package/package.json +2 -2
- package/types/acorex-modules-assessment-management.d.ts +383 -271
- package/types/acorex-modules-common.d.ts +1 -0
- package/fesm2022/acorex-modules-assessment-management-acorex-modules-assessment-management-o8aFazwA.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-assessment-case.entity-yrc_Yybq.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-assessment-session.entity-Cwf30iuu.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-fill-assessment-session.command-CJieLR5g.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-index-D8KjfHAH.mjs +0 -1509
- package/fesm2022/acorex-modules-assessment-management-index-D8KjfHAH.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-preview-question.command-D0-FB1HH.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-DYyUhSWd.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-questionnaire-calculation.entity-CYF0k42_.mjs +0 -236
- package/fesm2022/acorex-modules-assessment-management-questionnaire-calculation.entity-CYF0k42_.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-questionnaire-viewer-popup.component-Cy5ElBmU.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-questionnaire.entity-RWSkzNbA.mjs.map +0 -1
- package/fesm2022/acorex-modules-assessment-management-save-questionnaire-questions.command-koGmUbNE.mjs +0 -61
- package/fesm2022/acorex-modules-assessment-management-save-questionnaire-questions.command-koGmUbNE.mjs.map +0 -1
|
@@ -1,48 +1,53 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injector, Injectable, NgModule,
|
|
2
|
+
import { inject, Injector, Injectable, NgModule, input, output, signal, viewChild, computed, effect, untracked, ChangeDetectionStrategy, Component, ViewEncapsulation, ElementRef, afterNextRender } from '@angular/core';
|
|
3
3
|
import { AXPCommonMenuKeys } from '@acorex/modules/common';
|
|
4
|
-
import { AXPEntityService, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
5
|
-
import { AXPSearchCommandProvider, createEntityCommandOptions, AXPFileStorageService, AXPStickyDirective, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER } from '@acorex/platform/common';
|
|
4
|
+
import { AXPEntityService, AXPEntityDefinitionRegistryService, AXPEntityEventsKeys, AXP_ENTITY_DEFINITION_LOADER } from '@acorex/platform/layout/entity';
|
|
5
|
+
import { AXPSearchCommandProvider, createEntityCommandOptions, AXPFileStorageService, AXPStickyDirective, AXP_STATUS_PROVIDERS, AXP_MENU_PROVIDER, AXP_SEARCH_PROVIDER, AXPSystemStatusType } from '@acorex/platform/common';
|
|
6
6
|
import { AXPAuthGuard, AXP_PERMISSION_DEFINITION_PROVIDER, AXPSessionService } from '@acorex/platform/auth';
|
|
7
|
-
import { AXPStateMessageComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPThemeLayoutBlockComponent, AXPStopwatchComponent } from '@acorex/platform/layout/components';
|
|
8
|
-
import { provideCommandSetups, provideCommand } from '@acorex/platform/runtime';
|
|
9
|
-
import { AXPExpressionEvaluatorService, AXPDeviceService, containsHtmlMarkup, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, provideLazyProvider, AXP_FEATURE_DEFINITION_PROVIDER, AXPContextStore } from '@acorex/platform/core';
|
|
7
|
+
import { AXPDataSelectorService, AXPPropertyViewerService, AXPStandardSectionItemsBuilderComponent, AXPStateMessageComponent, AXP_PAGE_COMPONENT_PROVIDER, AXPOutcomeResultsViewerComponent, AXPThemeLayoutBlockComponent, AXPStopwatchComponent } from '@acorex/platform/layout/components';
|
|
8
|
+
import { AXPCommandService, provideCommandSetups, provideCommand } from '@acorex/platform/runtime';
|
|
9
|
+
import { AXPExpressionEvaluatorService, AXPDeviceService, AXPBroadcastEventService, AXPDataGenerator, containsHtmlMarkup, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, provideLazyProvider, AXP_FEATURE_DEFINITION_PROVIDER, AXPContextStore } from '@acorex/platform/core';
|
|
10
10
|
import { ROUTES, ActivatedRoute, Router } from '@angular/router';
|
|
11
11
|
import { AXPRootLayoutComponent } from '@acorex/platform/themes/default';
|
|
12
12
|
import { AXMMetaDataDefinitionEntityModule } from '@acorex/modules/data-management';
|
|
13
|
-
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
14
|
-
import { AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER, AXPWidgetContainerComponent, AXPWidgetCoreService } from '@acorex/platform/layout/widget-core';
|
|
13
|
+
import * as i1$1 from '@acorex/platform/layout/widget-core';
|
|
14
|
+
import { AXPWidgetGroupEnum, AXP_WIDGETS_EDITOR_CATEGORY, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER, AXPWidgetsCatalog, createBooleanProperty, AXPWidgetRegistryService, AXPWidgetContainerComponent, AXPWidgetCoreService } from '@acorex/platform/layout/widget-core';
|
|
15
15
|
import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY } from '@acorex/platform/layout/widgets';
|
|
16
16
|
import * as i3 from '@angular/common';
|
|
17
17
|
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
18
18
|
import * as i1$3 from '@acorex/components/form';
|
|
19
19
|
import { AXFormModule } from '@acorex/components/form';
|
|
20
|
-
import * as i4
|
|
21
|
-
import { resolveMultiLanguageString, AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
22
|
-
import * as i2
|
|
20
|
+
import * as i4 from '@acorex/core/translation';
|
|
21
|
+
import { resolveMultiLanguageString, AXTranslationService, AXTranslationModule, createMultiLanguageString, isEffectivelyEmptyLocalizedValue } from '@acorex/core/translation';
|
|
22
|
+
import * as i2 from '@acorex/components/decorators';
|
|
23
23
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
24
24
|
import { AXToastService } from '@acorex/components/toast';
|
|
25
25
|
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
26
|
-
import { cloneDeep, get } from 'lodash-es';
|
|
26
|
+
import { cloneDeep, get, isEqual, isNil, first, defaultTo, isEmpty, isObject } from 'lodash-es';
|
|
27
|
+
import { AXDataSource } from '@acorex/cdk/common';
|
|
28
|
+
import { AXFullScreenDirective } from '@acorex/cdk/full-screen';
|
|
29
|
+
import * as i1 from '@acorex/components/button';
|
|
30
|
+
import { AXButtonModule } from '@acorex/components/button';
|
|
31
|
+
import { AXDropdownModule } from '@acorex/components/dropdown';
|
|
32
|
+
import { AXLabelModule } from '@acorex/components/label';
|
|
33
|
+
import { AXSwitchModule } from '@acorex/components/switch';
|
|
34
|
+
import * as i5 from '@angular/forms';
|
|
35
|
+
import { FormsModule } from '@angular/forms';
|
|
27
36
|
import { AXPopupService } from '@acorex/components/popup';
|
|
28
|
-
import
|
|
37
|
+
import { AXPPageLayoutBaseComponent, AXPPageLayoutBase, AXPPageLayoutComponent } from '@acorex/platform/layout/views';
|
|
38
|
+
import * as i2$1 from '@acorex/components/alert';
|
|
29
39
|
import { AXAlertModule } from '@acorex/components/alert';
|
|
30
|
-
import * as i4 from '@acorex/components/text-area';
|
|
40
|
+
import * as i4$1 from '@acorex/components/text-area';
|
|
31
41
|
import { AXTextAreaModule } from '@acorex/components/text-area';
|
|
32
42
|
import { AXSafePipe } from '@acorex/core/pipes';
|
|
33
|
-
import * as i5 from '@angular/forms';
|
|
34
|
-
import { FormsModule } from '@angular/forms';
|
|
35
43
|
import { AXDrawerDirectiveModule } from '@acorex/cdk/drawer';
|
|
36
44
|
import { AXResizableDirective } from '@acorex/cdk/resizable';
|
|
37
45
|
import * as i2$2 from '@acorex/components/badge';
|
|
38
46
|
import { AXBadgeModule } from '@acorex/components/badge';
|
|
39
|
-
import * as i1$2 from '@acorex/components/button';
|
|
40
|
-
import { AXButtonModule } from '@acorex/components/button';
|
|
41
47
|
import * as i3$1 from '@acorex/components/drawer';
|
|
42
48
|
import { AXDrawerModule } from '@acorex/components/drawer';
|
|
43
|
-
import * as i1$
|
|
49
|
+
import * as i1$2 from '@acorex/components/tabs';
|
|
44
50
|
import { AXTabsComponent, AXTabsModule } from '@acorex/components/tabs';
|
|
45
|
-
import { AXPPageLayoutBaseComponent, AXPPageLayoutComponent, AXPPageLayoutBase } from '@acorex/platform/layout/views';
|
|
46
51
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
47
52
|
|
|
48
53
|
//#region ---- Root Configuration ----
|
|
@@ -81,12 +86,6 @@ const RootConfig = {
|
|
|
81
86
|
titlePlural: '@assessment-management:sessions.entities.assessment-session.plural',
|
|
82
87
|
icon: 'fa-light fa-clipboard-check',
|
|
83
88
|
},
|
|
84
|
-
questionnaireCalculation: {
|
|
85
|
-
name: 'QuestionnaireCalculation',
|
|
86
|
-
title: '@assessment-management:questionnaire-calculations.entities.questionnaire-calculation.title',
|
|
87
|
-
titlePlural: '@assessment-management:questionnaire-calculations.entities.questionnaire-calculation.plural',
|
|
88
|
-
icon: 'fa-light fa-calculator',
|
|
89
|
-
},
|
|
90
89
|
},
|
|
91
90
|
};
|
|
92
91
|
//#endregion
|
|
@@ -102,15 +101,13 @@ class AXMAssessmentManagementEntityProvider {
|
|
|
102
101
|
if (moduleName === RootConfig.module.name) {
|
|
103
102
|
switch (entityName) {
|
|
104
103
|
case RootConfig.entities.questionBankItem.name:
|
|
105
|
-
return (await import('./acorex-modules-assessment-management-question-bank-item.entity-
|
|
104
|
+
return (await import('./acorex-modules-assessment-management-question-bank-item.entity-1Pm9O0kv.mjs')).factory(this.injector);
|
|
106
105
|
case RootConfig.entities.questionnaire.name:
|
|
107
|
-
return (await import('./acorex-modules-assessment-management-questionnaire.entity-
|
|
106
|
+
return (await import('./acorex-modules-assessment-management-questionnaire.entity-BI_jc4C6.mjs')).factory();
|
|
108
107
|
case RootConfig.entities.assessmentCase.name:
|
|
109
|
-
return (await import('./acorex-modules-assessment-management-assessment-case.entity-
|
|
108
|
+
return (await import('./acorex-modules-assessment-management-assessment-case.entity-B6C2PRZw.mjs')).factory(this.injector);
|
|
110
109
|
case RootConfig.entities.assessmentSession.name:
|
|
111
|
-
return (await import('./acorex-modules-assessment-management-assessment-session.entity-
|
|
112
|
-
case RootConfig.entities.questionnaireCalculation.name:
|
|
113
|
-
return (await import('./acorex-modules-assessment-management-questionnaire-calculation.entity-CYF0k42_.mjs')).factory(this.injector);
|
|
110
|
+
return (await import('./acorex-modules-assessment-management-assessment-session.entity-DquzZNaQ.mjs')).factory(this.injector);
|
|
114
111
|
}
|
|
115
112
|
}
|
|
116
113
|
return null;
|
|
@@ -177,9 +174,6 @@ const AXMAssessmentManagementPermissionKeys = {
|
|
|
177
174
|
Session: {
|
|
178
175
|
Management: 'AssessmentManagement:Session:Management',
|
|
179
176
|
},
|
|
180
|
-
QuestionnaireCalculation: {
|
|
181
|
-
Management: 'AssessmentManagement:QuestionnaireCalculation:Management',
|
|
182
|
-
},
|
|
183
177
|
Automation: {
|
|
184
178
|
Management: 'AssessmentManagement:Automation:Management',
|
|
185
179
|
},
|
|
@@ -270,7 +264,6 @@ class AXMAssessmentManagementPermissionDefinitionProvider {
|
|
|
270
264
|
const QUESTIONNAIRE_PERMISSIONS = '@assessment-management:questionnaires.permissions.questionnaire';
|
|
271
265
|
const CASE_PERMISSIONS = '@assessment-management:cases.permissions.assessment-case';
|
|
272
266
|
const SESSION_PERMISSIONS = '@assessment-management:sessions.permissions.assessment-session';
|
|
273
|
-
const QUESTIONNAIRE_CALCULATION_PERMISSIONS = '@assessment-management:questionnaire-calculations.permissions.questionnaire-calculation';
|
|
274
267
|
const AUTOMATION_PERMISSIONS = '@assessment-management:automations.permissions.automation';
|
|
275
268
|
context
|
|
276
269
|
.addGroup(RootConfig.module.name, `${MODULE_PERMISSIONS}.title`, `${MODULE_PERMISSIONS}.description`)
|
|
@@ -289,9 +282,6 @@ class AXMAssessmentManagementPermissionDefinitionProvider {
|
|
|
289
282
|
// AssessmentSession Permissions (view-only; sessions are created by workflows)
|
|
290
283
|
.addPermission(keys.Session.Management, `${SESSION_PERMISSIONS}.management.title`, `${SESSION_PERMISSIONS}.management.description`)
|
|
291
284
|
.endPermission()
|
|
292
|
-
// QuestionnaireCalculation Permissions
|
|
293
|
-
.addPermission(keys.QuestionnaireCalculation.Management, `${QUESTIONNAIRE_CALCULATION_PERMISSIONS}.management.title`, `${QUESTIONNAIRE_CALCULATION_PERMISSIONS}.management.description`)
|
|
294
|
-
.endPermission()
|
|
295
285
|
// Automation Permissions
|
|
296
286
|
.addPermission(keys.Automation.Management, `${AUTOMATION_PERMISSIONS}.management.title`, `${AUTOMATION_PERMISSIONS}.management.description`)
|
|
297
287
|
.endPermission()
|
|
@@ -440,10 +430,10 @@ const AXMQuestionBankInterfaceEditorWidget = {
|
|
|
440
430
|
],
|
|
441
431
|
components: {
|
|
442
432
|
edit: {
|
|
443
|
-
component: () => import('./acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-
|
|
433
|
+
component: () => import('./acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-wdHMGBxi.mjs').then((c) => c.AXMQuestionBankInterfaceEditorWidgetEditComponent),
|
|
444
434
|
},
|
|
445
435
|
designer: {
|
|
446
|
-
component: () => import('./acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-
|
|
436
|
+
component: () => import('./acorex-modules-assessment-management-question-bank-interface-editor-widget-edit.component-wdHMGBxi.mjs').then((c) => c.AXMQuestionBankInterfaceEditorWidgetEditComponent),
|
|
447
437
|
},
|
|
448
438
|
column: {
|
|
449
439
|
component: () => import('@acorex/platform/layout/widgets').then((m) => m.AXPWidgetFieldConfiguratorWidgetColumnComponent),
|
|
@@ -998,6 +988,279 @@ function allocateNextQuestionItemName(used) {
|
|
|
998
988
|
}
|
|
999
989
|
//#endregion
|
|
1000
990
|
|
|
991
|
+
//#region ---- Imports ----
|
|
992
|
+
const DEFAULT_PRE_QUESTIONNAIRE_CONFIG = { enabled: false };
|
|
993
|
+
const DEFAULT_POST_QUESTIONNAIRE_CONFIG = {
|
|
994
|
+
reviewEnabled: false,
|
|
995
|
+
summaryEnabled: false,
|
|
996
|
+
showOutcomeResults: false,
|
|
997
|
+
};
|
|
998
|
+
const DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY = {
|
|
999
|
+
viewMode: 'single-page',
|
|
1000
|
+
showProgressBar: true,
|
|
1001
|
+
showTimer: false,
|
|
1002
|
+
showQuestionNumbers: true,
|
|
1003
|
+
validationStrategy: 'step',
|
|
1004
|
+
completionMode: 'submit-only',
|
|
1005
|
+
};
|
|
1006
|
+
const OUTCOME_DISPLAY_OPERATORS = [
|
|
1007
|
+
'eq',
|
|
1008
|
+
'neq',
|
|
1009
|
+
'gt',
|
|
1010
|
+
'gte',
|
|
1011
|
+
'lt',
|
|
1012
|
+
'lte',
|
|
1013
|
+
];
|
|
1014
|
+
const OUTCOME_DISPLAY_EMPHASIS = ['normal', 'medium', 'bold'];
|
|
1015
|
+
function normalizeOutcomeDisplayColor(value) {
|
|
1016
|
+
if (typeof value !== 'string') {
|
|
1017
|
+
return undefined;
|
|
1018
|
+
}
|
|
1019
|
+
const trimmed = value.trim();
|
|
1020
|
+
const parts = trimmed.split(/\s+/);
|
|
1021
|
+
if (parts.length !== 3) {
|
|
1022
|
+
return undefined;
|
|
1023
|
+
}
|
|
1024
|
+
return trimmed;
|
|
1025
|
+
}
|
|
1026
|
+
function normalizeOutcomeDisplayOperator(value) {
|
|
1027
|
+
const raw = typeof value === 'string'
|
|
1028
|
+
? value
|
|
1029
|
+
: typeof value === 'object' && value !== null && 'id' in value
|
|
1030
|
+
? String(value.id ?? '')
|
|
1031
|
+
: '';
|
|
1032
|
+
const normalized = raw.trim().toLowerCase();
|
|
1033
|
+
return OUTCOME_DISPLAY_OPERATORS.includes(normalized)
|
|
1034
|
+
? normalized
|
|
1035
|
+
: undefined;
|
|
1036
|
+
}
|
|
1037
|
+
function normalizeOutcomeDisplayCompareValue(value) {
|
|
1038
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
1039
|
+
return value;
|
|
1040
|
+
}
|
|
1041
|
+
if (typeof value === 'boolean') {
|
|
1042
|
+
return value;
|
|
1043
|
+
}
|
|
1044
|
+
if (typeof value === 'string') {
|
|
1045
|
+
const trimmed = value.trim();
|
|
1046
|
+
if (!trimmed) {
|
|
1047
|
+
return undefined;
|
|
1048
|
+
}
|
|
1049
|
+
if (trimmed === 'true')
|
|
1050
|
+
return true;
|
|
1051
|
+
if (trimmed === 'false')
|
|
1052
|
+
return false;
|
|
1053
|
+
const asNumber = Number(trimmed);
|
|
1054
|
+
if (Number.isFinite(asNumber)) {
|
|
1055
|
+
return asNumber;
|
|
1056
|
+
}
|
|
1057
|
+
return trimmed;
|
|
1058
|
+
}
|
|
1059
|
+
return undefined;
|
|
1060
|
+
}
|
|
1061
|
+
function normalizeOutcomeDisplayEmphasis(value) {
|
|
1062
|
+
const raw = typeof value === 'string'
|
|
1063
|
+
? value
|
|
1064
|
+
: typeof value === 'object' && value !== null && 'id' in value
|
|
1065
|
+
? String(value.id ?? '')
|
|
1066
|
+
: '';
|
|
1067
|
+
const normalized = raw.trim().toLowerCase();
|
|
1068
|
+
return OUTCOME_DISPLAY_EMPHASIS.includes(normalized)
|
|
1069
|
+
? normalized
|
|
1070
|
+
: 'normal';
|
|
1071
|
+
}
|
|
1072
|
+
function normalizeOutcomeDisplayIcon(icon) {
|
|
1073
|
+
if (icon == null || icon === '') {
|
|
1074
|
+
return undefined;
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof icon === 'string') {
|
|
1077
|
+
const trimmed = icon.trim();
|
|
1078
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
1079
|
+
}
|
|
1080
|
+
const styleClass = String(icon.styleClass ?? '').trim();
|
|
1081
|
+
const iconClass = String(icon.iconClass ?? '').trim();
|
|
1082
|
+
const combined = [styleClass, iconClass].filter(Boolean).join(' ');
|
|
1083
|
+
return combined.length > 0 ? combined : undefined;
|
|
1084
|
+
}
|
|
1085
|
+
/** Parses a theme color chooser value into foreground, background, and border parts. */
|
|
1086
|
+
function parseQuestionnaireOutcomeDisplayColor(value) {
|
|
1087
|
+
if (!value?.trim()) {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
const parts = value.trim().split(/\s+/);
|
|
1091
|
+
if (parts.length !== 3) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
foreground: parts[0],
|
|
1096
|
+
background: parts[1],
|
|
1097
|
+
border: parts[2],
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
function isQuestionnaireOutcomeDisplayColorHex(value) {
|
|
1101
|
+
return value.trim().startsWith('#');
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Returns true when the evaluated outcome value matches the display rule condition.
|
|
1105
|
+
*/
|
|
1106
|
+
function matchesQuestionnaireOutcomeDisplayRule(value, rule) {
|
|
1107
|
+
const right = rule.compareValue;
|
|
1108
|
+
switch (rule.operator) {
|
|
1109
|
+
case 'eq':
|
|
1110
|
+
return value == right;
|
|
1111
|
+
case 'neq':
|
|
1112
|
+
return value != right;
|
|
1113
|
+
case 'gt':
|
|
1114
|
+
return Number(value) > Number(right);
|
|
1115
|
+
case 'gte':
|
|
1116
|
+
return Number(value) >= Number(right);
|
|
1117
|
+
case 'lt':
|
|
1118
|
+
return Number(value) < Number(right);
|
|
1119
|
+
case 'lte':
|
|
1120
|
+
return Number(value) <= Number(right);
|
|
1121
|
+
default:
|
|
1122
|
+
return false;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
function normalizeQuestionnaireOutcomeDisplayRules(rules) {
|
|
1126
|
+
if (!Array.isArray(rules)) {
|
|
1127
|
+
return [];
|
|
1128
|
+
}
|
|
1129
|
+
const normalized = [];
|
|
1130
|
+
for (const [index, rule] of rules.entries()) {
|
|
1131
|
+
const operator = normalizeOutcomeDisplayOperator(rule?.operator);
|
|
1132
|
+
const compareValue = normalizeOutcomeDisplayCompareValue(rule?.compareValue);
|
|
1133
|
+
const color = normalizeOutcomeDisplayColor(rule?.color);
|
|
1134
|
+
if (!operator || compareValue === undefined || !color) {
|
|
1135
|
+
continue;
|
|
1136
|
+
}
|
|
1137
|
+
normalized.push({
|
|
1138
|
+
id: String(rule?.id ?? '').trim() || `rule-${index + 1}`,
|
|
1139
|
+
order: rule?.order ?? index,
|
|
1140
|
+
operator,
|
|
1141
|
+
compareValue,
|
|
1142
|
+
color,
|
|
1143
|
+
emphasis: normalizeOutcomeDisplayEmphasis(rule?.emphasis),
|
|
1144
|
+
icon: normalizeOutcomeDisplayIcon(rule?.icon),
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
return normalized.sort((a, b) => a.order - b.order);
|
|
1148
|
+
}
|
|
1149
|
+
const DEFAULT_QUESTIONNAIRE_OUTCOMES = { sections: [] };
|
|
1150
|
+
function normalizeQuestionnaireOutcomesValue(value) {
|
|
1151
|
+
const sections = value?.sections;
|
|
1152
|
+
if (!Array.isArray(sections)) {
|
|
1153
|
+
return { sections: [] };
|
|
1154
|
+
}
|
|
1155
|
+
return {
|
|
1156
|
+
sections: sections.map((section, index) => ({
|
|
1157
|
+
...section,
|
|
1158
|
+
name: (section.name ?? '').trim() || `section-${index + 1}`,
|
|
1159
|
+
order: section.order ?? index,
|
|
1160
|
+
items: Array.isArray(section.items)
|
|
1161
|
+
? section.items.map((item) => ({
|
|
1162
|
+
...item,
|
|
1163
|
+
displayRules: normalizeQuestionnaireOutcomeDisplayRules(item.displayRules),
|
|
1164
|
+
}))
|
|
1165
|
+
: [],
|
|
1166
|
+
})),
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
/** All outcome items across sections (evaluation, automations, duplicate checks). */
|
|
1170
|
+
function flattenQuestionnaireOutcomeItems(value) {
|
|
1171
|
+
return normalizeQuestionnaireOutcomesValue(value).sections.flatMap((section) => section.items);
|
|
1172
|
+
}
|
|
1173
|
+
function findDuplicateOutcomeNames(value) {
|
|
1174
|
+
const seen = new Map();
|
|
1175
|
+
for (const item of flattenQuestionnaireOutcomeItems(value)) {
|
|
1176
|
+
const key = (item.name ?? '').trim();
|
|
1177
|
+
if (!key)
|
|
1178
|
+
continue;
|
|
1179
|
+
seen.set(key, (seen.get(key) ?? 0) + 1);
|
|
1180
|
+
}
|
|
1181
|
+
return Array.from(seen.entries())
|
|
1182
|
+
.filter(([, count]) => count > 1)
|
|
1183
|
+
.map(([name]) => name);
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Maps entity pre/post to viewer config (defaults when omitted).
|
|
1187
|
+
*/
|
|
1188
|
+
function toPrePostConfig(q) {
|
|
1189
|
+
if (!q) {
|
|
1190
|
+
return null;
|
|
1191
|
+
}
|
|
1192
|
+
const pre = {
|
|
1193
|
+
...DEFAULT_PRE_QUESTIONNAIRE_CONFIG,
|
|
1194
|
+
...q.pre,
|
|
1195
|
+
enabled: q.pre?.enabled === true,
|
|
1196
|
+
};
|
|
1197
|
+
const post = {
|
|
1198
|
+
...DEFAULT_POST_QUESTIONNAIRE_CONFIG,
|
|
1199
|
+
...q.post,
|
|
1200
|
+
reviewEnabled: q.post?.reviewEnabled === true,
|
|
1201
|
+
summaryEnabled: q.post?.summaryEnabled === true,
|
|
1202
|
+
showOutcomeResults: q.post?.showOutcomeResults === true,
|
|
1203
|
+
};
|
|
1204
|
+
return { pre, post };
|
|
1205
|
+
}
|
|
1206
|
+
const VIEW_MODE_VALUES = ['single-page', 'page-per-group', 'page-per-question', 'side-menu'];
|
|
1207
|
+
const VALIDATION_STRATEGY_VALUES = ['step', 'end'];
|
|
1208
|
+
const COMPLETION_MODE_VALUES = ['submit-only', 'save-and-continue'];
|
|
1209
|
+
/**
|
|
1210
|
+
* Coerces stored view mode (string or SelectBox `{ id }`) to a known value.
|
|
1211
|
+
*/
|
|
1212
|
+
function normalizeViewMode(value) {
|
|
1213
|
+
if (typeof value === 'string' && VIEW_MODE_VALUES.includes(value)) {
|
|
1214
|
+
return value;
|
|
1215
|
+
}
|
|
1216
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1217
|
+
return normalizeViewMode(value.id);
|
|
1218
|
+
}
|
|
1219
|
+
return 'single-page';
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Coerces stored validation strategy (string or SelectBox `{ id }`) to a known value.
|
|
1223
|
+
*/
|
|
1224
|
+
function normalizeValidationStrategy$1(value) {
|
|
1225
|
+
if (typeof value === 'string' && VALIDATION_STRATEGY_VALUES.includes(value)) {
|
|
1226
|
+
return value;
|
|
1227
|
+
}
|
|
1228
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1229
|
+
return normalizeValidationStrategy$1(value.id);
|
|
1230
|
+
}
|
|
1231
|
+
return 'step';
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Coerces stored completion mode (string or SelectBox `{ id }`) to a known value.
|
|
1235
|
+
*/
|
|
1236
|
+
function normalizeCompletionMode(value) {
|
|
1237
|
+
if (typeof value === 'string' && COMPLETION_MODE_VALUES.includes(value)) {
|
|
1238
|
+
return value;
|
|
1239
|
+
}
|
|
1240
|
+
if (value != null && typeof value === 'object' && 'id' in value && typeof value.id === 'string') {
|
|
1241
|
+
return normalizeCompletionMode(value.id);
|
|
1242
|
+
}
|
|
1243
|
+
return 'submit-only';
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Maps entity `display` to {@link QuestionnaireDisplaySettings} (defaults when omitted).
|
|
1247
|
+
*/
|
|
1248
|
+
function toDisplaySettings(q) {
|
|
1249
|
+
if (!q) {
|
|
1250
|
+
return null;
|
|
1251
|
+
}
|
|
1252
|
+
const d = { ...DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY, ...q.display };
|
|
1253
|
+
return {
|
|
1254
|
+
viewMode: normalizeViewMode(d.viewMode),
|
|
1255
|
+
showProgressBar: d.showProgressBar ?? true,
|
|
1256
|
+
showTimer: d.showTimer ?? false,
|
|
1257
|
+
showQuestionNumbers: d.showQuestionNumbers ?? true,
|
|
1258
|
+
validationStrategy: normalizeValidationStrategy$1(d.validationStrategy),
|
|
1259
|
+
completionMode: normalizeCompletionMode(d.completionMode),
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
//#endregion
|
|
1263
|
+
|
|
1001
1264
|
//#region ---- Pre/Post Content Utilities ----
|
|
1002
1265
|
/**
|
|
1003
1266
|
* Formats elapsed seconds as `m:ss` or `h:mm:ss` when an hour or more.
|
|
@@ -1015,7 +1278,7 @@ function formatElapsedDuration(totalSeconds) {
|
|
|
1015
1278
|
/**
|
|
1016
1279
|
* Resolve placeholders in summary content.
|
|
1017
1280
|
* Fixed: {{totalQuestions}}, {{answeredCount}}, {{totalTime}}, {{elapsedSeconds}}.
|
|
1018
|
-
* Plus any {{
|
|
1281
|
+
* Plus any {{outcomeName}} from values.outcomes.
|
|
1019
1282
|
*/
|
|
1020
1283
|
function resolveSummaryPlaceholders(content, values) {
|
|
1021
1284
|
if (!content)
|
|
@@ -1105,7 +1368,7 @@ function isQuestionnaireAnswerValueEmpty(value) {
|
|
|
1105
1368
|
//#endregion
|
|
1106
1369
|
//#region ---- Service ----
|
|
1107
1370
|
/**
|
|
1108
|
-
* Opens the questionnaire viewer dialog and evaluates questionnaire
|
|
1371
|
+
* Opens the questionnaire viewer dialog and evaluates questionnaire outcomes when a questionnaire id is provided.
|
|
1109
1372
|
*/
|
|
1110
1373
|
class AXMQuestionnaireViewerService {
|
|
1111
1374
|
constructor() {
|
|
@@ -1121,10 +1384,13 @@ class AXMQuestionnaireViewerService {
|
|
|
1121
1384
|
* Open questionnaire viewer in a dialog
|
|
1122
1385
|
*/
|
|
1123
1386
|
async open(config) {
|
|
1124
|
-
const { AXMQuestionnaireViewerPopupComponent } = await import('./acorex-modules-assessment-management-questionnaire-viewer-popup.component-
|
|
1387
|
+
const { AXMQuestionnaireViewerPopupComponent } = await import('./acorex-modules-assessment-management-questionnaire-viewer-popup.component-Dwx0y7WY.mjs');
|
|
1125
1388
|
const structure = config.structure;
|
|
1126
1389
|
const submitHandler = config.submitHandler ??
|
|
1127
|
-
((answers) => this.buildSummaryPlaceholderValues(structure, answers, {
|
|
1390
|
+
((answers) => this.buildSummaryPlaceholderValues(structure, answers, {
|
|
1391
|
+
questionnaireId: config.questionnaireId,
|
|
1392
|
+
outcomeRules: config.outcomeRules,
|
|
1393
|
+
}));
|
|
1128
1394
|
const result = await this.popupService.open(AXMQuestionnaireViewerPopupComponent, {
|
|
1129
1395
|
title: config.title,
|
|
1130
1396
|
size: this.deviceService.isSmall() ? 'full' : 'lg',
|
|
@@ -1137,17 +1403,18 @@ class AXMQuestionnaireViewerService {
|
|
|
1137
1403
|
saveHandler: config.saveHandler,
|
|
1138
1404
|
assessmentFillContext: config.assessmentFillContext,
|
|
1139
1405
|
questionnaireId: config.questionnaireId,
|
|
1406
|
+
outcomeRules: config.outcomeRules,
|
|
1140
1407
|
},
|
|
1141
1408
|
});
|
|
1142
1409
|
return result.data || null;
|
|
1143
1410
|
}
|
|
1144
1411
|
/**
|
|
1145
|
-
* Evaluate all questionnaire
|
|
1412
|
+
* Evaluate all questionnaire outcomes for the given questionnaire and answers.
|
|
1146
1413
|
* Pass `structure` so expressions can use `answer.byId`, `answer.byTag`, and `answer.allByTag`.
|
|
1147
1414
|
*/
|
|
1148
1415
|
/**
|
|
1149
1416
|
* Resolves `isVisible` for a section or question: `false` hides; `true`/undefined shows;
|
|
1150
|
-
* non-empty string is evaluated with the same scope as questionnaire
|
|
1417
|
+
* non-empty string is evaluated with the same scope as questionnaire outcomes (`answer.*`, `fn.*`, etc.).
|
|
1151
1418
|
*/
|
|
1152
1419
|
async evaluateQuestionnaireVisibilityFlag(isVisible, answers, structure) {
|
|
1153
1420
|
if (isVisible === false) {
|
|
@@ -1172,11 +1439,11 @@ class AXMQuestionnaireViewerService {
|
|
|
1172
1439
|
}
|
|
1173
1440
|
}
|
|
1174
1441
|
/**
|
|
1175
|
-
* Evaluates questionnaire
|
|
1442
|
+
* Evaluates questionnaire outcome rules and returns values plus display titles.
|
|
1176
1443
|
*/
|
|
1177
|
-
async evaluateOutcomes(
|
|
1178
|
-
const rules = await this.
|
|
1179
|
-
if (!rules
|
|
1444
|
+
async evaluateOutcomes(answers, options) {
|
|
1445
|
+
const rules = await this.resolveOutcomeRules(options?.questionnaireId, options?.outcomeRules);
|
|
1446
|
+
if (!rules.length)
|
|
1180
1447
|
return { values: {}, outcomeTitles: {} };
|
|
1181
1448
|
const sorted = this.topologicalSort(rules);
|
|
1182
1449
|
const outcomes = {};
|
|
@@ -1185,25 +1452,32 @@ class AXMQuestionnaireViewerService {
|
|
|
1185
1452
|
if (rule.name) {
|
|
1186
1453
|
outcomeTitles[rule.name] = this.resolveOutcomeDisplayTitle(rule);
|
|
1187
1454
|
}
|
|
1188
|
-
const value = await this.computeResult(rule, answers, outcomes, structure);
|
|
1455
|
+
const value = await this.computeResult(rule, answers, outcomes, options?.structure);
|
|
1189
1456
|
if (rule.name && value !== undefined)
|
|
1190
1457
|
outcomes[rule.name] = value;
|
|
1191
1458
|
}
|
|
1192
1459
|
return { values: outcomes, outcomeTitles };
|
|
1193
1460
|
}
|
|
1194
1461
|
/**
|
|
1195
|
-
* Progress metrics and optional
|
|
1462
|
+
* Progress metrics and optional outcome results for summary / preview.
|
|
1196
1463
|
*/
|
|
1197
1464
|
async buildSummaryPlaceholderValues(structure, answers, options) {
|
|
1198
1465
|
const { answeredQuestionsCount } = this.calculateProgressFromStructure(structure, answers);
|
|
1199
1466
|
const totalQuestions = structure?.sections?.reduce((s, sec) => s + (sec.items?.length ?? 0), 0) ?? 0;
|
|
1200
1467
|
let outcomes;
|
|
1201
1468
|
let outcomeTitles;
|
|
1202
|
-
|
|
1203
|
-
|
|
1469
|
+
let outcomeSections;
|
|
1470
|
+
if (options?.outcomeRules?.length || options?.questionnaireId) {
|
|
1471
|
+
const { values: evaluated, outcomeTitles: titles } = await this.evaluateOutcomes(answers, {
|
|
1472
|
+
questionnaireId: options?.questionnaireId,
|
|
1473
|
+
outcomeRules: options?.outcomeRules,
|
|
1474
|
+
structure,
|
|
1475
|
+
});
|
|
1204
1476
|
if (Object.keys(evaluated).length > 0) {
|
|
1205
1477
|
outcomes = evaluated;
|
|
1206
1478
|
outcomeTitles = titles;
|
|
1479
|
+
const sections = await this.resolveOutcomeSections(options?.questionnaireId, options?.outcomeRules);
|
|
1480
|
+
outcomeSections = this.buildOutcomeResultSections(sections, evaluated, titles);
|
|
1207
1481
|
}
|
|
1208
1482
|
}
|
|
1209
1483
|
const elapsed = options?.elapsedSeconds;
|
|
@@ -1215,6 +1489,30 @@ class AXMQuestionnaireViewerService {
|
|
|
1215
1489
|
totalTimeFormatted,
|
|
1216
1490
|
outcomes,
|
|
1217
1491
|
outcomeTitles,
|
|
1492
|
+
outcomeSections,
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Builds outcome section rows from stored session values (no expression re-evaluation).
|
|
1497
|
+
*/
|
|
1498
|
+
async buildOutcomeResultsFromStoredValues(storedOutcomes, options) {
|
|
1499
|
+
const keys = Object.keys(storedOutcomes);
|
|
1500
|
+
if (!keys.length) {
|
|
1501
|
+
return { outcomes: {}, outcomeTitles: {}, outcomeSections: [] };
|
|
1502
|
+
}
|
|
1503
|
+
const rules = await this.resolveOutcomeRules(options.questionnaireId, undefined);
|
|
1504
|
+
const outcomeTitles = {};
|
|
1505
|
+
for (const rule of rules) {
|
|
1506
|
+
if (rule.name) {
|
|
1507
|
+
outcomeTitles[rule.name] = this.resolveOutcomeDisplayTitle(rule);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const sections = await this.resolveOutcomeSections(options.questionnaireId, undefined);
|
|
1511
|
+
const outcomeSections = this.buildOutcomeResultSections(sections, storedOutcomes, outcomeTitles);
|
|
1512
|
+
return {
|
|
1513
|
+
outcomes: storedOutcomes,
|
|
1514
|
+
outcomeTitles,
|
|
1515
|
+
outcomeSections,
|
|
1218
1516
|
};
|
|
1219
1517
|
}
|
|
1220
1518
|
//#endregion
|
|
@@ -1246,38 +1544,100 @@ class AXMQuestionnaireViewerService {
|
|
|
1246
1544
|
return { answeredQuestionsCount: answered, progressPercentage };
|
|
1247
1545
|
}
|
|
1248
1546
|
//#endregion
|
|
1249
|
-
//#region ---- Questionnaire
|
|
1250
|
-
async
|
|
1251
|
-
|
|
1252
|
-
|
|
1547
|
+
//#region ---- Questionnaire outcomes (evaluation) ----
|
|
1548
|
+
async resolveOutcomeRules(questionnaireId, inlineRules) {
|
|
1549
|
+
if (inlineRules?.length) {
|
|
1550
|
+
return inlineRules;
|
|
1551
|
+
}
|
|
1552
|
+
if (!questionnaireId) {
|
|
1553
|
+
return [];
|
|
1554
|
+
}
|
|
1555
|
+
const questionnaire = await this.loadQuestionnaire(questionnaireId);
|
|
1556
|
+
return flattenQuestionnaireOutcomeItems(questionnaire?.outcomes);
|
|
1557
|
+
}
|
|
1558
|
+
async resolveOutcomeSections(questionnaireId, inlineRules) {
|
|
1559
|
+
if (inlineRules?.length) {
|
|
1560
|
+
return [{ name: 'outcomes', order: 0, items: inlineRules }];
|
|
1561
|
+
}
|
|
1562
|
+
if (!questionnaireId) {
|
|
1563
|
+
return [];
|
|
1564
|
+
}
|
|
1565
|
+
const questionnaire = await this.loadQuestionnaire(questionnaireId);
|
|
1566
|
+
return normalizeQuestionnaireOutcomesValue(questionnaire?.outcomes).sections;
|
|
1567
|
+
}
|
|
1568
|
+
async loadQuestionnaire(questionnaireId) {
|
|
1569
|
+
return this.entityService
|
|
1570
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.questionnaire.name)
|
|
1253
1571
|
.data()
|
|
1254
|
-
.
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1572
|
+
.byKey(questionnaireId);
|
|
1573
|
+
}
|
|
1574
|
+
buildOutcomeResultSections(sections, values, titles) {
|
|
1575
|
+
const sortedSections = sections.slice().sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
1576
|
+
const groups = [];
|
|
1577
|
+
for (const [index, section] of sortedSections.entries()) {
|
|
1578
|
+
const sectionName = (section.name ?? '').trim() || `section-${index + 1}`;
|
|
1579
|
+
const sectionOrder = section.order ?? index;
|
|
1580
|
+
const items = [];
|
|
1581
|
+
for (const item of section.items ?? []) {
|
|
1582
|
+
if (!item.name || values[item.name] === undefined) {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
const value = values[item.name];
|
|
1586
|
+
const display = this.resolveOutcomeDisplay(item, value);
|
|
1587
|
+
items.push({
|
|
1588
|
+
key: item.name,
|
|
1589
|
+
value,
|
|
1590
|
+
label: (titles[item.name] ?? '').trim() || this.humanizeOutcomeKey(item.name),
|
|
1591
|
+
display,
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
if (items.length === 0) {
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
groups.push({
|
|
1598
|
+
trackKey: `${sectionOrder}::${sectionName}`,
|
|
1599
|
+
sectionName,
|
|
1600
|
+
sectionOrder,
|
|
1601
|
+
sectionTitle: section.title ?? { 'en-US': sectionName },
|
|
1602
|
+
sectionDescription: section.description,
|
|
1603
|
+
items,
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
return groups;
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* First matching display rule for an evaluated outcome value.
|
|
1610
|
+
*/
|
|
1611
|
+
resolveOutcomeDisplay(rule, value) {
|
|
1612
|
+
const displayRules = normalizeQuestionnaireOutcomeDisplayRules(rule.displayRules);
|
|
1613
|
+
if (!displayRules.length) {
|
|
1614
|
+
return undefined;
|
|
1615
|
+
}
|
|
1616
|
+
for (const displayRule of displayRules) {
|
|
1617
|
+
if (matchesQuestionnaireOutcomeDisplayRule(value, displayRule)) {
|
|
1618
|
+
return {
|
|
1619
|
+
color: displayRule.color,
|
|
1620
|
+
emphasis: displayRule.emphasis ?? 'normal',
|
|
1621
|
+
iconClass: typeof displayRule.icon === 'string' ? displayRule.icon : undefined,
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return undefined;
|
|
1264
1626
|
}
|
|
1265
1627
|
/**
|
|
1266
|
-
* Display label for
|
|
1628
|
+
* Display label for an outcome rule: `title` when set, otherwise a humanized `name`.
|
|
1267
1629
|
*/
|
|
1268
1630
|
resolveOutcomeDisplayTitle(rule) {
|
|
1269
|
-
const
|
|
1270
|
-
if (
|
|
1271
|
-
|
|
1272
|
-
if (t.length > 0)
|
|
1273
|
-
return t;
|
|
1631
|
+
const resolved = resolveMultiLanguageString(rule.title, 'en-US').trim();
|
|
1632
|
+
if (resolved.length > 0) {
|
|
1633
|
+
return resolved;
|
|
1274
1634
|
}
|
|
1275
1635
|
const name = rule.name?.trim();
|
|
1276
1636
|
if (name)
|
|
1277
|
-
return this.
|
|
1637
|
+
return this.humanizeOutcomeKey(name);
|
|
1278
1638
|
return '';
|
|
1279
1639
|
}
|
|
1280
|
-
|
|
1640
|
+
humanizeOutcomeKey(name) {
|
|
1281
1641
|
return name
|
|
1282
1642
|
.replace(/_/g, ' ')
|
|
1283
1643
|
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
@@ -1287,14 +1647,14 @@ class AXMQuestionnaireViewerService {
|
|
|
1287
1647
|
.join(' ');
|
|
1288
1648
|
}
|
|
1289
1649
|
async computeResult(rule, answers, outcomes, structure) {
|
|
1290
|
-
const exprText = this.
|
|
1650
|
+
const exprText = this.outcomeExpressionText(rule);
|
|
1291
1651
|
if (!exprText)
|
|
1292
1652
|
return undefined;
|
|
1293
1653
|
const raw = await this.evaluateOutcomeExpression(exprText, answers, outcomes, structure);
|
|
1294
1654
|
return this.coerceOutcome(raw, this.inferResultKind(rule));
|
|
1295
1655
|
}
|
|
1296
1656
|
/** Non-empty trimmed `expression`, or empty string if missing. */
|
|
1297
|
-
|
|
1657
|
+
outcomeExpressionText(rule) {
|
|
1298
1658
|
const exp = rule.expression;
|
|
1299
1659
|
return typeof exp === 'string' ? exp.trim() : '';
|
|
1300
1660
|
}
|
|
@@ -1332,17 +1692,17 @@ class AXMQuestionnaireViewerService {
|
|
|
1332
1692
|
return raw;
|
|
1333
1693
|
}
|
|
1334
1694
|
}
|
|
1335
|
-
async evaluateOutcomeExpression(expression, answers, outcomes, structure) {
|
|
1695
|
+
async evaluateOutcomeExpression(expression, answers, outcomes, structure, value) {
|
|
1336
1696
|
const trimmed = expression?.trim();
|
|
1337
1697
|
if (!trimmed)
|
|
1338
1698
|
return undefined;
|
|
1339
1699
|
try {
|
|
1340
|
-
const scope = this.buildExpressionScope(answers, outcomes, structure);
|
|
1700
|
+
const scope = this.buildExpressionScope(answers, outcomes, structure, value);
|
|
1341
1701
|
const wrapped = trimmed.includes('{{') ? trimmed : `{{ ${trimmed} }}`;
|
|
1342
1702
|
return await this.expressionEvaluator.evaluate(wrapped, scope);
|
|
1343
1703
|
}
|
|
1344
1704
|
catch (err) {
|
|
1345
|
-
console.warn('[QuestionnaireViewer]
|
|
1705
|
+
console.warn('[QuestionnaireViewer] Outcome expression evaluation failed:', expression, err);
|
|
1346
1706
|
return undefined;
|
|
1347
1707
|
}
|
|
1348
1708
|
}
|
|
@@ -1376,7 +1736,7 @@ class AXMQuestionnaireViewerService {
|
|
|
1376
1736
|
/**
|
|
1377
1737
|
* Scope: answer.eval (path), answer.byId / byTag / allByTag, formula.eval / outcome.eval, fn.* helpers.
|
|
1378
1738
|
*/
|
|
1379
|
-
buildExpressionScope(answers, outcomes, structure) {
|
|
1739
|
+
buildExpressionScope(answers, outcomes, structure, value) {
|
|
1380
1740
|
const resolveOutcome = (key) => outcomes[key];
|
|
1381
1741
|
const itemsOrdered = this.flattenQuestionnaireItems(structure ?? null);
|
|
1382
1742
|
const itemHasTag = (item, normalizedTag) => {
|
|
@@ -1472,6 +1832,7 @@ class AXMQuestionnaireViewerService {
|
|
|
1472
1832
|
formula: { eval: resolveOutcome },
|
|
1473
1833
|
outcome: { eval: resolveOutcome },
|
|
1474
1834
|
fn,
|
|
1835
|
+
...(value !== undefined ? { value } : {}),
|
|
1475
1836
|
};
|
|
1476
1837
|
}
|
|
1477
1838
|
expressionOutcomeRefs(expression, ruleNames) {
|
|
@@ -1513,7 +1874,7 @@ class AXMQuestionnaireViewerService {
|
|
|
1513
1874
|
visiting.add(name);
|
|
1514
1875
|
const rule = nameToRule.get(name);
|
|
1515
1876
|
if (rule) {
|
|
1516
|
-
const exprStr = this.
|
|
1877
|
+
const exprStr = this.outcomeExpressionText(rule);
|
|
1517
1878
|
const formDeps = this.expressionOutcomeRefs(exprStr, ruleNames);
|
|
1518
1879
|
for (const d of formDeps)
|
|
1519
1880
|
visit(d);
|
|
@@ -1531,13 +1892,2774 @@ class AXMQuestionnaireViewerService {
|
|
|
1531
1892
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1532
1893
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerService, providedIn: 'root' }); }
|
|
1533
1894
|
}
|
|
1534
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerService, decorators: [{
|
|
1535
|
-
type: Injectable,
|
|
1895
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerService, decorators: [{
|
|
1896
|
+
type: Injectable,
|
|
1897
|
+
args: [{
|
|
1898
|
+
providedIn: 'root',
|
|
1899
|
+
}]
|
|
1900
|
+
}] });
|
|
1901
|
+
|
|
1902
|
+
//#region ---- Imports ----
|
|
1903
|
+
//#endregion
|
|
1904
|
+
//#region ---- Groups ----
|
|
1905
|
+
const GROUP_IDENTITY = {
|
|
1906
|
+
name: 'identity',
|
|
1907
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.groups.identity.title',
|
|
1908
|
+
order: 0,
|
|
1909
|
+
};
|
|
1910
|
+
const GROUP_VALIDATION = {
|
|
1911
|
+
name: 'validation',
|
|
1912
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.groups.validation.title',
|
|
1913
|
+
order: 1,
|
|
1914
|
+
};
|
|
1915
|
+
const GROUP_VISIBILITY = {
|
|
1916
|
+
name: 'visibility',
|
|
1917
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.groups.visibility.title',
|
|
1918
|
+
order: 2,
|
|
1919
|
+
};
|
|
1920
|
+
const GROUP_HINT = {
|
|
1921
|
+
name: 'hint',
|
|
1922
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.groups.hint.title',
|
|
1923
|
+
order: 3,
|
|
1924
|
+
};
|
|
1925
|
+
const GROUP_COMMENT = {
|
|
1926
|
+
name: 'comment',
|
|
1927
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.groups.comment.title',
|
|
1928
|
+
order: 4,
|
|
1929
|
+
};
|
|
1930
|
+
//#endregion
|
|
1931
|
+
//#region ---- Shared options ----
|
|
1932
|
+
const HINT_MODE_OPTIONS = [
|
|
1933
|
+
{
|
|
1934
|
+
id: 'off',
|
|
1935
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.off',
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
id: 'info',
|
|
1939
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.info',
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: 'warning',
|
|
1943
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.warning',
|
|
1944
|
+
},
|
|
1945
|
+
{
|
|
1946
|
+
id: 'danger',
|
|
1947
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.danger',
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
id: 'success',
|
|
1951
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.success',
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
id: 'neutral',
|
|
1955
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.options.neutral',
|
|
1956
|
+
},
|
|
1957
|
+
];
|
|
1958
|
+
//#endregion
|
|
1959
|
+
//#region ---- Properties by group ----
|
|
1960
|
+
const IDENTITY_PROPS = [
|
|
1961
|
+
{
|
|
1962
|
+
name: 'name',
|
|
1963
|
+
title: '@general:terms.common.name',
|
|
1964
|
+
group: GROUP_IDENTITY,
|
|
1965
|
+
order: 10,
|
|
1966
|
+
schema: {
|
|
1967
|
+
dataType: 'string',
|
|
1968
|
+
defaultValue: '',
|
|
1969
|
+
interface: {
|
|
1970
|
+
name: 'name',
|
|
1971
|
+
path: 'name',
|
|
1972
|
+
type: AXPWidgetsCatalog.text,
|
|
1973
|
+
options: {
|
|
1974
|
+
placeholder: '@general:terms.common.name',
|
|
1975
|
+
},
|
|
1976
|
+
},
|
|
1977
|
+
},
|
|
1978
|
+
visible: true,
|
|
1979
|
+
},
|
|
1980
|
+
{
|
|
1981
|
+
name: 'tags',
|
|
1982
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.tags.title',
|
|
1983
|
+
group: GROUP_IDENTITY,
|
|
1984
|
+
order: 20,
|
|
1985
|
+
schema: {
|
|
1986
|
+
dataType: 'array',
|
|
1987
|
+
defaultValue: [],
|
|
1988
|
+
interface: {
|
|
1989
|
+
name: 'tags',
|
|
1990
|
+
path: 'tags',
|
|
1991
|
+
type: 'tag-editor',
|
|
1992
|
+
options: {
|
|
1993
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-builder.fields.tags.placeholder',
|
|
1994
|
+
allowDuplicate: false,
|
|
1995
|
+
},
|
|
1996
|
+
},
|
|
1997
|
+
},
|
|
1998
|
+
visible: true,
|
|
1999
|
+
},
|
|
2000
|
+
];
|
|
2001
|
+
const VALIDATION_PROPS = [
|
|
2002
|
+
{
|
|
2003
|
+
...createBooleanProperty({
|
|
2004
|
+
name: 'isRequired',
|
|
2005
|
+
path: 'isRequired',
|
|
2006
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.is-required.title',
|
|
2007
|
+
group: GROUP_VALIDATION,
|
|
2008
|
+
defaultValue: false,
|
|
2009
|
+
}),
|
|
2010
|
+
order: 10,
|
|
2011
|
+
},
|
|
2012
|
+
];
|
|
2013
|
+
const VISIBILITY_PROPS = [
|
|
2014
|
+
{
|
|
2015
|
+
...createBooleanProperty({
|
|
2016
|
+
name: 'isVisible',
|
|
2017
|
+
path: 'isVisible',
|
|
2018
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.visible.title',
|
|
2019
|
+
group: GROUP_VISIBILITY,
|
|
2020
|
+
defaultValue: true,
|
|
2021
|
+
}),
|
|
2022
|
+
order: 10,
|
|
2023
|
+
},
|
|
2024
|
+
];
|
|
2025
|
+
const HINT_PROPS = [
|
|
2026
|
+
{
|
|
2027
|
+
name: 'hintMode',
|
|
2028
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint-mode.title',
|
|
2029
|
+
group: GROUP_HINT,
|
|
2030
|
+
order: 10,
|
|
2031
|
+
schema: {
|
|
2032
|
+
dataType: 'string',
|
|
2033
|
+
defaultValue: { id: 'off', title: HINT_MODE_OPTIONS[0].title },
|
|
2034
|
+
interface: {
|
|
2035
|
+
name: 'hintMode',
|
|
2036
|
+
path: 'hint.mode',
|
|
2037
|
+
type: AXPWidgetsCatalog.select,
|
|
2038
|
+
options: {
|
|
2039
|
+
valueField: 'id',
|
|
2040
|
+
textField: 'title',
|
|
2041
|
+
dataSource: [...HINT_MODE_OPTIONS],
|
|
2042
|
+
},
|
|
2043
|
+
},
|
|
2044
|
+
},
|
|
2045
|
+
visible: true,
|
|
2046
|
+
},
|
|
2047
|
+
{
|
|
2048
|
+
name: 'hintContent',
|
|
2049
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.hint.title',
|
|
2050
|
+
group: GROUP_HINT,
|
|
2051
|
+
order: 20,
|
|
2052
|
+
schema: {
|
|
2053
|
+
dataType: 'string',
|
|
2054
|
+
defaultValue: '',
|
|
2055
|
+
interface: {
|
|
2056
|
+
name: 'hintContent',
|
|
2057
|
+
path: 'hint.content',
|
|
2058
|
+
type: AXPWidgetsCatalog.richText,
|
|
2059
|
+
options: {},
|
|
2060
|
+
},
|
|
2061
|
+
},
|
|
2062
|
+
visible: "{{ context.eval('hint.mode') && (context.eval('hint.mode').id || context.eval('hint.mode')) != 'off' }}",
|
|
2063
|
+
},
|
|
2064
|
+
];
|
|
2065
|
+
const COMMENT_PROPS = [
|
|
2066
|
+
{
|
|
2067
|
+
...createBooleanProperty({
|
|
2068
|
+
name: 'commentEnabled',
|
|
2069
|
+
path: 'comment.enabled',
|
|
2070
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.comment-enabled.title',
|
|
2071
|
+
group: GROUP_COMMENT,
|
|
2072
|
+
defaultValue: false,
|
|
2073
|
+
}),
|
|
2074
|
+
order: 10,
|
|
2075
|
+
},
|
|
2076
|
+
{
|
|
2077
|
+
...createBooleanProperty({
|
|
2078
|
+
name: 'commentRequired',
|
|
2079
|
+
path: 'comment.required',
|
|
2080
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.fields.comment-required.title',
|
|
2081
|
+
group: GROUP_COMMENT,
|
|
2082
|
+
defaultValue: false,
|
|
2083
|
+
visible: "{{ context.eval('comment.enabled') === true }}",
|
|
2084
|
+
}),
|
|
2085
|
+
order: 20,
|
|
2086
|
+
},
|
|
2087
|
+
];
|
|
2088
|
+
//#endregion
|
|
2089
|
+
//#region ---- Hint form context helper ----
|
|
2090
|
+
/**
|
|
2091
|
+
* Builds initial `hint` object for the question property viewer from the effective (merged) hint config.
|
|
2092
|
+
*/
|
|
2093
|
+
function createQuestionHintFormContext(hint) {
|
|
2094
|
+
let content = '';
|
|
2095
|
+
if (hint.mode !== 'off') {
|
|
2096
|
+
const hc = hint.content;
|
|
2097
|
+
if (typeof hc === 'string') {
|
|
2098
|
+
content = hc;
|
|
2099
|
+
}
|
|
2100
|
+
else if (hc && typeof hc === 'object') {
|
|
2101
|
+
content = Object.values(hc)[0] ?? '';
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
const modeId = hint.mode;
|
|
2105
|
+
const opt = HINT_MODE_OPTIONS.find((o) => o.id === modeId) ?? HINT_MODE_OPTIONS[0];
|
|
2106
|
+
return {
|
|
2107
|
+
content,
|
|
2108
|
+
mode: { id: opt.id, title: opt.title },
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
//#endregion
|
|
2112
|
+
//#region ---- Tab definition ----
|
|
2113
|
+
/**
|
|
2114
|
+
* Property viewer tabs for editing a single questionnaire question row (metadata).
|
|
2115
|
+
*/
|
|
2116
|
+
const QUESTIONNAIRE_QUESTION_EDIT_TABS = [
|
|
2117
|
+
{
|
|
2118
|
+
name: 'general',
|
|
2119
|
+
title: '@assessment-management:questionnaires.components.questionnaire-builder.tabs.general.title',
|
|
2120
|
+
groups: [
|
|
2121
|
+
{
|
|
2122
|
+
name: GROUP_IDENTITY.name,
|
|
2123
|
+
title: GROUP_IDENTITY.title,
|
|
2124
|
+
isCollapsed: false,
|
|
2125
|
+
props: IDENTITY_PROPS,
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
name: GROUP_VALIDATION.name,
|
|
2129
|
+
title: GROUP_VALIDATION.title,
|
|
2130
|
+
isCollapsed: false,
|
|
2131
|
+
props: VALIDATION_PROPS,
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
name: GROUP_VISIBILITY.name,
|
|
2135
|
+
title: GROUP_VISIBILITY.title,
|
|
2136
|
+
isCollapsed: false,
|
|
2137
|
+
props: VISIBILITY_PROPS,
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
name: GROUP_HINT.name,
|
|
2141
|
+
title: GROUP_HINT.title,
|
|
2142
|
+
isCollapsed: false,
|
|
2143
|
+
props: HINT_PROPS,
|
|
2144
|
+
},
|
|
2145
|
+
{
|
|
2146
|
+
name: GROUP_COMMENT.name,
|
|
2147
|
+
title: GROUP_COMMENT.title,
|
|
2148
|
+
isCollapsed: false,
|
|
2149
|
+
props: COMMENT_PROPS,
|
|
2150
|
+
},
|
|
2151
|
+
],
|
|
2152
|
+
},
|
|
2153
|
+
];
|
|
2154
|
+
//#endregion
|
|
2155
|
+
|
|
2156
|
+
//#region ---- Imports ----
|
|
2157
|
+
//#endregion
|
|
2158
|
+
//#region ---- Component ----
|
|
2159
|
+
/**
|
|
2160
|
+
* Reusable Questionnaire Builder Component
|
|
2161
|
+
* Can be used both in dialog and inline contexts
|
|
2162
|
+
*/
|
|
2163
|
+
class AXMQuestionnaireQuestionsBuilderComponent {
|
|
2164
|
+
//#endregion
|
|
2165
|
+
//#region ---- Question bank entity data ----
|
|
2166
|
+
questionBankData() {
|
|
2167
|
+
return this.entityService
|
|
2168
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.questionBankItem.name)
|
|
2169
|
+
.data();
|
|
2170
|
+
}
|
|
2171
|
+
questionBankCategoryData() {
|
|
2172
|
+
return this.entityService
|
|
2173
|
+
.withEntity(RootConfig.module.name, `${RootConfig.entities.questionBankItem.name}Category`)
|
|
2174
|
+
.data();
|
|
2175
|
+
}
|
|
2176
|
+
//#endregion
|
|
2177
|
+
//#region ---- Lifecycle ----
|
|
2178
|
+
constructor() {
|
|
2179
|
+
//#region ---- Services & Dependencies ----
|
|
2180
|
+
this.dataSelectorService = inject(AXPDataSelectorService);
|
|
2181
|
+
this.entityService = inject(AXPEntityService);
|
|
2182
|
+
this.entityResolver = inject(AXPEntityDefinitionRegistryService);
|
|
2183
|
+
this.translationService = inject(AXTranslationService);
|
|
2184
|
+
this.propertyViewerService = inject(AXPPropertyViewerService);
|
|
2185
|
+
this.questionnaireViewerService = inject(AXMQuestionnaireViewerService);
|
|
2186
|
+
this.toastService = inject(AXToastService);
|
|
2187
|
+
this.widgetRegistry = inject(AXPWidgetRegistryService);
|
|
2188
|
+
this.commandService = inject(AXPCommandService);
|
|
2189
|
+
//#endregion
|
|
2190
|
+
//#region ---- Inputs & Outputs ----
|
|
2191
|
+
/**
|
|
2192
|
+
* Initial value (QuestionnaireBuilderValue)
|
|
2193
|
+
*/
|
|
2194
|
+
this.value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
2195
|
+
/**
|
|
2196
|
+
* Readonly mode
|
|
2197
|
+
*/
|
|
2198
|
+
this.readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
2199
|
+
/**
|
|
2200
|
+
* Pre/post config for preview (welcome, review, summary).
|
|
2201
|
+
* When provided, passed to the preview dialog.
|
|
2202
|
+
*/
|
|
2203
|
+
this.prePostConfig = input(null, ...(ngDevMode ? [{ debugName: "prePostConfig" }] : /* istanbul ignore next */ []));
|
|
2204
|
+
/**
|
|
2205
|
+
* When false, the header (Add Section, Settings, Preview, Full Screen) is hidden.
|
|
2206
|
+
* Use when actions are provided by the host (e.g. page primary header actions).
|
|
2207
|
+
*/
|
|
2208
|
+
this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
|
|
2209
|
+
/**
|
|
2210
|
+
* Display settings (view mode, progress bar, timer, etc.) when provided by the host (e.g. entity form).
|
|
2211
|
+
* Used for preview. When not provided, falls back to state/value or defaults.
|
|
2212
|
+
*/
|
|
2213
|
+
this.displaySettingsInput = input(null, ...(ngDevMode ? [{ debugName: "displaySettingsInput" }] : /* istanbul ignore next */ []));
|
|
2214
|
+
/**
|
|
2215
|
+
* Persisted questionnaire id (e.g. from entity form) — enables questionnaire outcomes in preview.
|
|
2216
|
+
*/
|
|
2217
|
+
this.questionnaireEntityId = input(undefined, ...(ngDevMode ? [{ debugName: "questionnaireEntityId" }] : /* istanbul ignore next */ []));
|
|
2218
|
+
/**
|
|
2219
|
+
* Value change event
|
|
2220
|
+
*/
|
|
2221
|
+
this.valueChange = output();
|
|
2222
|
+
//#endregion
|
|
2223
|
+
//#region ---- Class Properties ----
|
|
2224
|
+
// Designer state management - always start with at least one default section
|
|
2225
|
+
this.builderState = signal({
|
|
2226
|
+
sections: [createDefaultSection()],
|
|
2227
|
+
}, ...(ngDevMode ? [{ debugName: "builderState" }] : /* istanbul ignore next */ []));
|
|
2228
|
+
// Selected item tracking
|
|
2229
|
+
this.selectedItemName = signal(null, ...(ngDevMode ? [{ debugName: "selectedItemName" }] : /* istanbul ignore next */ []));
|
|
2230
|
+
this.selectedSectionName = signal(null, ...(ngDevMode ? [{ debugName: "selectedSectionName" }] : /* istanbul ignore next */ []));
|
|
2231
|
+
// Fullscreen directive reference
|
|
2232
|
+
this.fullscreenDirective = viewChild('fullscreen', ...(ngDevMode ? [{ debugName: "fullscreenDirective" }] : /* istanbul ignore next */ []));
|
|
2233
|
+
this.standardRef = viewChild(AXPStandardSectionItemsBuilderComponent, ...(ngDevMode ? [{ debugName: "standardRef" }] : /* istanbul ignore next */ []));
|
|
2234
|
+
//#endregion
|
|
2235
|
+
//#region ---- Computed Properties ----
|
|
2236
|
+
/** Value for {@link AXPStandardSectionItemsBuilderComponent} (sections only; drag/reorder handled there). */
|
|
2237
|
+
this.builderValue = computed(() => ({
|
|
2238
|
+
sections: this.builderState().sections.map((s) => ({
|
|
2239
|
+
id: s.name,
|
|
2240
|
+
name: s.name,
|
|
2241
|
+
order: s.order,
|
|
2242
|
+
title: s.title,
|
|
2243
|
+
description: s.description,
|
|
2244
|
+
tags: s.tags,
|
|
2245
|
+
isVisible: s.isVisible,
|
|
2246
|
+
items: s.items.map((it) => ({
|
|
2247
|
+
id: it.name,
|
|
2248
|
+
name: it.name,
|
|
2249
|
+
order: it.order,
|
|
2250
|
+
questionBankItemId: it.questionBankItemId,
|
|
2251
|
+
isRequired: it.isRequired,
|
|
2252
|
+
isVisible: it.isVisible,
|
|
2253
|
+
interfaceOverride: it.interfaceOverride,
|
|
2254
|
+
hint: it.hint,
|
|
2255
|
+
comment: it.comment,
|
|
2256
|
+
tags: it.tags,
|
|
2257
|
+
question: it.question,
|
|
2258
|
+
isNewlyAdded: it.isNewlyAdded,
|
|
2259
|
+
})),
|
|
2260
|
+
})),
|
|
2261
|
+
}), ...(ngDevMode ? [{ debugName: "builderValue" }] : /* istanbul ignore next */ []));
|
|
2262
|
+
this.isPreviewDisabled = computed(() => this.builderState().sections.length === 0 || this.builderState().sections.every((s) => s.items.length === 0), ...(ngDevMode ? [{ debugName: "isPreviewDisabled" }] : /* istanbul ignore next */ []));
|
|
2263
|
+
this.standardConfig = computed(() => ({
|
|
2264
|
+
showSectionTechnicalName: true,
|
|
2265
|
+
minSectionCount: 1,
|
|
2266
|
+
texts: {
|
|
2267
|
+
addSection: '@assessment-management:questionnaires.components.questionnaire-builder.actions.add-section.title',
|
|
2268
|
+
addItem: '@assessment-management:questionnaires.components.questionnaire-builder.actions.add-question.title',
|
|
2269
|
+
emptySectionsTitle: '@assessment-management:questionnaires.components.questionnaire-builder.empty-states.no-sections.title',
|
|
2270
|
+
emptySectionsDescription: '@assessment-management:questionnaires.components.questionnaire-builder.empty-states.no-sections.description',
|
|
2271
|
+
emptyItemsTitle: '@assessment-management:questionnaires.components.questionnaire-builder.empty-states.empty-section.title',
|
|
2272
|
+
emptyItemsDescription: '@assessment-management:questionnaires.components.questionnaire-builder.empty-states.empty-section.description',
|
|
2273
|
+
defaultSectionBadge: '@assessment-management:questionnaires.components.questionnaire-builder.default-section-badge',
|
|
2274
|
+
},
|
|
2275
|
+
mapItemToView: (item, section) => this.mapQuestionnaireItemToView(item, section),
|
|
2276
|
+
promptAddItems: (sid, v) => this.questionnairePromptAddItems(sid, v),
|
|
2277
|
+
promptEditItem: (item, sid, v) => this.questionnairePromptEditItem(item, sid, v),
|
|
2278
|
+
}), ...(ngDevMode ? [{ debugName: "standardConfig" }] : /* istanbul ignore next */ []));
|
|
2279
|
+
/**
|
|
2280
|
+
* Get current display settings from state or default
|
|
2281
|
+
*/
|
|
2282
|
+
this.displaySettings = computed(() => {
|
|
2283
|
+
const fromInput = this.displaySettingsInput();
|
|
2284
|
+
if (fromInput != null) {
|
|
2285
|
+
return fromInput;
|
|
2286
|
+
}
|
|
2287
|
+
const state = this.builderState();
|
|
2288
|
+
if (state.displaySettings) {
|
|
2289
|
+
return state.displaySettings;
|
|
2290
|
+
}
|
|
2291
|
+
const currentValue = convertStateToValue(state, this.value() || undefined);
|
|
2292
|
+
return (currentValue.displaySettings || {
|
|
2293
|
+
viewMode: 'single-page',
|
|
2294
|
+
showProgressBar: true,
|
|
2295
|
+
showTimer: false,
|
|
2296
|
+
showQuestionNumbers: true,
|
|
2297
|
+
});
|
|
2298
|
+
}, ...(ngDevMode ? [{ debugName: "displaySettings" }] : /* istanbul ignore next */ []));
|
|
2299
|
+
// Track last emitted value to prevent circular updates
|
|
2300
|
+
let lastEmittedValue = null;
|
|
2301
|
+
// Sync value input to state (only when value changes externally)
|
|
2302
|
+
effect(() => {
|
|
2303
|
+
const val = this.value();
|
|
2304
|
+
if (val !== null && val !== undefined) {
|
|
2305
|
+
const currentState = untracked(() => this.builderState());
|
|
2306
|
+
const currentValue = convertStateToValue(currentState);
|
|
2307
|
+
const valStr = JSON.stringify(val);
|
|
2308
|
+
const currentStr = JSON.stringify(currentValue);
|
|
2309
|
+
const lastEmittedStr = lastEmittedValue ? JSON.stringify(lastEmittedValue) : null;
|
|
2310
|
+
if (valStr !== currentStr && valStr !== lastEmittedStr) {
|
|
2311
|
+
const newState = convertValueToState(val);
|
|
2312
|
+
untracked(() => {
|
|
2313
|
+
this.builderState.set(newState);
|
|
2314
|
+
this.loadQuestionDetailsForState(newState);
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
else if (val === null || val === undefined) {
|
|
2319
|
+
// If value is null/undefined, ensure we have at least one default section
|
|
2320
|
+
const currentState = untracked(() => this.builderState());
|
|
2321
|
+
if (currentState.sections.length === 0) {
|
|
2322
|
+
const defaultSection = createDefaultSection();
|
|
2323
|
+
defaultSection.order = 0;
|
|
2324
|
+
untracked(() => {
|
|
2325
|
+
this.builderState.set({ sections: [defaultSection] });
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
});
|
|
2330
|
+
// Sync state changes to output
|
|
2331
|
+
effect(() => {
|
|
2332
|
+
const state = this.builderState();
|
|
2333
|
+
const currentValue = this.value();
|
|
2334
|
+
const value = convertStateToValue(state, currentValue || undefined);
|
|
2335
|
+
untracked(() => {
|
|
2336
|
+
lastEmittedValue = value;
|
|
2337
|
+
this.valueChange.emit(value);
|
|
2338
|
+
});
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Load question details for all items in the state
|
|
2343
|
+
*/
|
|
2344
|
+
async loadQuestionDetailsForState(state) {
|
|
2345
|
+
const questionIds = new Set();
|
|
2346
|
+
// Collect all question bank item IDs
|
|
2347
|
+
state.sections.forEach((section) => {
|
|
2348
|
+
section.items.forEach((item) => {
|
|
2349
|
+
if (item.questionBankItemId && !item.question) {
|
|
2350
|
+
questionIds.add(item.questionBankItemId);
|
|
2351
|
+
}
|
|
2352
|
+
});
|
|
2353
|
+
});
|
|
2354
|
+
if (questionIds.size === 0)
|
|
2355
|
+
return;
|
|
2356
|
+
// Load all questions in parallel
|
|
2357
|
+
const questionPromises = Array.from(questionIds).map((id) => this.questionBankData()
|
|
2358
|
+
.byKey(id)
|
|
2359
|
+
.catch(() => null));
|
|
2360
|
+
const questions = await Promise.all(questionPromises);
|
|
2361
|
+
// Create a map of question ID to question data
|
|
2362
|
+
const questionMap = new Map();
|
|
2363
|
+
questions.forEach((q) => {
|
|
2364
|
+
if (q) {
|
|
2365
|
+
questionMap.set(q.id, q);
|
|
2366
|
+
}
|
|
2367
|
+
});
|
|
2368
|
+
// Update state with question details
|
|
2369
|
+
this.builderState.update((currentState) => ({
|
|
2370
|
+
...currentState,
|
|
2371
|
+
sections: currentState.sections.map((section) => ({
|
|
2372
|
+
...section,
|
|
2373
|
+
items: section.items.map((item) => {
|
|
2374
|
+
if (item.question)
|
|
2375
|
+
return item; // Already has question data
|
|
2376
|
+
const questionData = questionMap.get(item.questionBankItemId);
|
|
2377
|
+
if (questionData) {
|
|
2378
|
+
return {
|
|
2379
|
+
...item,
|
|
2380
|
+
question: {
|
|
2381
|
+
id: questionData.id,
|
|
2382
|
+
title: questionData.title,
|
|
2383
|
+
question: questionData.question,
|
|
2384
|
+
note: questionData.note,
|
|
2385
|
+
difficulty: questionData.difficulty,
|
|
2386
|
+
interface: questionData.interface,
|
|
2387
|
+
},
|
|
2388
|
+
};
|
|
2389
|
+
}
|
|
2390
|
+
return item;
|
|
2391
|
+
}),
|
|
2392
|
+
})),
|
|
2393
|
+
}));
|
|
2394
|
+
}
|
|
2395
|
+
mapQuestionnaireItemToView(item, _section) {
|
|
2396
|
+
const q = item;
|
|
2397
|
+
const title = this.itemQuestionHeading(q);
|
|
2398
|
+
const note = this.itemQuestionNotePreview(q);
|
|
2399
|
+
const badges = [];
|
|
2400
|
+
const req = q.isRequired;
|
|
2401
|
+
const rawReq = typeof req === 'boolean' || typeof req === 'string' ? req : undefined;
|
|
2402
|
+
const requiredMode = getQuestionnaireItemRequiredBadgeMode(rawReq);
|
|
2403
|
+
if (requiredMode === 'required') {
|
|
2404
|
+
badges.push({
|
|
2405
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.required',
|
|
2406
|
+
variant: 'danger',
|
|
2407
|
+
});
|
|
2408
|
+
}
|
|
2409
|
+
else if (requiredMode === 'conditional') {
|
|
2410
|
+
badges.push({
|
|
2411
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.conditional-required',
|
|
2412
|
+
variant: 'warning',
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
else {
|
|
2416
|
+
badges.push({
|
|
2417
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.optional',
|
|
2418
|
+
variant: 'success',
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
const rawVis = q.isVisible;
|
|
2422
|
+
const visibilityMode = getQuestionnaireItemVisibilityBadgeMode(typeof rawVis === 'boolean' || typeof rawVis === 'string' ? rawVis : undefined);
|
|
2423
|
+
if (visibilityMode === 'hidden') {
|
|
2424
|
+
badges.push({
|
|
2425
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.visibility-hidden',
|
|
2426
|
+
variant: 'danger',
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
else if (visibilityMode === 'conditional') {
|
|
2430
|
+
badges.push({
|
|
2431
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.visibility-conditional',
|
|
2432
|
+
variant: 'warning',
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
else {
|
|
2436
|
+
badges.push({
|
|
2437
|
+
text: '@assessment-management:questionnaires.components.questionnaire-builder.item-badge.visibility-visible',
|
|
2438
|
+
variant: 'success',
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
return {
|
|
2442
|
+
icon: this.getQuestionWidgetIcon(q),
|
|
2443
|
+
title,
|
|
2444
|
+
name: q.name,
|
|
2445
|
+
description: note || undefined,
|
|
2446
|
+
badges,
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
/**
|
|
2450
|
+
* Standard section-items builder emits here. Uses direct `builderState.update` so the `valueChange`
|
|
2451
|
+
* effect runs in the same turn and hosts (e.g. questions page) can mark dirty.
|
|
2452
|
+
*/
|
|
2453
|
+
onBuilderValueChange(next) {
|
|
2454
|
+
this.builderState.update((state) => {
|
|
2455
|
+
const updatedState = {
|
|
2456
|
+
...state,
|
|
2457
|
+
sections: this.mergeSectionsFromStandardBuilder(next.sections, state.sections),
|
|
2458
|
+
};
|
|
2459
|
+
if (updatedState.sections.length === 0) {
|
|
2460
|
+
const defaultSection = createDefaultSection();
|
|
2461
|
+
defaultSection.order = 0;
|
|
2462
|
+
return { ...updatedState, sections: [defaultSection] };
|
|
2463
|
+
}
|
|
2464
|
+
return updatedState;
|
|
2465
|
+
});
|
|
2466
|
+
}
|
|
2467
|
+
mergeSectionsFromStandardBuilder(incoming, previous) {
|
|
2468
|
+
const prevByName = new Map(previous.map((s) => [s.name, s]));
|
|
2469
|
+
return incoming.map((sec) => {
|
|
2470
|
+
const axSec = sec;
|
|
2471
|
+
const incomingName = String(axSec['name'] ?? axSec['id'] ?? '').trim();
|
|
2472
|
+
const prevSec = prevByName.get(incomingName);
|
|
2473
|
+
if (!prevSec) {
|
|
2474
|
+
return this.normalizeIncomingSection(sec);
|
|
2475
|
+
}
|
|
2476
|
+
const prevItemByName = new Map(prevSec.items.map((i) => [i.name, i]));
|
|
2477
|
+
const merged = this.normalizeIncomingSection(sec);
|
|
2478
|
+
return {
|
|
2479
|
+
...merged,
|
|
2480
|
+
isNewlyAdded: prevSec.isNewlyAdded ?? merged.isNewlyAdded,
|
|
2481
|
+
items: merged.items.map((it) => {
|
|
2482
|
+
const prev = prevItemByName.get(it.name);
|
|
2483
|
+
if (!prev) {
|
|
2484
|
+
return it;
|
|
2485
|
+
}
|
|
2486
|
+
return {
|
|
2487
|
+
...prev,
|
|
2488
|
+
...it,
|
|
2489
|
+
question: it.question ?? prev.question,
|
|
2490
|
+
};
|
|
2491
|
+
}),
|
|
2492
|
+
};
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
/** Map platform section rows (id + name) into domain sections (name only). */
|
|
2496
|
+
normalizeIncomingSection(sec) {
|
|
2497
|
+
const ax = sec;
|
|
2498
|
+
const name = String(ax['name'] ?? ax['id'] ?? '').trim() || `section-${Date.now()}`;
|
|
2499
|
+
return {
|
|
2500
|
+
name,
|
|
2501
|
+
title: sec.title,
|
|
2502
|
+
description: sec.description,
|
|
2503
|
+
order: sec.order,
|
|
2504
|
+
tags: sec.tags,
|
|
2505
|
+
isVisible: sec.isVisible,
|
|
2506
|
+
isNewlyAdded: sec.isNewlyAdded,
|
|
2507
|
+
items: sec.items.map((it) => this.normalizeIncomingItem(it)),
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
normalizeIncomingItem(it) {
|
|
2511
|
+
const name = String(it['name'] ?? it['id'] ?? '').trim() || `item-${Date.now()}`;
|
|
2512
|
+
const qbi = it.questionBankItemId;
|
|
2513
|
+
return {
|
|
2514
|
+
name,
|
|
2515
|
+
questionBankItemId: qbi,
|
|
2516
|
+
order: it.order,
|
|
2517
|
+
isRequired: it.isRequired,
|
|
2518
|
+
isVisible: it.isVisible,
|
|
2519
|
+
interfaceOverride: it.interfaceOverride,
|
|
2520
|
+
hint: it.hint,
|
|
2521
|
+
comment: it.comment,
|
|
2522
|
+
tags: it.tags,
|
|
2523
|
+
question: it.question,
|
|
2524
|
+
isNewlyAdded: it.isNewlyAdded,
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
/** Edit dialog context: default visible; normalize legacy string booleans; expressions pass through (property viewer handles binding). */
|
|
2528
|
+
questionEditFormIsVisible(raw) {
|
|
2529
|
+
if (raw === undefined || raw === null) {
|
|
2530
|
+
return true;
|
|
2531
|
+
}
|
|
2532
|
+
if (typeof raw === 'boolean') {
|
|
2533
|
+
return raw;
|
|
2534
|
+
}
|
|
2535
|
+
if (raw.trim() === '') {
|
|
2536
|
+
return true;
|
|
2537
|
+
}
|
|
2538
|
+
const t = raw.trim().toLowerCase();
|
|
2539
|
+
if (t === 'true' || t === '1') {
|
|
2540
|
+
return true;
|
|
2541
|
+
}
|
|
2542
|
+
if (t === 'false' || t === '0') {
|
|
2543
|
+
return false;
|
|
2544
|
+
}
|
|
2545
|
+
return raw.trim();
|
|
2546
|
+
}
|
|
2547
|
+
questionEditFormIsRequired(item) {
|
|
2548
|
+
const r = item.isRequired;
|
|
2549
|
+
if (typeof r === 'string') {
|
|
2550
|
+
const t = r.trim();
|
|
2551
|
+
if (!t) {
|
|
2552
|
+
return false;
|
|
2553
|
+
}
|
|
2554
|
+
const tl = t.toLowerCase();
|
|
2555
|
+
if (tl === 'true' || tl === '1') {
|
|
2556
|
+
return true;
|
|
2557
|
+
}
|
|
2558
|
+
if (tl === 'false' || tl === '0') {
|
|
2559
|
+
return false;
|
|
2560
|
+
}
|
|
2561
|
+
return t;
|
|
2562
|
+
}
|
|
2563
|
+
return r ?? false;
|
|
2564
|
+
}
|
|
2565
|
+
/** Persist from property viewer: omit when default visible; `false` when hidden; trimmed non-empty string = expression. */
|
|
2566
|
+
persistQuestionIsVisibleFromForm(value) {
|
|
2567
|
+
if (value === undefined || value === null) {
|
|
2568
|
+
return undefined;
|
|
2569
|
+
}
|
|
2570
|
+
if (typeof value === 'boolean') {
|
|
2571
|
+
return value ? undefined : false;
|
|
2572
|
+
}
|
|
2573
|
+
if (typeof value === 'string') {
|
|
2574
|
+
const t = value.trim();
|
|
2575
|
+
return t || undefined;
|
|
2576
|
+
}
|
|
2577
|
+
return undefined;
|
|
2578
|
+
}
|
|
2579
|
+
persistQuestionIsRequiredFromForm(value) {
|
|
2580
|
+
if (value === undefined || value === null) {
|
|
2581
|
+
return false;
|
|
2582
|
+
}
|
|
2583
|
+
if (typeof value === 'boolean') {
|
|
2584
|
+
return value;
|
|
2585
|
+
}
|
|
2586
|
+
if (typeof value === 'string') {
|
|
2587
|
+
const t = value.trim();
|
|
2588
|
+
if (!t) {
|
|
2589
|
+
return false;
|
|
2590
|
+
}
|
|
2591
|
+
return t;
|
|
2592
|
+
}
|
|
2593
|
+
return false;
|
|
2594
|
+
}
|
|
2595
|
+
async questionnairePromptEditItem(item, sectionId, _value) {
|
|
2596
|
+
const qItem = item;
|
|
2597
|
+
const validationFailed = async (titleKey, descKey, fallTitle, fallDesc) => {
|
|
2598
|
+
const title = (await this.translationService.translateAsync(titleKey)) || fallTitle;
|
|
2599
|
+
const content = (await this.translationService.translateAsync(descKey)) || fallDesc;
|
|
2600
|
+
this.toastService.show({ color: 'warning', title, content });
|
|
2601
|
+
throw new Error('QuestionnaireEditQuestionValidation');
|
|
2602
|
+
};
|
|
2603
|
+
try {
|
|
2604
|
+
const bankRow = qItem.questionBankItemId
|
|
2605
|
+
? await this.entityService
|
|
2606
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.questionBankItem.name)
|
|
2607
|
+
.data()
|
|
2608
|
+
.byKey(qItem.questionBankItemId)
|
|
2609
|
+
.catch(() => null)
|
|
2610
|
+
: null;
|
|
2611
|
+
const bankComment = normalizeQuestionCommentConfig(bankRow?.comment);
|
|
2612
|
+
const mergedCommentForForm = mergeQuestionCommentConfig(bankComment, qItem.comment);
|
|
2613
|
+
const bankHint = normalizeQuestionHintFromEntityRow(bankRow ?? {});
|
|
2614
|
+
const mergedHintForForm = mergeQuestionHintForViewer(bankHint, parseQuestionHintPartialFromRecord(qItem));
|
|
2615
|
+
const result = await this.propertyViewerService
|
|
2616
|
+
.create()
|
|
2617
|
+
.dialog((d) => {
|
|
2618
|
+
d.setTitle('@assessment-management:questionnaires.components.questionnaire-builder.actions.edit-question.title')
|
|
2619
|
+
.setSize('md')
|
|
2620
|
+
.setCloseButton(true)
|
|
2621
|
+
.setMode('advanced')
|
|
2622
|
+
.setTabs(QUESTIONNAIRE_QUESTION_EDIT_TABS)
|
|
2623
|
+
.setContext({
|
|
2624
|
+
name: qItem.name,
|
|
2625
|
+
tags: qItem.tags ?? [],
|
|
2626
|
+
isRequired: this.questionEditFormIsRequired(qItem),
|
|
2627
|
+
isVisible: this.questionEditFormIsVisible(qItem.isVisible),
|
|
2628
|
+
hint: createQuestionHintFormContext(mergedHintForForm),
|
|
2629
|
+
comment: mergedCommentForForm,
|
|
2630
|
+
})
|
|
2631
|
+
.onAction(async (ref) => {
|
|
2632
|
+
const context = ref.context();
|
|
2633
|
+
const rawId = String(context.name ?? '').trim();
|
|
2634
|
+
if (!rawId) {
|
|
2635
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-required.title', '@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-required.description', 'Question ID required', 'Enter a unique question ID.');
|
|
2636
|
+
}
|
|
2637
|
+
if (!this.isValidQuestionnaireItemName(rawId)) {
|
|
2638
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-invalid.title', '@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-invalid.description', 'Invalid question ID', 'Use letters, numbers, underscores, and hyphens (1–128 characters).');
|
|
2639
|
+
}
|
|
2640
|
+
const isDuplicate = this.builderState().sections.some((s) => s.items.some((i) => (s.name !== sectionId || i.name !== qItem.name) && i.name === rawId));
|
|
2641
|
+
if (isDuplicate) {
|
|
2642
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-duplicate.title', '@assessment-management:questionnaires.components.questionnaire-builder.validation.question-id-duplicate.description', 'Duplicate question ID', 'Another question already uses this ID.');
|
|
2643
|
+
}
|
|
2644
|
+
});
|
|
2645
|
+
})
|
|
2646
|
+
.show();
|
|
2647
|
+
if (!result) {
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
const formData = result.values;
|
|
2651
|
+
const rawIdOut = String(formData.name ?? '').trim();
|
|
2652
|
+
const tags = this.normalizeTagsFromForm(formData.tags);
|
|
2653
|
+
const hintPersist = this.persistQuestionHintFromForm(bankHint, formData.hint);
|
|
2654
|
+
const commentPersist = this.persistQuestionCommentFromForm(bankComment, formData.comment);
|
|
2655
|
+
const nextItem = {
|
|
2656
|
+
...qItem,
|
|
2657
|
+
name: rawIdOut,
|
|
2658
|
+
id: rawIdOut,
|
|
2659
|
+
tags,
|
|
2660
|
+
isRequired: this.persistQuestionIsRequiredFromForm(formData.isRequired),
|
|
2661
|
+
isVisible: this.persistQuestionIsVisibleFromForm(formData.isVisible),
|
|
2662
|
+
};
|
|
2663
|
+
if (hintPersist != null) {
|
|
2664
|
+
nextItem.hint = hintPersist;
|
|
2665
|
+
}
|
|
2666
|
+
else {
|
|
2667
|
+
delete nextItem.hint;
|
|
2668
|
+
}
|
|
2669
|
+
if (commentPersist != null) {
|
|
2670
|
+
nextItem.comment = commentPersist;
|
|
2671
|
+
}
|
|
2672
|
+
else {
|
|
2673
|
+
delete nextItem.comment;
|
|
2674
|
+
}
|
|
2675
|
+
return nextItem;
|
|
2676
|
+
}
|
|
2677
|
+
catch (error) {
|
|
2678
|
+
if (error instanceof Error && error.message === 'QuestionnaireEditQuestionValidation') {
|
|
2679
|
+
return null;
|
|
2680
|
+
}
|
|
2681
|
+
console.error('Error editing question:', error);
|
|
2682
|
+
return null;
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
//#endregion
|
|
2686
|
+
//#region ---- Section Management ----
|
|
2687
|
+
/** Toolbar / page command: delegates to {@link AXPStandardSectionItemsBuilderComponent#addSection}. */
|
|
2688
|
+
async addSection() {
|
|
2689
|
+
await this.standardRef()?.addSection();
|
|
2690
|
+
}
|
|
2691
|
+
//#endregion
|
|
2692
|
+
//#region ---- Item Management ----
|
|
2693
|
+
async questionnairePromptAddItems(sectionId, value) {
|
|
2694
|
+
const all = value.sections;
|
|
2695
|
+
const section = all.find((x) => x.name === sectionId);
|
|
2696
|
+
if (!section)
|
|
2697
|
+
return null;
|
|
2698
|
+
return (await this.selectQuestionsFromQuestionBankForSection(section, all));
|
|
2699
|
+
}
|
|
2700
|
+
/**
|
|
2701
|
+
* Open question bank selector and return new items (standard builder appends them).
|
|
2702
|
+
*/
|
|
2703
|
+
async selectQuestionsFromQuestionBankForSection(section, allSections) {
|
|
2704
|
+
try {
|
|
2705
|
+
const dataSource = new AXDataSource({
|
|
2706
|
+
key: 'id',
|
|
2707
|
+
pageSize: 20,
|
|
2708
|
+
load: async (e) => {
|
|
2709
|
+
const questions = await this.questionBankData().query(e);
|
|
2710
|
+
return {
|
|
2711
|
+
items: questions.items,
|
|
2712
|
+
total: questions.total,
|
|
2713
|
+
};
|
|
2714
|
+
},
|
|
2715
|
+
});
|
|
2716
|
+
// Create category tree data source for filtering
|
|
2717
|
+
const categoryTreeDataSource = {
|
|
2718
|
+
loadRootNodes: async () => {
|
|
2719
|
+
const result = await this.questionBankCategoryData().query({
|
|
2720
|
+
skip: 0,
|
|
2721
|
+
take: 1000,
|
|
2722
|
+
filter: {
|
|
2723
|
+
field: 'parentId',
|
|
2724
|
+
operator: { type: 'isEmpty' },
|
|
2725
|
+
value: true,
|
|
2726
|
+
},
|
|
2727
|
+
});
|
|
2728
|
+
return result.items.map((item) => ({
|
|
2729
|
+
id: item.id,
|
|
2730
|
+
title: item.title || item.name,
|
|
2731
|
+
description: item.description || '',
|
|
2732
|
+
parentId: item.parentId,
|
|
2733
|
+
childrenCount: item.childrenCount || 0,
|
|
2734
|
+
}));
|
|
2735
|
+
},
|
|
2736
|
+
loadChildNodes: async (parentId) => {
|
|
2737
|
+
const result = await this.questionBankCategoryData().query({
|
|
2738
|
+
skip: 0,
|
|
2739
|
+
take: 1000,
|
|
2740
|
+
filter: {
|
|
2741
|
+
field: 'parentId',
|
|
2742
|
+
operator: { type: 'equal' },
|
|
2743
|
+
value: parentId,
|
|
2744
|
+
},
|
|
2745
|
+
});
|
|
2746
|
+
return result.items.map((item) => ({
|
|
2747
|
+
id: item.id,
|
|
2748
|
+
title: item.title || item.name,
|
|
2749
|
+
description: item.description || '',
|
|
2750
|
+
parentId: item.parentId,
|
|
2751
|
+
childrenCount: item.childrenCount || 0,
|
|
2752
|
+
}));
|
|
2753
|
+
},
|
|
2754
|
+
searchNodes: async (searchValue) => {
|
|
2755
|
+
const result = await this.questionBankCategoryData().query({
|
|
2756
|
+
skip: 0,
|
|
2757
|
+
take: 1000,
|
|
2758
|
+
filter: {
|
|
2759
|
+
filters: [
|
|
2760
|
+
{
|
|
2761
|
+
field: 'title',
|
|
2762
|
+
operator: { type: 'contains' },
|
|
2763
|
+
value: searchValue,
|
|
2764
|
+
},
|
|
2765
|
+
{
|
|
2766
|
+
field: 'name',
|
|
2767
|
+
operator: { type: 'contains' },
|
|
2768
|
+
value: searchValue,
|
|
2769
|
+
},
|
|
2770
|
+
],
|
|
2771
|
+
logic: 'or',
|
|
2772
|
+
},
|
|
2773
|
+
});
|
|
2774
|
+
return result.items.map((item) => ({
|
|
2775
|
+
id: item.id,
|
|
2776
|
+
title: item.title || item.name,
|
|
2777
|
+
description: item.description || '',
|
|
2778
|
+
parentId: item.parentId,
|
|
2779
|
+
childrenCount: item.childrenCount || 0,
|
|
2780
|
+
}));
|
|
2781
|
+
},
|
|
2782
|
+
};
|
|
2783
|
+
const entity = await this.entityResolver.resolve(RootConfig.module.name, RootConfig.entities.questionBankItem.name);
|
|
2784
|
+
if (!entity) {
|
|
2785
|
+
throw new Error('Entity not found: ' + RootConfig.entities.questionBankItem.name);
|
|
2786
|
+
}
|
|
2787
|
+
const columns = entity.columns
|
|
2788
|
+
?.filter((column) => entity.properties.some((property) => property.name === column.name))
|
|
2789
|
+
.map((column) => {
|
|
2790
|
+
const property = entity.properties.find((prop) => prop.name === column.name);
|
|
2791
|
+
return {
|
|
2792
|
+
name: column.name,
|
|
2793
|
+
title: property?.title ?? '',
|
|
2794
|
+
visible: column.options?.visible !== false,
|
|
2795
|
+
widget: {
|
|
2796
|
+
type: column.showAs?.type ?? property?.schema?.interface?.type ?? 'text-editor',
|
|
2797
|
+
options: column.showAs?.options ?? property?.schema?.interface?.options ?? {},
|
|
2798
|
+
},
|
|
2799
|
+
};
|
|
2800
|
+
}) || [];
|
|
2801
|
+
// Translate titles
|
|
2802
|
+
const selectQuestionsTitle = (await this.translationService.translateAsync('@assessment-management:questionnaires.components.questionnaire-builder.select-questions')) || 'Select Questions from Question Bank';
|
|
2803
|
+
const categoriesTitle = (await this.translationService.translateAsync('@assessment-management:questionnaires.components.questionnaire-builder.categories')) || 'Categories';
|
|
2804
|
+
const titleLabel = (await this.translationService.translateAsync('@general:terms.common.title')) || 'Title';
|
|
2805
|
+
const noteLabel = (await this.translationService.translateAsync('@assessment-management:question-bank.entities.question-bank-item.fields.note.title')) || 'Note';
|
|
2806
|
+
// Open data selector with category filter
|
|
2807
|
+
const result = await this.dataSelectorService.openWithCategoryFilter({
|
|
2808
|
+
title: selectQuestionsTitle,
|
|
2809
|
+
dataSource: dataSource,
|
|
2810
|
+
columns: columns,
|
|
2811
|
+
selectionMode: 'multiple',
|
|
2812
|
+
searchFields: [
|
|
2813
|
+
{ name: 'title', title: titleLabel },
|
|
2814
|
+
{ name: 'note', title: noteLabel },
|
|
2815
|
+
],
|
|
2816
|
+
allowCreate: 'full',
|
|
2817
|
+
onCreate: (mode) => this.createQuestionBankItem(entity, mode),
|
|
2818
|
+
}, {
|
|
2819
|
+
title: categoriesTitle,
|
|
2820
|
+
dataSource: categoryTreeDataSource,
|
|
2821
|
+
filterField: 'categoryIds',
|
|
2822
|
+
filterOperator: 'contains',
|
|
2823
|
+
width: '350px',
|
|
2824
|
+
});
|
|
2825
|
+
if (result?.items && result.items.length > 0) {
|
|
2826
|
+
const questionPromises = result.items.map((item) => this.questionBankData()
|
|
2827
|
+
.byKey(item.id)
|
|
2828
|
+
.catch(() => null));
|
|
2829
|
+
const questions = await Promise.all(questionPromises);
|
|
2830
|
+
const used = collectQuestionnaireItemNames(allSections);
|
|
2831
|
+
const baseOrder = section.items.length;
|
|
2832
|
+
const newItems = result.items.map((item, index) => {
|
|
2833
|
+
const fullQuestion = questions[index];
|
|
2834
|
+
const qName = allocateNextQuestionItemName(used);
|
|
2835
|
+
used.add(qName);
|
|
2836
|
+
return {
|
|
2837
|
+
name: qName,
|
|
2838
|
+
questionBankItemId: item.id,
|
|
2839
|
+
order: baseOrder + index,
|
|
2840
|
+
isRequired: false,
|
|
2841
|
+
isVisible: undefined,
|
|
2842
|
+
isNewlyAdded: true,
|
|
2843
|
+
question: fullQuestion
|
|
2844
|
+
? {
|
|
2845
|
+
id: fullQuestion.id,
|
|
2846
|
+
title: fullQuestion.title,
|
|
2847
|
+
question: fullQuestion.question,
|
|
2848
|
+
note: fullQuestion.note,
|
|
2849
|
+
difficulty: fullQuestion.difficulty,
|
|
2850
|
+
}
|
|
2851
|
+
: {
|
|
2852
|
+
id: item.id,
|
|
2853
|
+
title: item.title || 'Question',
|
|
2854
|
+
question: item.question,
|
|
2855
|
+
note: item.note,
|
|
2856
|
+
difficulty: item.difficulty,
|
|
2857
|
+
},
|
|
2858
|
+
};
|
|
2859
|
+
});
|
|
2860
|
+
return newItems;
|
|
2861
|
+
}
|
|
2862
|
+
return null;
|
|
2863
|
+
}
|
|
2864
|
+
catch (error) {
|
|
2865
|
+
console.error('Error loading questions:', error);
|
|
2866
|
+
return null;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Create a new question bank item via Entity:Create and return it for selection in the data selector.
|
|
2871
|
+
*/
|
|
2872
|
+
async createQuestionBankItem(entity, _mode) {
|
|
2873
|
+
const result = await this.commandService.execute('Entity:Create', {
|
|
2874
|
+
__context__: {
|
|
2875
|
+
entity: `${entity.module}.${entity.name}`,
|
|
2876
|
+
entityInfo: {
|
|
2877
|
+
name: entity.name,
|
|
2878
|
+
module: entity.module,
|
|
2879
|
+
title: entity.title,
|
|
2880
|
+
parentKey: entity.parentKey,
|
|
2881
|
+
},
|
|
2882
|
+
data: {},
|
|
2883
|
+
options: {},
|
|
2884
|
+
},
|
|
2885
|
+
});
|
|
2886
|
+
if (result?.success && result?.data) {
|
|
2887
|
+
const item = Array.isArray(result.data) ? result.data[0] : result.data;
|
|
2888
|
+
return item;
|
|
2889
|
+
}
|
|
2890
|
+
return null;
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Maps nested `hint` from the question property viewer to persisted questionnaire item `hint` partial (diff from bank).
|
|
2894
|
+
*/
|
|
2895
|
+
persistQuestionHintFromForm(bank, hint) {
|
|
2896
|
+
if (!hint) {
|
|
2897
|
+
return undefined;
|
|
2898
|
+
}
|
|
2899
|
+
const modeRaw = hint.mode == null ? undefined : typeof hint.mode === 'string' ? hint.mode : hint.mode.id;
|
|
2900
|
+
const mode = normalizeQuestionHintMode(modeRaw) ?? 'off';
|
|
2901
|
+
const c = hint.content;
|
|
2902
|
+
let content;
|
|
2903
|
+
if (c == null) {
|
|
2904
|
+
content = undefined;
|
|
2905
|
+
}
|
|
2906
|
+
else if (typeof c === 'string') {
|
|
2907
|
+
const t = c.trim();
|
|
2908
|
+
content = t || undefined;
|
|
2909
|
+
}
|
|
2910
|
+
else if (typeof c === 'object') {
|
|
2911
|
+
content = c;
|
|
2912
|
+
}
|
|
2913
|
+
const edited = normalizeQuestionHintConfig({ mode, content });
|
|
2914
|
+
return diffQuestionHintOverride(bank, edited);
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Persists questionnaire item `comment` override: only fields that differ from the question bank default.
|
|
2918
|
+
*/
|
|
2919
|
+
persistQuestionCommentFromForm(bank, form) {
|
|
2920
|
+
if (!form) {
|
|
2921
|
+
return undefined;
|
|
2922
|
+
}
|
|
2923
|
+
const edited = normalizeQuestionCommentConfig(form);
|
|
2924
|
+
return diffQuestionCommentOverride(bank, edited);
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Normalize tag-editor output to trimmed unique strings (supports string[] or { title }[] from tag service).
|
|
2928
|
+
*/
|
|
2929
|
+
normalizeTagsFromForm(raw) {
|
|
2930
|
+
if (raw == null || !Array.isArray(raw))
|
|
2931
|
+
return undefined;
|
|
2932
|
+
const seen = new Set();
|
|
2933
|
+
const out = [];
|
|
2934
|
+
for (const entry of raw) {
|
|
2935
|
+
let t = '';
|
|
2936
|
+
if (typeof entry === 'string')
|
|
2937
|
+
t = entry.trim();
|
|
2938
|
+
else if (entry && typeof entry === 'object' && 'title' in entry) {
|
|
2939
|
+
t = String(entry.title).trim();
|
|
2940
|
+
}
|
|
2941
|
+
if (!t)
|
|
2942
|
+
continue;
|
|
2943
|
+
const key = t.toLowerCase();
|
|
2944
|
+
if (seen.has(key))
|
|
2945
|
+
continue;
|
|
2946
|
+
seen.add(key);
|
|
2947
|
+
out.push(t);
|
|
2948
|
+
}
|
|
2949
|
+
return out.length ? out : undefined;
|
|
2950
|
+
}
|
|
2951
|
+
/** Allowed characters for questionnaire item technical name (UUID-safe). */
|
|
2952
|
+
isValidQuestionnaireItemName(name) {
|
|
2953
|
+
return name.length >= 1 && name.length <= 128 && /^[a-zA-Z0-9_-]+$/.test(name);
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Plain heading for builder cards: prefer rich `question`, else admin list `title`.
|
|
2957
|
+
*/
|
|
2958
|
+
itemQuestionHeading(item) {
|
|
2959
|
+
const q = item.question;
|
|
2960
|
+
if (!q) {
|
|
2961
|
+
return 'Question';
|
|
2962
|
+
}
|
|
2963
|
+
const locale = this.translationService.getActiveLang?.() ?? 'en-US';
|
|
2964
|
+
const raw = q.question;
|
|
2965
|
+
if (raw != null && raw !== '') {
|
|
2966
|
+
const html = typeof raw === 'string' ? raw : resolveMultiLanguageString(raw, locale);
|
|
2967
|
+
const plain = stripHtmlToPlain(html);
|
|
2968
|
+
if (plain.trim()) {
|
|
2969
|
+
return plain;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
const titleResolved = resolveMultiLanguageString(q.title, locale);
|
|
2973
|
+
return titleResolved.trim() || 'Question';
|
|
2974
|
+
}
|
|
2975
|
+
/** Plain preview line for optional note under the heading. */
|
|
2976
|
+
itemQuestionNotePreview(item) {
|
|
2977
|
+
const raw = item.question?.note;
|
|
2978
|
+
if (raw == null || raw === '') {
|
|
2979
|
+
return '';
|
|
2980
|
+
}
|
|
2981
|
+
const locale = this.translationService.getActiveLang?.() ?? 'en-US';
|
|
2982
|
+
const html = typeof raw === 'string' ? raw : resolveMultiLanguageString(raw, locale);
|
|
2983
|
+
return stripHtmlToPlain(html);
|
|
2984
|
+
}
|
|
2985
|
+
/**
|
|
2986
|
+
* Resolve icon based on widget type, with safe fallback.
|
|
2987
|
+
*/
|
|
2988
|
+
getQuestionWidgetIcon(item) {
|
|
2989
|
+
const fallbackIcon = 'fa-light fa-question-circle';
|
|
2990
|
+
const widgetType = item.interfaceOverride?.type ?? item.question?.interface?.type;
|
|
2991
|
+
if (!widgetType) {
|
|
2992
|
+
return fallbackIcon;
|
|
2993
|
+
}
|
|
2994
|
+
try {
|
|
2995
|
+
return this.widgetRegistry.resolve(widgetType).icon ?? fallbackIcon;
|
|
2996
|
+
}
|
|
2997
|
+
catch {
|
|
2998
|
+
return fallbackIcon;
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
//#endregion
|
|
3002
|
+
//#region ---- Preview ----
|
|
3003
|
+
/**
|
|
3004
|
+
* Open preview dialog with questionnaire viewer
|
|
3005
|
+
*/
|
|
3006
|
+
async handlePreview() {
|
|
3007
|
+
if (this.isPreviewDisabled()) {
|
|
3008
|
+
return;
|
|
3009
|
+
}
|
|
3010
|
+
try {
|
|
3011
|
+
const currentValue = convertStateToValue(this.builderState(), this.value() || undefined);
|
|
3012
|
+
// Always use the current displaySettings from the computed property to ensure preview uses latest settings
|
|
3013
|
+
currentValue.displaySettings = this.displaySettings();
|
|
3014
|
+
const previewTitle = (await this.translationService.translateAsync('@assessment-management:questionnaires.components.questionnaire-builder.actions.preview.title')) || 'Preview';
|
|
3015
|
+
const result = await this.questionnaireViewerService.open({
|
|
3016
|
+
title: previewTitle,
|
|
3017
|
+
structure: currentValue,
|
|
3018
|
+
prePostConfig: this.prePostConfig() ?? undefined,
|
|
3019
|
+
questionnaireId: this.questionnaireEntityId(),
|
|
3020
|
+
});
|
|
3021
|
+
// Handle result if needed (answers, submitted status)
|
|
3022
|
+
if (result) {
|
|
3023
|
+
console.log('Questionnaire preview result:', result);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
catch (error) {
|
|
3027
|
+
console.error('Error opening preview:', error);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* Toggle fullscreen mode using the directive
|
|
3032
|
+
*/
|
|
3033
|
+
async handleFullscreen() {
|
|
3034
|
+
const fullscreen = this.fullscreenDirective();
|
|
3035
|
+
if (fullscreen) {
|
|
3036
|
+
await fullscreen.toggle();
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3040
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireQuestionsBuilderComponent, isStandalone: true, selector: "axm-questionnaire-questions-builder", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, prePostConfig: { classPropertyName: "prePostConfig", publicName: "prePostConfig", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null }, displaySettingsInput: { classPropertyName: "displaySettingsInput", publicName: "displaySettingsInput", isSignal: true, isRequired: false, transformFunction: null }, questionnaireEntityId: { classPropertyName: "questionnaireEntityId", publicName: "questionnaireEntityId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "fullscreenDirective", first: true, predicate: ["fullscreen"], descendants: true, isSignal: true }, { propertyName: "standardRef", first: true, predicate: AXPStandardSectionItemsBuilderComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"axm-questionnaire-questions-builder\" axFullscreen #fullscreen=\"axFullscreen\">\n @if (showHeader()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n @if (!readonly()) {\n <ax-button class=\"ax-sm\" [text]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.add-section.title'\n | translate\n | async) || 'Add Section'\n \" [color]=\"'primary'\" (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <ax-button class=\"ax-sm\" [title]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.preview.title'\n | translate\n | async) || 'Preview'\n \" [disabled]=\"isPreviewDisabled()\" (onClick)=\"handlePreview()\">\n <ax-icon icon=\"fa-light fa-eye\"></ax-icon>\n </ax-button>\n }\n <ax-button class=\"ax-sm\" [title]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.fullscreen.title'\n | translate\n | async) || 'Full Screen'\n \" (onClick)=\"handleFullscreen()\">\n <ax-icon icon=\"fa-light fa-expand\"></ax-icon>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder #standardRef class=\"ax-block ax-min-h-[200px]\" [value]=\"builderValue()\"\n [config]=\"standardConfig()\" [readonly]=\"readonly()\" (valueChange)=\"onBuilderValueChange($event)\" />\n</div>", styles: [".axm-questionnaire-questions-builder{display:flex;height:100%;width:100%;flex-direction:column}.axm-questionnaire-questions-builder .__header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-bottom-width:1px;padding:.75rem}.axm-questionnaire-questions-builder .__header .__header-left,.axm-questionnaire-questions-builder .__header .__header-right{display:flex;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: AXSwitchModule }, { kind: "ngmodule", type: AXLabelModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStandardSectionItemsBuilderComponent, selector: "axp-standard-section-items-builder", inputs: ["value", "config", "readonly"], outputs: ["valueChange"] }, { kind: "directive", type: AXFullScreenDirective, selector: "[axFullscreen]", outputs: ["fullscreenChange"], exportAs: ["axFullscreen"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3041
|
+
}
|
|
3042
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsBuilderComponent, decorators: [{
|
|
3043
|
+
type: Component,
|
|
3044
|
+
args: [{ selector: 'axm-questionnaire-questions-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
3045
|
+
CommonModule,
|
|
3046
|
+
FormsModule,
|
|
3047
|
+
AXButtonModule,
|
|
3048
|
+
AXDecoratorModule,
|
|
3049
|
+
AXDropdownModule,
|
|
3050
|
+
AXFormModule,
|
|
3051
|
+
AXSwitchModule,
|
|
3052
|
+
AXLabelModule,
|
|
3053
|
+
AXTranslationModule,
|
|
3054
|
+
AXPStandardSectionItemsBuilderComponent,
|
|
3055
|
+
AXFullScreenDirective,
|
|
3056
|
+
], template: "<div class=\"axm-questionnaire-questions-builder\" axFullscreen #fullscreen=\"axFullscreen\">\n @if (showHeader()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n @if (!readonly()) {\n <ax-button class=\"ax-sm\" [text]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.add-section.title'\n | translate\n | async) || 'Add Section'\n \" [color]=\"'primary'\" (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n <ax-button class=\"ax-sm\" [title]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.preview.title'\n | translate\n | async) || 'Preview'\n \" [disabled]=\"isPreviewDisabled()\" (onClick)=\"handlePreview()\">\n <ax-icon icon=\"fa-light fa-eye\"></ax-icon>\n </ax-button>\n }\n <ax-button class=\"ax-sm\" [title]=\"\n ('@assessment-management:questionnaires.components.questionnaire-builder.actions.fullscreen.title'\n | translate\n | async) || 'Full Screen'\n \" (onClick)=\"handleFullscreen()\">\n <ax-icon icon=\"fa-light fa-expand\"></ax-icon>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder #standardRef class=\"ax-block ax-min-h-[200px]\" [value]=\"builderValue()\"\n [config]=\"standardConfig()\" [readonly]=\"readonly()\" (valueChange)=\"onBuilderValueChange($event)\" />\n</div>", styles: [".axm-questionnaire-questions-builder{display:flex;height:100%;width:100%;flex-direction:column}.axm-questionnaire-questions-builder .__header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-bottom-width:1px;padding:.75rem}.axm-questionnaire-questions-builder .__header .__header-left,.axm-questionnaire-questions-builder .__header .__header-right{display:flex;gap:.5rem}\n"] }]
|
|
3057
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], prePostConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "prePostConfig", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], displaySettingsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "displaySettingsInput", required: false }] }], questionnaireEntityId: [{ type: i0.Input, args: [{ isSignal: true, alias: "questionnaireEntityId", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], fullscreenDirective: [{ type: i0.ViewChild, args: ['fullscreen', { isSignal: true }] }], standardRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPStandardSectionItemsBuilderComponent), { isSignal: true }] }] } });
|
|
3058
|
+
|
|
3059
|
+
/** Component key for the questionnaire Questions page tab. Register via AXP_PAGE_COMPONENT_PROVIDER. */
|
|
3060
|
+
const QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY = 'questionnaire-questions-page';
|
|
3061
|
+
|
|
3062
|
+
const QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND = 'Questionnaire:Questions:Save';
|
|
3063
|
+
/**
|
|
3064
|
+
* Command to save the questionnaire questions field.
|
|
3065
|
+
* By default uses entity update (patch) with { questions }.
|
|
3066
|
+
* Can be overridden for custom API logic.
|
|
3067
|
+
*/
|
|
3068
|
+
class AXMSaveQuestionnaireQuestionsCommand {
|
|
3069
|
+
constructor() {
|
|
3070
|
+
this.entityService = inject(AXPEntityService);
|
|
3071
|
+
this.translationService = inject(AXTranslationService);
|
|
3072
|
+
}
|
|
3073
|
+
async execute(input) {
|
|
3074
|
+
const { id, questions } = input;
|
|
3075
|
+
if (!id) {
|
|
3076
|
+
return {
|
|
3077
|
+
success: false,
|
|
3078
|
+
message: {
|
|
3079
|
+
text: await this.translationService.translateAsync('@general:messages.entity.invalid-data'),
|
|
3080
|
+
},
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
try {
|
|
3084
|
+
const entityRef = `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}`;
|
|
3085
|
+
const dataAccessor = this.entityService.withEntity(entityRef).data();
|
|
3086
|
+
await dataAccessor.update(id, { questions });
|
|
3087
|
+
return {
|
|
3088
|
+
success: true,
|
|
3089
|
+
data: { id, questions },
|
|
3090
|
+
message: {
|
|
3091
|
+
text: await this.translationService.translateAsync('@general:messages.generic.success.description'),
|
|
3092
|
+
},
|
|
3093
|
+
};
|
|
3094
|
+
}
|
|
3095
|
+
catch (error) {
|
|
3096
|
+
const message = error instanceof Error
|
|
3097
|
+
? error.message
|
|
3098
|
+
: await this.translationService.translateAsync('@general:messages.generic.error.description');
|
|
3099
|
+
return {
|
|
3100
|
+
success: false,
|
|
3101
|
+
message: { text: message },
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireQuestionsCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3106
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireQuestionsCommand, providedIn: 'root' }); }
|
|
3107
|
+
}
|
|
3108
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireQuestionsCommand, decorators: [{
|
|
3109
|
+
type: Injectable,
|
|
3110
|
+
args: [{
|
|
3111
|
+
providedIn: 'root',
|
|
3112
|
+
}]
|
|
3113
|
+
}] });
|
|
3114
|
+
|
|
3115
|
+
var saveQuestionnaireQuestions_command = /*#__PURE__*/Object.freeze({
|
|
3116
|
+
__proto__: null,
|
|
3117
|
+
AXMSaveQuestionnaireQuestionsCommand: AXMSaveQuestionnaireQuestionsCommand,
|
|
3118
|
+
QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND: QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND
|
|
3119
|
+
});
|
|
3120
|
+
|
|
3121
|
+
/** Local command handled in execute(); reverts questions to rootContext (no AXPCommand). */
|
|
3122
|
+
const QUESTIONNAIRE_QUESTIONS_DISCARD_COMMAND = 'Questionnaire:Questions:Discard';
|
|
3123
|
+
const QUESTIONNAIRE_QUESTIONS_ADD_SECTION_COMMAND = 'Questionnaire:Questions:AddSection';
|
|
3124
|
+
const QUESTIONNAIRE_QUESTIONS_PREVIEW_COMMAND = 'Questionnaire:Questions:Preview';
|
|
3125
|
+
//#region ---- Questionnaire Questions Page Component ----
|
|
3126
|
+
/**
|
|
3127
|
+
* Page component that renders the questions property using axm-questionnaire-questions-builder.
|
|
3128
|
+
* Extends AXPPageLayoutBaseComponent to provide a Save button that persists questions via Questionnaire:Questions:Save.
|
|
3129
|
+
* Receives rootContext (entity data).
|
|
3130
|
+
*/
|
|
3131
|
+
class AXMQuestionnaireQuestionsPageComponent extends AXPPageLayoutBaseComponent {
|
|
3132
|
+
//#endregion
|
|
3133
|
+
//#region ---- Lifecycle ----
|
|
3134
|
+
constructor() {
|
|
3135
|
+
super();
|
|
3136
|
+
//#region ---- Inputs ----
|
|
3137
|
+
this.rootContext = input(...(ngDevMode ? [undefined, { debugName: "rootContext" }] : /* istanbul ignore next */ []));
|
|
3138
|
+
/** Optional page config (e.g. field, layout) set by the page-component-renderer. */
|
|
3139
|
+
this.pageConfig = input(...(ngDevMode ? [undefined, { debugName: "pageConfig" }] : /* istanbul ignore next */ []));
|
|
3140
|
+
//#endregion
|
|
3141
|
+
//#region ---- Services & Dependencies ----
|
|
3142
|
+
this.commandService = inject(AXPCommandService);
|
|
3143
|
+
this.eventService = inject(AXPBroadcastEventService);
|
|
3144
|
+
this.hostPageLayout = inject(AXPPageLayoutBase, { optional: true, skipSelf: true });
|
|
3145
|
+
//#endregion
|
|
3146
|
+
//#region ---- View References ----
|
|
3147
|
+
this.builderRef = viewChild('builderRef', ...(ngDevMode ? [{ debugName: "builderRef" }] : /* istanbul ignore next */ []));
|
|
3148
|
+
//#endregion
|
|
3149
|
+
//#region ---- State Signals ----
|
|
3150
|
+
/** Latest context (includes edited questions). Used for Save when rootContext is not updated by the parent. */
|
|
3151
|
+
this.localContext = signal(null, ...(ngDevMode ? [{ debugName: "localContext" }] : /* istanbul ignore next */ []));
|
|
3152
|
+
/** When true, the next valueChange from the builder is ignored (avoids undoing discard due to stale emit). */
|
|
3153
|
+
this.ignoreNextValueChange = signal(false, ...(ngDevMode ? [{ debugName: "ignoreNextValueChange" }] : /* istanbul ignore next */ []));
|
|
3154
|
+
/** Stable pre/post config so we don't pass a new object every CD (avoids infinite loop). */
|
|
3155
|
+
this.prePostConfigStable = signal(null, ...(ngDevMode ? [{ debugName: "prePostConfigStable" }] : /* istanbul ignore next */ []));
|
|
3156
|
+
/** Baseline snapshot of questions for dirty checks. */
|
|
3157
|
+
this.baselineQuestions = signal(null, ...(ngDevMode ? [{ debugName: "baselineQuestions" }] : /* istanbul ignore next */ []));
|
|
3158
|
+
/**
|
|
3159
|
+
* When true, the next builder emission should realign the baseline to the builder's canonical shape.
|
|
3160
|
+
* Root/API `questions` often differs from the normalized object emitted by the builder (defaults, ordering, derived fields), which would otherwise keep `isDirty` true on load and after discard/save.
|
|
3161
|
+
*/
|
|
3162
|
+
this.questionsBaselinePendingReconcile = signal(false, ...(ngDevMode ? [{ debugName: "questionsBaselinePendingReconcile" }] : /* istanbul ignore next */ []));
|
|
3163
|
+
this.isDirty = signal(false, ...(ngDevMode ? [{ debugName: "isDirty" }] : /* istanbul ignore next */ []));
|
|
3164
|
+
//#endregion
|
|
3165
|
+
//#region ---- Computed State ----
|
|
3166
|
+
/** Current context: prefer local updates so edits are preserved. */
|
|
3167
|
+
this.context = computed(() => {
|
|
3168
|
+
const local = this.localContext();
|
|
3169
|
+
if (local != null)
|
|
3170
|
+
return local;
|
|
3171
|
+
return this.rootContext() ?? {};
|
|
3172
|
+
}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
3173
|
+
/** Questions value passed to the builder (from context). */
|
|
3174
|
+
this.questionsValue = computed(() => {
|
|
3175
|
+
const ctx = this.context();
|
|
3176
|
+
const q = ctx['questions'];
|
|
3177
|
+
return (q != null && typeof q === 'object' ? q : null);
|
|
3178
|
+
}, ...(ngDevMode ? [{ debugName: "questionsValue" }] : /* istanbul ignore next */ []));
|
|
3179
|
+
/** Pre/post config for preview; stable reference to avoid infinite change detection. */
|
|
3180
|
+
this.prePostConfig = computed(() => this.prePostConfigStable(), ...(ngDevMode ? [{ debugName: "prePostConfig" }] : /* istanbul ignore next */ []));
|
|
3181
|
+
/** Display settings from entity (for builder preview). */
|
|
3182
|
+
this.entityDisplaySettings = computed(() => toDisplaySettings((this.rootContext() ?? undefined)) ?? null, ...(ngDevMode ? [{ debugName: "entityDisplaySettings" }] : /* istanbul ignore next */ []));
|
|
3183
|
+
/** Questionnaire entity id for preview outcome evaluation. */
|
|
3184
|
+
this.questionnaireEntityId = computed(() => {
|
|
3185
|
+
const id = this.rootContext()?.['id'];
|
|
3186
|
+
return typeof id === 'string' && id.length > 0 ? id : undefined;
|
|
3187
|
+
}, ...(ngDevMode ? [{ debugName: "questionnaireEntityId" }] : /* istanbul ignore next */ []));
|
|
3188
|
+
let previousRootId = undefined;
|
|
3189
|
+
effect(() => {
|
|
3190
|
+
const ctx = this.rootContext();
|
|
3191
|
+
const currentId = ctx != null && typeof ctx === 'object' ? ctx['id'] : undefined;
|
|
3192
|
+
if (currentId !== previousRootId) {
|
|
3193
|
+
previousRootId = currentId;
|
|
3194
|
+
this.localContext.set(null);
|
|
3195
|
+
const rootQuestions = ctx?.['questions'];
|
|
3196
|
+
this.baselineQuestions.set(this.cloneQuestions(rootQuestions));
|
|
3197
|
+
this.isDirty.set(false);
|
|
3198
|
+
this.questionsBaselinePendingReconcile.set(true);
|
|
3199
|
+
}
|
|
3200
|
+
});
|
|
3201
|
+
let lastPrePostKey = '';
|
|
3202
|
+
effect(() => {
|
|
3203
|
+
const ctx = this.rootContext();
|
|
3204
|
+
const next = toPrePostConfig(ctx ?? undefined);
|
|
3205
|
+
const key = next ? JSON.stringify(next) : '';
|
|
3206
|
+
if (key !== lastPrePostKey) {
|
|
3207
|
+
lastPrePostKey = key;
|
|
3208
|
+
this.prePostConfigStable.set(next);
|
|
3209
|
+
}
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
//#endregion
|
|
3213
|
+
//#region ---- Page Actions ----
|
|
3214
|
+
async getPrimaryMenuItems() {
|
|
3215
|
+
const addSectionTitle = (await this.translateService.translateAsync('@assessment-management:questionnaires.components.questionnaire-builder.actions.add-section.title')) || 'Add Section';
|
|
3216
|
+
const previewTitle = (await this.translateService.translateAsync('@assessment-management:questionnaires.components.questionnaire-builder.actions.preview.title')) || 'Preview';
|
|
3217
|
+
const discardTitle = (await this.translateService.translateAsync('@general:actions.discard.title')) || 'Discard';
|
|
3218
|
+
const saveTitle = (await this.translateService.translateAsync('@general:actions.save.title')) || 'Save';
|
|
3219
|
+
const addSectionAction = {
|
|
3220
|
+
title: addSectionTitle,
|
|
3221
|
+
icon: 'fa-light fa-layer-group',
|
|
3222
|
+
zone: 'header',
|
|
3223
|
+
priority: 'primary',
|
|
3224
|
+
color: 'primary',
|
|
3225
|
+
command: {
|
|
3226
|
+
name: QUESTIONNAIRE_QUESTIONS_ADD_SECTION_COMMAND,
|
|
3227
|
+
options: {},
|
|
3228
|
+
},
|
|
3229
|
+
};
|
|
3230
|
+
const previewAction = {
|
|
3231
|
+
title: previewTitle,
|
|
3232
|
+
icon: 'fa-light fa-eye',
|
|
3233
|
+
zone: 'header',
|
|
3234
|
+
priority: 'primary',
|
|
3235
|
+
color: 'default',
|
|
3236
|
+
command: {
|
|
3237
|
+
name: QUESTIONNAIRE_QUESTIONS_PREVIEW_COMMAND,
|
|
3238
|
+
options: {},
|
|
3239
|
+
},
|
|
3240
|
+
};
|
|
3241
|
+
const discardAction = {
|
|
3242
|
+
title: discardTitle,
|
|
3243
|
+
icon: 'fa-light fa-rotate-left',
|
|
3244
|
+
zone: 'footer',
|
|
3245
|
+
priority: 'secondary',
|
|
3246
|
+
color: 'default',
|
|
3247
|
+
visible: this.isDirty(),
|
|
3248
|
+
command: {
|
|
3249
|
+
name: QUESTIONNAIRE_QUESTIONS_DISCARD_COMMAND,
|
|
3250
|
+
options: {},
|
|
3251
|
+
},
|
|
3252
|
+
};
|
|
3253
|
+
const saveAction = {
|
|
3254
|
+
title: saveTitle,
|
|
3255
|
+
icon: 'fa-light fa-floppy-disk',
|
|
3256
|
+
zone: 'footer',
|
|
3257
|
+
priority: 'primary',
|
|
3258
|
+
color: 'primary',
|
|
3259
|
+
visible: this.isDirty(),
|
|
3260
|
+
command: {
|
|
3261
|
+
name: QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND,
|
|
3262
|
+
options: {},
|
|
3263
|
+
},
|
|
3264
|
+
};
|
|
3265
|
+
return [addSectionAction, previewAction, discardAction, saveAction];
|
|
3266
|
+
}
|
|
3267
|
+
//#endregion
|
|
3268
|
+
//#region ---- Command Handling ----
|
|
3269
|
+
execute(command) {
|
|
3270
|
+
if (command.name === QUESTIONNAIRE_QUESTIONS_DISCARD_COMMAND) {
|
|
3271
|
+
this.ignoreNextValueChange.set(true);
|
|
3272
|
+
this.localContext.set(null);
|
|
3273
|
+
this.isDirty.set(false);
|
|
3274
|
+
this.questionsBaselinePendingReconcile.set(true);
|
|
3275
|
+
this.recompute();
|
|
3276
|
+
return;
|
|
3277
|
+
}
|
|
3278
|
+
if (command.name === QUESTIONNAIRE_QUESTIONS_ADD_SECTION_COMMAND) {
|
|
3279
|
+
void this.builderRef()?.addSection();
|
|
3280
|
+
return;
|
|
3281
|
+
}
|
|
3282
|
+
if (command.name === QUESTIONNAIRE_QUESTIONS_PREVIEW_COMMAND) {
|
|
3283
|
+
this.builderRef()?.handlePreview();
|
|
3284
|
+
return;
|
|
3285
|
+
}
|
|
3286
|
+
if (command.name !== QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND) {
|
|
3287
|
+
return;
|
|
3288
|
+
}
|
|
3289
|
+
// Return result for delegateExecute; cast needed to satisfy base signature
|
|
3290
|
+
return this.handleSaveExecute();
|
|
3291
|
+
}
|
|
3292
|
+
async handleSaveExecute() {
|
|
3293
|
+
const ctx = this.localContext() ?? this.rootContext() ?? {};
|
|
3294
|
+
const id = typeof ctx['id'] === 'string' ? ctx['id'] : undefined;
|
|
3295
|
+
const questions = ctx['questions'];
|
|
3296
|
+
if (!id) {
|
|
3297
|
+
return {
|
|
3298
|
+
success: false,
|
|
3299
|
+
message: {
|
|
3300
|
+
text: await this.translateService.translateAsync('@general:messages.entity.invalid-data'),
|
|
3301
|
+
},
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
const input = {
|
|
3305
|
+
id,
|
|
3306
|
+
questions: questions ?? { sections: [] },
|
|
3307
|
+
};
|
|
3308
|
+
const result = await this.commandService.execute(QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND, input);
|
|
3309
|
+
const execResult = (result ?? { success: false });
|
|
3310
|
+
if (execResult.success) {
|
|
3311
|
+
const savedQuestions = questions ?? { sections: [] };
|
|
3312
|
+
this.baselineQuestions.set(this.cloneQuestions(savedQuestions));
|
|
3313
|
+
this.localContext.set(null);
|
|
3314
|
+
this.isDirty.set(false);
|
|
3315
|
+
this.questionsBaselinePendingReconcile.set(true);
|
|
3316
|
+
this.recompute();
|
|
3317
|
+
this.eventService.publish(AXPEntityEventsKeys.REFRESH_LAYOUT, {
|
|
3318
|
+
name: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}`,
|
|
3319
|
+
});
|
|
3320
|
+
// Success toast is shown by details-view when execute() returns success
|
|
3321
|
+
}
|
|
3322
|
+
return execResult;
|
|
3323
|
+
}
|
|
3324
|
+
//#endregion
|
|
3325
|
+
//#region ---- UI Handlers ----
|
|
3326
|
+
/** Updates local context when the builder emits a new questions value. Skip if unchanged to avoid CD loop. */
|
|
3327
|
+
onQuestionsChange(value) {
|
|
3328
|
+
if (this.ignoreNextValueChange()) {
|
|
3329
|
+
this.ignoreNextValueChange.set(false);
|
|
3330
|
+
return;
|
|
3331
|
+
}
|
|
3332
|
+
const current = this.questionsValue();
|
|
3333
|
+
if (this.areQuestionsEqual(current ?? undefined, value ?? undefined)) {
|
|
3334
|
+
if (this.questionsBaselinePendingReconcile()) {
|
|
3335
|
+
const aligned = current ?? value;
|
|
3336
|
+
this.baselineQuestions.set(this.cloneQuestions(aligned ?? undefined));
|
|
3337
|
+
this.questionsBaselinePendingReconcile.set(false);
|
|
3338
|
+
this.isDirty.set(false);
|
|
3339
|
+
}
|
|
3340
|
+
return;
|
|
3341
|
+
}
|
|
3342
|
+
const base = this.localContext() ?? this.rootContext() ?? {};
|
|
3343
|
+
if (this.questionsBaselinePendingReconcile() && this.localContext() == null) {
|
|
3344
|
+
this.baselineQuestions.set(this.cloneQuestions(value));
|
|
3345
|
+
this.isDirty.set(false);
|
|
3346
|
+
this.questionsBaselinePendingReconcile.set(false);
|
|
3347
|
+
this.localContext.set({ ...base, questions: value });
|
|
3348
|
+
this.recompute();
|
|
3349
|
+
return;
|
|
3350
|
+
}
|
|
3351
|
+
this.localContext.set({ ...base, questions: value });
|
|
3352
|
+
const baseline = this.baselineQuestions();
|
|
3353
|
+
const dirty = !this.areQuestionsEqual(baseline, value);
|
|
3354
|
+
this.isDirty.set(dirty);
|
|
3355
|
+
this.recompute();
|
|
3356
|
+
}
|
|
3357
|
+
//#endregion
|
|
3358
|
+
//#region ---- Utility Methods ----
|
|
3359
|
+
areQuestionsEqual(a, b) {
|
|
3360
|
+
return isEqual(a, b);
|
|
3361
|
+
}
|
|
3362
|
+
cloneQuestions(value) {
|
|
3363
|
+
if (isNil(value))
|
|
3364
|
+
return value;
|
|
3365
|
+
return cloneDeep(value);
|
|
3366
|
+
}
|
|
3367
|
+
recompute() {
|
|
3368
|
+
super.recompute();
|
|
3369
|
+
const maybeLayout = this.hostPageLayout;
|
|
3370
|
+
maybeLayout.recompute?.();
|
|
3371
|
+
}
|
|
3372
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3373
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.9", type: AXMQuestionnaireQuestionsPageComponent, isStandalone: true, selector: "axm-questionnaire-questions-page", inputs: { rootContext: { classPropertyName: "rootContext", publicName: "rootContext", isSignal: true, isRequired: false, transformFunction: null }, pageConfig: { classPropertyName: "pageConfig", publicName: "pageConfig", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
3374
|
+
{
|
|
3375
|
+
provide: AXPPageLayoutBase,
|
|
3376
|
+
useExisting: AXMQuestionnaireQuestionsPageComponent,
|
|
3377
|
+
},
|
|
3378
|
+
], viewQueries: [{ propertyName: "builderRef", first: true, predicate: ["builderRef"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
3379
|
+
<axm-questionnaire-questions-builder
|
|
3380
|
+
#builderRef
|
|
3381
|
+
[value]="questionsValue()"
|
|
3382
|
+
[prePostConfig]="prePostConfig()"
|
|
3383
|
+
[displaySettingsInput]="entityDisplaySettings()"
|
|
3384
|
+
[questionnaireEntityId]="questionnaireEntityId()"
|
|
3385
|
+
[showHeader]="false"
|
|
3386
|
+
(valueChange)="onQuestionsChange($event)">
|
|
3387
|
+
</axm-questionnaire-questions-builder>
|
|
3388
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AXMQuestionnaireQuestionsBuilderComponent, selector: "axm-questionnaire-questions-builder", inputs: ["value", "readonly", "prePostConfig", "showHeader", "displaySettingsInput", "questionnaireEntityId"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3389
|
+
}
|
|
3390
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsPageComponent, decorators: [{
|
|
3391
|
+
type: Component,
|
|
3392
|
+
args: [{
|
|
3393
|
+
selector: 'axm-questionnaire-questions-page',
|
|
3394
|
+
standalone: true,
|
|
3395
|
+
imports: [AXMQuestionnaireQuestionsBuilderComponent],
|
|
3396
|
+
template: `
|
|
3397
|
+
<axm-questionnaire-questions-builder
|
|
3398
|
+
#builderRef
|
|
3399
|
+
[value]="questionsValue()"
|
|
3400
|
+
[prePostConfig]="prePostConfig()"
|
|
3401
|
+
[displaySettingsInput]="entityDisplaySettings()"
|
|
3402
|
+
[questionnaireEntityId]="questionnaireEntityId()"
|
|
3403
|
+
[showHeader]="false"
|
|
3404
|
+
(valueChange)="onQuestionsChange($event)">
|
|
3405
|
+
</axm-questionnaire-questions-builder>
|
|
3406
|
+
`,
|
|
3407
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
3408
|
+
providers: [
|
|
3409
|
+
{
|
|
3410
|
+
provide: AXPPageLayoutBase,
|
|
3411
|
+
useExisting: AXMQuestionnaireQuestionsPageComponent,
|
|
3412
|
+
},
|
|
3413
|
+
],
|
|
3414
|
+
}]
|
|
3415
|
+
}], ctorParameters: () => [], propDecorators: { rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], builderRef: [{ type: i0.ViewChild, args: ['builderRef', { isSignal: true }] }] } });
|
|
3416
|
+
|
|
3417
|
+
var questionnaireQuestionsPage_component = /*#__PURE__*/Object.freeze({
|
|
3418
|
+
__proto__: null,
|
|
3419
|
+
AXMQuestionnaireQuestionsPageComponent: AXMQuestionnaireQuestionsPageComponent
|
|
3420
|
+
});
|
|
3421
|
+
|
|
3422
|
+
//#region ---- Questionnaire Questions Page Component Provider ----
|
|
3423
|
+
class AXMQuestionnaireQuestionsPageComponentProvider {
|
|
3424
|
+
async components() {
|
|
3425
|
+
return [
|
|
3426
|
+
{
|
|
3427
|
+
key: QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY,
|
|
3428
|
+
loader: () => Promise.resolve().then(function () { return questionnaireQuestionsPage_component; }).then((m) => m.AXMQuestionnaireQuestionsPageComponent),
|
|
3429
|
+
},
|
|
3430
|
+
];
|
|
3431
|
+
}
|
|
3432
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsPageComponentProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3433
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsPageComponentProvider }); }
|
|
3434
|
+
}
|
|
3435
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireQuestionsPageComponentProvider, decorators: [{
|
|
3436
|
+
type: Injectable
|
|
3437
|
+
}] });
|
|
3438
|
+
|
|
3439
|
+
var index$1 = /*#__PURE__*/Object.freeze({
|
|
3440
|
+
__proto__: null,
|
|
3441
|
+
AXMQuestionnaireQuestionsPageComponent: AXMQuestionnaireQuestionsPageComponent,
|
|
3442
|
+
AXMQuestionnaireQuestionsPageComponentProvider: AXMQuestionnaireQuestionsPageComponentProvider,
|
|
3443
|
+
AXMSaveQuestionnaireQuestionsCommand: AXMSaveQuestionnaireQuestionsCommand,
|
|
3444
|
+
QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY: QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY,
|
|
3445
|
+
QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND: QUESTIONNAIRE_QUESTIONS_SAVE_COMMAND
|
|
3446
|
+
});
|
|
3447
|
+
|
|
3448
|
+
//#region ---- Questions builder exports ----
|
|
3449
|
+
//#endregion
|
|
3450
|
+
|
|
3451
|
+
//#region ---- Imports ----
|
|
3452
|
+
//#endregion
|
|
3453
|
+
//#region ---- Select options ----
|
|
3454
|
+
/** i18n keys for comparison operator select options. */
|
|
3455
|
+
const OUTCOME_DISPLAY_OPERATOR_LABEL_KEYS = {
|
|
3456
|
+
eq: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.eq',
|
|
3457
|
+
neq: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.neq',
|
|
3458
|
+
gt: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.gt',
|
|
3459
|
+
gte: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.gte',
|
|
3460
|
+
lt: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.lt',
|
|
3461
|
+
lte: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-operator.options.lte',
|
|
3462
|
+
};
|
|
3463
|
+
/** i18n keys for emphasis select options. */
|
|
3464
|
+
const OUTCOME_DISPLAY_EMPHASIS_LABEL_KEYS = {
|
|
3465
|
+
normal: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-emphasis.options.normal',
|
|
3466
|
+
medium: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-emphasis.options.medium',
|
|
3467
|
+
bold: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-emphasis.options.bold',
|
|
3468
|
+
};
|
|
3469
|
+
const OUTCOME_DISPLAY_OPERATOR_SELECT_OPTIONS = Object.keys(OUTCOME_DISPLAY_OPERATOR_LABEL_KEYS).map((id) => ({
|
|
3470
|
+
id,
|
|
3471
|
+
title: OUTCOME_DISPLAY_OPERATOR_LABEL_KEYS[id],
|
|
3472
|
+
}));
|
|
3473
|
+
const OUTCOME_DISPLAY_OPERATOR_STRING_SELECT_OPTIONS = OUTCOME_DISPLAY_OPERATOR_SELECT_OPTIONS.filter((option) => option.id === 'eq' || option.id === 'neq');
|
|
3474
|
+
const OUTCOME_DISPLAY_OPERATOR_BOOLEAN_SELECT_OPTIONS = OUTCOME_DISPLAY_OPERATOR_SELECT_OPTIONS.filter((option) => option.id === 'eq');
|
|
3475
|
+
const OUTCOME_DISPLAY_EMPHASIS_SELECT_OPTIONS = Object.keys(OUTCOME_DISPLAY_EMPHASIS_LABEL_KEYS).map((id) => ({
|
|
3476
|
+
id,
|
|
3477
|
+
title: OUTCOME_DISPLAY_EMPHASIS_LABEL_KEYS[id],
|
|
3478
|
+
}));
|
|
3479
|
+
function toOutcomeDisplayOperatorSelectValue(operator) {
|
|
3480
|
+
return { id: operator, title: OUTCOME_DISPLAY_OPERATOR_LABEL_KEYS[operator] };
|
|
3481
|
+
}
|
|
3482
|
+
function toOutcomeDisplayEmphasisSelectValue(emphasis) {
|
|
3483
|
+
return { id: emphasis, title: OUTCOME_DISPLAY_EMPHASIS_LABEL_KEYS[emphasis] };
|
|
3484
|
+
}
|
|
3485
|
+
//#endregion
|
|
3486
|
+
|
|
3487
|
+
//#region ---- Imports ----
|
|
3488
|
+
//#endregion
|
|
3489
|
+
//#region ---- Result kind labels ----
|
|
3490
|
+
/** i18n keys for select options (property viewer). */
|
|
3491
|
+
const OUTCOME_RESULT_KIND_LABEL_KEYS = {
|
|
3492
|
+
number: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.result-kind.options.number',
|
|
3493
|
+
string: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.result-kind.options.string',
|
|
3494
|
+
boolean: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.result-kind.options.boolean',
|
|
3495
|
+
};
|
|
3496
|
+
/**
|
|
3497
|
+
* Sync labels for list badges — mirrors i18n `result-kind.options` (en-US Title Case).
|
|
3498
|
+
* Select/editor fields still use {@link OUTCOME_RESULT_KIND_LABEL_KEYS} with the translate pipe.
|
|
3499
|
+
*/
|
|
3500
|
+
const OUTCOME_RESULT_KIND_LABELS = {
|
|
3501
|
+
number: createMultiLanguageString('Number', 'عدد'),
|
|
3502
|
+
string: createMultiLanguageString('Text', 'متن'),
|
|
3503
|
+
boolean: createMultiLanguageString('Yes / No', 'بله / خیر'),
|
|
3504
|
+
};
|
|
3505
|
+
const OUTCOME_RESULT_KIND_SELECT_OPTIONS = Object.keys(OUTCOME_RESULT_KIND_LABEL_KEYS).map((id) => ({
|
|
3506
|
+
id,
|
|
3507
|
+
title: OUTCOME_RESULT_KIND_LABEL_KEYS[id],
|
|
3508
|
+
}));
|
|
3509
|
+
function resolveOutcomeResultKindLabel(kind, locale) {
|
|
3510
|
+
return resolveMultiLanguageString(OUTCOME_RESULT_KIND_LABELS[kind], locale);
|
|
3511
|
+
}
|
|
3512
|
+
function toOutcomeResultKindSelectValue(kind) {
|
|
3513
|
+
return { id: kind, title: OUTCOME_RESULT_KIND_LABEL_KEYS[kind] };
|
|
3514
|
+
}
|
|
3515
|
+
//#endregion
|
|
3516
|
+
|
|
3517
|
+
//#region ---- Imports ----
|
|
3518
|
+
//#endregion
|
|
3519
|
+
//#region ---- Groups ----
|
|
3520
|
+
const GROUP_BASIC = {
|
|
3521
|
+
name: 'basic-info',
|
|
3522
|
+
title: '@general:terms.interface.basic-info',
|
|
3523
|
+
order: 0,
|
|
3524
|
+
};
|
|
3525
|
+
const GROUP_RESULT = {
|
|
3526
|
+
name: 'result',
|
|
3527
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.groups.result',
|
|
3528
|
+
order: 1,
|
|
3529
|
+
};
|
|
3530
|
+
const GROUP_DISPLAY_RULES = {
|
|
3531
|
+
name: 'display-rules',
|
|
3532
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.groups.display-rules',
|
|
3533
|
+
order: 2,
|
|
3534
|
+
};
|
|
3535
|
+
const RESULT_KIND_OPTIONS = OUTCOME_RESULT_KIND_SELECT_OPTIONS;
|
|
3536
|
+
const DISPLAY_RULE_GRID_CELL = {
|
|
3537
|
+
alignSelf: 'center',
|
|
3538
|
+
alignItems: 'center',
|
|
3539
|
+
justifyContent: 'center',
|
|
3540
|
+
};
|
|
3541
|
+
const COMPARE_VALUE_PLACEHOLDER = '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-compare-value.placeholder';
|
|
3542
|
+
//#endregion
|
|
3543
|
+
//#region ---- Display rule row layout (result-kind aware) ----
|
|
3544
|
+
function buildDisplayRuleOperatorWidget(resultKind) {
|
|
3545
|
+
const dataSource = resultKind === 'boolean'
|
|
3546
|
+
? OUTCOME_DISPLAY_OPERATOR_BOOLEAN_SELECT_OPTIONS
|
|
3547
|
+
: resultKind === 'string'
|
|
3548
|
+
? OUTCOME_DISPLAY_OPERATOR_STRING_SELECT_OPTIONS
|
|
3549
|
+
: OUTCOME_DISPLAY_OPERATOR_SELECT_OPTIONS;
|
|
3550
|
+
return {
|
|
3551
|
+
type: AXPWidgetsCatalog.select,
|
|
3552
|
+
mode: 'edit',
|
|
3553
|
+
path: 'operator',
|
|
3554
|
+
name: 'operator',
|
|
3555
|
+
options: {
|
|
3556
|
+
valueField: 'id',
|
|
3557
|
+
textField: 'title',
|
|
3558
|
+
dataSource: [...dataSource],
|
|
3559
|
+
},
|
|
3560
|
+
};
|
|
3561
|
+
}
|
|
3562
|
+
function buildDisplayRuleCompareValueWidget(resultKind) {
|
|
3563
|
+
if (resultKind === 'boolean') {
|
|
3564
|
+
return {
|
|
3565
|
+
type: AXPWidgetsCatalog.toggle,
|
|
3566
|
+
mode: 'edit',
|
|
3567
|
+
path: 'compareValue',
|
|
3568
|
+
name: 'compareValue',
|
|
3569
|
+
options: {},
|
|
3570
|
+
};
|
|
3571
|
+
}
|
|
3572
|
+
if (resultKind === 'string') {
|
|
3573
|
+
return {
|
|
3574
|
+
type: AXPWidgetsCatalog.text,
|
|
3575
|
+
mode: 'edit',
|
|
3576
|
+
path: 'compareValue',
|
|
3577
|
+
name: 'compareValue',
|
|
3578
|
+
options: {
|
|
3579
|
+
placeholder: COMPARE_VALUE_PLACEHOLDER,
|
|
3580
|
+
},
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3583
|
+
return {
|
|
3584
|
+
type: AXPWidgetsCatalog.number,
|
|
3585
|
+
mode: 'edit',
|
|
3586
|
+
path: 'compareValue',
|
|
3587
|
+
name: 'compareValue',
|
|
3588
|
+
options: {
|
|
3589
|
+
placeholder: COMPARE_VALUE_PLACEHOLDER,
|
|
3590
|
+
},
|
|
3591
|
+
};
|
|
3592
|
+
}
|
|
3593
|
+
function buildDisplayRuleRepeaterChildren(resultKind) {
|
|
3594
|
+
return [
|
|
3595
|
+
{
|
|
3596
|
+
type: AXPWidgetsCatalog.grid,
|
|
3597
|
+
mode: 'edit',
|
|
3598
|
+
options: {
|
|
3599
|
+
width: '100%',
|
|
3600
|
+
grid: {
|
|
3601
|
+
default: {
|
|
3602
|
+
columns: 12,
|
|
3603
|
+
gap: '8px',
|
|
3604
|
+
alignItems: 'center',
|
|
3605
|
+
},
|
|
3606
|
+
},
|
|
3607
|
+
},
|
|
3608
|
+
children: [
|
|
3609
|
+
{
|
|
3610
|
+
type: AXPWidgetsCatalog.gridItem,
|
|
3611
|
+
mode: 'edit',
|
|
3612
|
+
options: { colSpan: 3, ...DISPLAY_RULE_GRID_CELL },
|
|
3613
|
+
children: [buildDisplayRuleOperatorWidget(resultKind)],
|
|
3614
|
+
},
|
|
3615
|
+
{
|
|
3616
|
+
type: AXPWidgetsCatalog.gridItem,
|
|
3617
|
+
mode: 'edit',
|
|
3618
|
+
options: { colSpan: 2, ...DISPLAY_RULE_GRID_CELL },
|
|
3619
|
+
children: [buildDisplayRuleCompareValueWidget(resultKind)],
|
|
3620
|
+
},
|
|
3621
|
+
{
|
|
3622
|
+
type: AXPWidgetsCatalog.gridItem,
|
|
3623
|
+
mode: 'edit',
|
|
3624
|
+
options: { colSpan: 3, ...DISPLAY_RULE_GRID_CELL },
|
|
3625
|
+
children: [
|
|
3626
|
+
{
|
|
3627
|
+
type: AXPWidgetsCatalog.themeColorChooser,
|
|
3628
|
+
mode: 'edit',
|
|
3629
|
+
path: 'color',
|
|
3630
|
+
name: 'color',
|
|
3631
|
+
options: {
|
|
3632
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-color.placeholder',
|
|
3633
|
+
},
|
|
3634
|
+
},
|
|
3635
|
+
],
|
|
3636
|
+
},
|
|
3637
|
+
{
|
|
3638
|
+
type: AXPWidgetsCatalog.gridItem,
|
|
3639
|
+
mode: 'edit',
|
|
3640
|
+
options: { colSpan: 2, ...DISPLAY_RULE_GRID_CELL },
|
|
3641
|
+
children: [
|
|
3642
|
+
{
|
|
3643
|
+
type: AXPWidgetsCatalog.select,
|
|
3644
|
+
mode: 'edit',
|
|
3645
|
+
path: 'emphasis',
|
|
3646
|
+
name: 'emphasis',
|
|
3647
|
+
options: {
|
|
3648
|
+
valueField: 'id',
|
|
3649
|
+
textField: 'title',
|
|
3650
|
+
dataSource: [...OUTCOME_DISPLAY_EMPHASIS_SELECT_OPTIONS],
|
|
3651
|
+
},
|
|
3652
|
+
},
|
|
3653
|
+
],
|
|
3654
|
+
},
|
|
3655
|
+
{
|
|
3656
|
+
type: AXPWidgetsCatalog.gridItem,
|
|
3657
|
+
mode: 'edit',
|
|
3658
|
+
options: { colSpan: 2, ...DISPLAY_RULE_GRID_CELL },
|
|
3659
|
+
children: [
|
|
3660
|
+
{
|
|
3661
|
+
type: AXPWidgetsCatalog.iconChooser,
|
|
3662
|
+
mode: 'edit',
|
|
3663
|
+
path: 'icon',
|
|
3664
|
+
name: 'icon',
|
|
3665
|
+
options: {},
|
|
3666
|
+
},
|
|
3667
|
+
],
|
|
3668
|
+
},
|
|
3669
|
+
],
|
|
3670
|
+
},
|
|
3671
|
+
];
|
|
3672
|
+
}
|
|
3673
|
+
function buildDisplayRulesProps(resultKind) {
|
|
3674
|
+
return [
|
|
3675
|
+
{
|
|
3676
|
+
name: 'displayRules',
|
|
3677
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-rules.title',
|
|
3678
|
+
description: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.display-rules.description',
|
|
3679
|
+
group: GROUP_DISPLAY_RULES,
|
|
3680
|
+
order: 10,
|
|
3681
|
+
showLabel: false,
|
|
3682
|
+
schema: {
|
|
3683
|
+
dataType: 'array',
|
|
3684
|
+
defaultValue: [],
|
|
3685
|
+
nullable: true,
|
|
3686
|
+
interface: {
|
|
3687
|
+
name: 'displayRules',
|
|
3688
|
+
path: 'displayRules',
|
|
3689
|
+
type: AXPWidgetsCatalog.repeaterLayout,
|
|
3690
|
+
options: {
|
|
3691
|
+
hasControls: true,
|
|
3692
|
+
allowReorder: true,
|
|
3693
|
+
width: '100%',
|
|
3694
|
+
},
|
|
3695
|
+
children: buildDisplayRuleRepeaterChildren(resultKind),
|
|
3696
|
+
},
|
|
3697
|
+
},
|
|
3698
|
+
visible: true,
|
|
3699
|
+
},
|
|
3700
|
+
];
|
|
3701
|
+
}
|
|
3702
|
+
//#endregion
|
|
3703
|
+
//#region ---- Properties ----
|
|
3704
|
+
const BASIC_PROPS = [
|
|
3705
|
+
{
|
|
3706
|
+
name: 'name',
|
|
3707
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.name.title',
|
|
3708
|
+
group: GROUP_BASIC,
|
|
3709
|
+
order: 10,
|
|
3710
|
+
schema: {
|
|
3711
|
+
dataType: 'string',
|
|
3712
|
+
defaultValue: '',
|
|
3713
|
+
interface: {
|
|
3714
|
+
name: 'name',
|
|
3715
|
+
path: 'name',
|
|
3716
|
+
type: AXPWidgetsCatalog.text,
|
|
3717
|
+
options: {
|
|
3718
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.name.placeholder',
|
|
3719
|
+
},
|
|
3720
|
+
},
|
|
3721
|
+
},
|
|
3722
|
+
validations: [{ rule: 'required' }, { rule: 'variable-name' }],
|
|
3723
|
+
visible: true,
|
|
3724
|
+
},
|
|
3725
|
+
{
|
|
3726
|
+
name: 'title',
|
|
3727
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.title.title',
|
|
3728
|
+
group: GROUP_BASIC,
|
|
3729
|
+
order: 20,
|
|
3730
|
+
schema: {
|
|
3731
|
+
dataType: 'string',
|
|
3732
|
+
defaultValue: '',
|
|
3733
|
+
interface: {
|
|
3734
|
+
name: 'title',
|
|
3735
|
+
path: 'title',
|
|
3736
|
+
type: AXPWidgetsCatalog.text,
|
|
3737
|
+
options: {
|
|
3738
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.title.placeholder',
|
|
3739
|
+
},
|
|
3740
|
+
},
|
|
3741
|
+
},
|
|
3742
|
+
validations: [{ rule: 'required' }],
|
|
3743
|
+
visible: true,
|
|
3744
|
+
},
|
|
3745
|
+
{
|
|
3746
|
+
name: 'description',
|
|
3747
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.description.title',
|
|
3748
|
+
group: GROUP_BASIC,
|
|
3749
|
+
order: 30,
|
|
3750
|
+
schema: {
|
|
3751
|
+
dataType: 'string',
|
|
3752
|
+
defaultValue: '',
|
|
3753
|
+
interface: {
|
|
3754
|
+
name: 'description',
|
|
3755
|
+
path: 'description',
|
|
3756
|
+
type: AXPWidgetsCatalog.largeText,
|
|
3757
|
+
options: {
|
|
3758
|
+
rows: 3,
|
|
3759
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.description.placeholder',
|
|
3760
|
+
},
|
|
3761
|
+
},
|
|
3762
|
+
},
|
|
3763
|
+
visible: true,
|
|
3764
|
+
},
|
|
3765
|
+
];
|
|
3766
|
+
const RESULT_PROPS = [
|
|
3767
|
+
{
|
|
3768
|
+
name: 'resultKind',
|
|
3769
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.result-kind.title',
|
|
3770
|
+
group: GROUP_RESULT,
|
|
3771
|
+
order: 10,
|
|
3772
|
+
schema: {
|
|
3773
|
+
dataType: 'string',
|
|
3774
|
+
defaultValue: { id: 'number', title: RESULT_KIND_OPTIONS[0].title },
|
|
3775
|
+
interface: {
|
|
3776
|
+
name: 'resultKind',
|
|
3777
|
+
path: 'resultKind',
|
|
3778
|
+
type: AXPWidgetsCatalog.select,
|
|
3779
|
+
options: {
|
|
3780
|
+
valueField: 'id',
|
|
3781
|
+
textField: 'title',
|
|
3782
|
+
dataSource: [...RESULT_KIND_OPTIONS],
|
|
3783
|
+
},
|
|
3784
|
+
},
|
|
3785
|
+
},
|
|
3786
|
+
validations: [{ rule: 'required' }],
|
|
3787
|
+
visible: true,
|
|
3788
|
+
},
|
|
3789
|
+
{
|
|
3790
|
+
name: 'expression',
|
|
3791
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.expression.title',
|
|
3792
|
+
group: GROUP_RESULT,
|
|
3793
|
+
order: 20,
|
|
3794
|
+
schema: {
|
|
3795
|
+
dataType: 'string',
|
|
3796
|
+
defaultValue: '',
|
|
3797
|
+
interface: {
|
|
3798
|
+
name: 'expression',
|
|
3799
|
+
path: 'expression',
|
|
3800
|
+
type: 'code-editor',
|
|
3801
|
+
options: {
|
|
3802
|
+
language: 'javascript',
|
|
3803
|
+
lineNumbers: true,
|
|
3804
|
+
height: 'min-h-72',
|
|
3805
|
+
placeholder: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.fields.expression.placeholder',
|
|
3806
|
+
},
|
|
3807
|
+
},
|
|
3808
|
+
},
|
|
3809
|
+
validations: [{ rule: 'required' }],
|
|
3810
|
+
visible: true,
|
|
3811
|
+
},
|
|
3812
|
+
];
|
|
3813
|
+
//#endregion
|
|
3814
|
+
//#region ---- Tabs ----
|
|
3815
|
+
/** Builds outcome edit tabs; display-rule value widgets match the selected result kind. */
|
|
3816
|
+
function buildQuestionnaireOutcomeEditTabs(resultKind = 'number') {
|
|
3817
|
+
return [
|
|
3818
|
+
{
|
|
3819
|
+
name: 'general',
|
|
3820
|
+
title: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.tabs.general.title',
|
|
3821
|
+
groups: [
|
|
3822
|
+
{
|
|
3823
|
+
name: GROUP_BASIC.name,
|
|
3824
|
+
title: GROUP_BASIC.title,
|
|
3825
|
+
isCollapsed: false,
|
|
3826
|
+
props: BASIC_PROPS,
|
|
3827
|
+
},
|
|
3828
|
+
{
|
|
3829
|
+
name: GROUP_RESULT.name,
|
|
3830
|
+
title: GROUP_RESULT.title,
|
|
3831
|
+
isCollapsed: false,
|
|
3832
|
+
props: RESULT_PROPS,
|
|
3833
|
+
},
|
|
3834
|
+
{
|
|
3835
|
+
name: GROUP_DISPLAY_RULES.name,
|
|
3836
|
+
title: GROUP_DISPLAY_RULES.title,
|
|
3837
|
+
isCollapsed: false,
|
|
3838
|
+
props: buildDisplayRulesProps(resultKind),
|
|
3839
|
+
},
|
|
3840
|
+
],
|
|
3841
|
+
},
|
|
3842
|
+
];
|
|
3843
|
+
}
|
|
3844
|
+
//#endregion
|
|
3845
|
+
|
|
3846
|
+
//#region ---- Imports ----
|
|
3847
|
+
//#endregion
|
|
3848
|
+
//#region ---- Mapping ----
|
|
3849
|
+
function outcomeItemToBuilderItem(item, index) {
|
|
3850
|
+
return {
|
|
3851
|
+
id: item.id,
|
|
3852
|
+
name: item.name,
|
|
3853
|
+
order: item.order ?? index,
|
|
3854
|
+
title: item.title,
|
|
3855
|
+
description: item.description,
|
|
3856
|
+
resultKind: item.resultKind,
|
|
3857
|
+
expression: item.expression,
|
|
3858
|
+
displayRules: item.displayRules,
|
|
3859
|
+
isNewlyAdded: item.isNewlyAdded,
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
function builderItemToOutcomeItem(item, index) {
|
|
3863
|
+
return {
|
|
3864
|
+
id: String(item.id ?? item['name'] ?? AXPDataGenerator.uuid()),
|
|
3865
|
+
name: String(item['name'] ?? ''),
|
|
3866
|
+
title: item['title'],
|
|
3867
|
+
description: item['description'],
|
|
3868
|
+
resultKind: (item['resultKind'] ?? 'number'),
|
|
3869
|
+
expression: String(item['expression'] ?? ''),
|
|
3870
|
+
displayRules: item['displayRules'],
|
|
3871
|
+
order: item.order ?? index,
|
|
3872
|
+
isNewlyAdded: item['isNewlyAdded'] === true,
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
function sectionToBuilderSection(section, index) {
|
|
3876
|
+
const name = section.name.trim() || `section-${index + 1}`;
|
|
3877
|
+
return {
|
|
3878
|
+
id: name,
|
|
3879
|
+
name,
|
|
3880
|
+
order: section.order ?? index,
|
|
3881
|
+
title: section.title,
|
|
3882
|
+
description: section.description,
|
|
3883
|
+
isNewlyAdded: section.isNewlyAdded,
|
|
3884
|
+
items: (section.items ?? []).map((item, itemIndex) => outcomeItemToBuilderItem(item, itemIndex)),
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3887
|
+
function builderSectionToOutcomeSection(section, index) {
|
|
3888
|
+
const name = String(section['name'] ?? section.id ?? '').trim() || `section-${index + 1}`;
|
|
3889
|
+
return {
|
|
3890
|
+
name,
|
|
3891
|
+
title: section['title'],
|
|
3892
|
+
description: section['description'],
|
|
3893
|
+
order: section.order ?? index,
|
|
3894
|
+
isNewlyAdded: section['isNewlyAdded'] === true,
|
|
3895
|
+
items: section.items.map((item, itemIndex) => builderItemToOutcomeItem(item, itemIndex)),
|
|
3896
|
+
};
|
|
3897
|
+
}
|
|
3898
|
+
function outcomesValueToBuilderValue(value) {
|
|
3899
|
+
const normalized = normalizeQuestionnaireOutcomesValue(value);
|
|
3900
|
+
return {
|
|
3901
|
+
sections: normalized.sections.map((section, index) => sectionToBuilderSection(section, index)),
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
function builderValueToOutcomesValue(value) {
|
|
3905
|
+
return {
|
|
3906
|
+
sections: value.sections.map((section, index) => builderSectionToOutcomeSection(section, index)),
|
|
3907
|
+
};
|
|
3908
|
+
}
|
|
3909
|
+
//#endregion
|
|
3910
|
+
|
|
3911
|
+
//#region ---- Imports ----
|
|
3912
|
+
//#endregion
|
|
3913
|
+
//#region ---- Helpers ----
|
|
3914
|
+
function normalizeOutcomeName(name) {
|
|
3915
|
+
return (name ?? '').trim();
|
|
3916
|
+
}
|
|
3917
|
+
function createDefaultOutcomeSection(order = 0) {
|
|
3918
|
+
return {
|
|
3919
|
+
name: `section-${Date.now()}`,
|
|
3920
|
+
title: 'New Section',
|
|
3921
|
+
order,
|
|
3922
|
+
items: [],
|
|
3923
|
+
isNewlyAdded: true,
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
//#endregion
|
|
3927
|
+
|
|
3928
|
+
//#region ---- Imports ----
|
|
3929
|
+
//#endregion
|
|
3930
|
+
//#region ---- Component ----
|
|
3931
|
+
class AXMQuestionnaireOutcomesBuilderComponent {
|
|
3932
|
+
//#endregion
|
|
3933
|
+
//#region ---- Lifecycle ----
|
|
3934
|
+
constructor() {
|
|
3935
|
+
//#region ---- Inputs / Outputs ----
|
|
3936
|
+
this.value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
3937
|
+
this.readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
3938
|
+
this.showHeader = input(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
|
|
3939
|
+
this.valueChange = output();
|
|
3940
|
+
//#endregion
|
|
3941
|
+
//#region ---- Services ----
|
|
3942
|
+
this.propertyViewerService = inject(AXPPropertyViewerService);
|
|
3943
|
+
this.translationService = inject(AXTranslationService);
|
|
3944
|
+
this.toastService = inject(AXToastService);
|
|
3945
|
+
//#endregion
|
|
3946
|
+
//#region ---- View references ----
|
|
3947
|
+
this.standardRef = viewChild(AXPStandardSectionItemsBuilderComponent, ...(ngDevMode ? [{ debugName: "standardRef" }] : /* istanbul ignore next */ []));
|
|
3948
|
+
//#endregion
|
|
3949
|
+
//#region ---- State ----
|
|
3950
|
+
this.builderValue = signal({ sections: [] }, ...(ngDevMode ? [{ debugName: "builderValue" }] : /* istanbul ignore next */ []));
|
|
3951
|
+
//#endregion
|
|
3952
|
+
//#region ---- Computed ----
|
|
3953
|
+
this.standardConfig = computed(() => ({
|
|
3954
|
+
showSectionTechnicalName: true,
|
|
3955
|
+
minSectionCount: 1,
|
|
3956
|
+
texts: {
|
|
3957
|
+
addSection: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-section.title',
|
|
3958
|
+
addItem: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-outcome.title',
|
|
3959
|
+
emptySectionsTitle: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.empty.no-sections.title',
|
|
3960
|
+
emptySectionsDescription: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.empty.no-sections.description',
|
|
3961
|
+
emptyItemsTitle: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.empty.empty-section.title',
|
|
3962
|
+
emptyItemsDescription: '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.empty.empty-section.description',
|
|
3963
|
+
},
|
|
3964
|
+
mapItemToView: (item, _section) => this.mapOutcomeItemToView(item),
|
|
3965
|
+
promptAddItems: (sectionId, value) => this.promptAddOutcome(sectionId, value),
|
|
3966
|
+
promptEditItem: (item, sectionId, value) => this.promptEditOutcome(item, sectionId, value),
|
|
3967
|
+
}), ...(ngDevMode ? [{ debugName: "standardConfig" }] : /* istanbul ignore next */ []));
|
|
3968
|
+
effect(() => {
|
|
3969
|
+
const next = normalizeQuestionnaireOutcomesValue(this.value());
|
|
3970
|
+
const mapped = outcomesValueToBuilderValue(next);
|
|
3971
|
+
untracked(() => this.builderValue.set(this.ensureMinOneSection(mapped)));
|
|
3972
|
+
});
|
|
3973
|
+
}
|
|
3974
|
+
//#endregion
|
|
3975
|
+
//#region ---- Public API ----
|
|
3976
|
+
/** Page header command: delegates to standard builder add-section dialog. */
|
|
3977
|
+
async addSection() {
|
|
3978
|
+
await this.standardRef()?.addSection();
|
|
3979
|
+
}
|
|
3980
|
+
//#endregion
|
|
3981
|
+
//#region ---- Builder handlers ----
|
|
3982
|
+
onBuilderValueChange(next) {
|
|
3983
|
+
const normalized = this.ensureMinOneSection(next);
|
|
3984
|
+
this.builderValue.set(normalized);
|
|
3985
|
+
this.valueChange.emit(builderValueToOutcomesValue(normalized));
|
|
3986
|
+
}
|
|
3987
|
+
//#endregion
|
|
3988
|
+
//#region ---- Item mapping ----
|
|
3989
|
+
mapOutcomeItemToView(item) {
|
|
3990
|
+
const outcome = item;
|
|
3991
|
+
const locale = this.translationService.getActiveLang() ?? 'en-US';
|
|
3992
|
+
const title = resolveMultiLanguageString(outcome.title, locale).trim();
|
|
3993
|
+
const description = resolveMultiLanguageString(outcome.description, locale).trim();
|
|
3994
|
+
const badges = [];
|
|
3995
|
+
const kind = this.coerceResultKind(outcome.resultKind);
|
|
3996
|
+
badges.push({
|
|
3997
|
+
text: resolveOutcomeResultKindLabel(kind, locale),
|
|
3998
|
+
variant: 'neutral',
|
|
3999
|
+
});
|
|
4000
|
+
return {
|
|
4001
|
+
icon: 'fa-light fa-calculator',
|
|
4002
|
+
title: title || outcome.name || '—',
|
|
4003
|
+
name: outcome.name,
|
|
4004
|
+
description: description || undefined,
|
|
4005
|
+
badges,
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
//#endregion
|
|
4009
|
+
//#region ---- Prompts ----
|
|
4010
|
+
async promptAddOutcome(sectionId, value) {
|
|
4011
|
+
const section = value.sections.find((s) => s.id === sectionId);
|
|
4012
|
+
if (!section) {
|
|
4013
|
+
return null;
|
|
4014
|
+
}
|
|
4015
|
+
const takenNames = this.collectOutcomeNames(value);
|
|
4016
|
+
const defaultName = this.allocateOutcomeName(takenNames);
|
|
4017
|
+
const item = await this.openOutcomeDialog({
|
|
4018
|
+
mode: 'add',
|
|
4019
|
+
context: {
|
|
4020
|
+
name: defaultName,
|
|
4021
|
+
title: '',
|
|
4022
|
+
description: '',
|
|
4023
|
+
resultKind: toOutcomeResultKindSelectValue('number'),
|
|
4024
|
+
expression: '',
|
|
4025
|
+
displayRules: [],
|
|
4026
|
+
},
|
|
4027
|
+
sectionId,
|
|
4028
|
+
value,
|
|
4029
|
+
excludeItemId: undefined,
|
|
4030
|
+
});
|
|
4031
|
+
return item ? [item] : null;
|
|
4032
|
+
}
|
|
4033
|
+
async promptEditOutcome(item, sectionId, value) {
|
|
4034
|
+
const outcome = item;
|
|
4035
|
+
return this.openOutcomeDialog({
|
|
4036
|
+
mode: 'edit',
|
|
4037
|
+
context: {
|
|
4038
|
+
name: outcome.name,
|
|
4039
|
+
title: outcome.title ?? '',
|
|
4040
|
+
description: outcome.description ?? '',
|
|
4041
|
+
resultKind: toOutcomeResultKindSelectValue(this.coerceResultKind(outcome.resultKind)),
|
|
4042
|
+
expression: outcome.expression ?? '',
|
|
4043
|
+
displayRules: this.toDisplayRulesFormContext(outcome.displayRules),
|
|
4044
|
+
},
|
|
4045
|
+
sectionId,
|
|
4046
|
+
value,
|
|
4047
|
+
excludeItemId: item.id,
|
|
4048
|
+
existingItem: item,
|
|
4049
|
+
});
|
|
4050
|
+
}
|
|
4051
|
+
async openOutcomeDialog(options) {
|
|
4052
|
+
const validationFailed = async (titleKey, descKey, fallTitle, fallDesc) => {
|
|
4053
|
+
const title = (await this.translationService.translateAsync(titleKey)) || fallTitle;
|
|
4054
|
+
const content = (await this.translationService.translateAsync(descKey)) || fallDesc;
|
|
4055
|
+
this.toastService.show({ color: 'warning', title, content });
|
|
4056
|
+
throw new Error('QuestionnaireOutcomeEditValidation');
|
|
4057
|
+
};
|
|
4058
|
+
try {
|
|
4059
|
+
const titleKey = options.mode === 'add'
|
|
4060
|
+
? '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-outcome.title'
|
|
4061
|
+
: '@general:actions.edit.title';
|
|
4062
|
+
const initialResultKind = this.coerceResultKind(options.context.resultKind);
|
|
4063
|
+
const result = await this.propertyViewerService
|
|
4064
|
+
.create()
|
|
4065
|
+
.dialog((d) => {
|
|
4066
|
+
d.setTitle(titleKey)
|
|
4067
|
+
.setSize('lg')
|
|
4068
|
+
.setCloseButton(true)
|
|
4069
|
+
.setMode('advanced')
|
|
4070
|
+
.setTabs(buildQuestionnaireOutcomeEditTabs(initialResultKind))
|
|
4071
|
+
.setContext(options.context)
|
|
4072
|
+
.onAction(async (ref) => {
|
|
4073
|
+
const context = ref.context();
|
|
4074
|
+
const rawName = normalizeOutcomeName(context.name);
|
|
4075
|
+
if (!rawName) {
|
|
4076
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.name-required.title', '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.name-required.description', 'Name required', 'Enter a unique outcome name.');
|
|
4077
|
+
}
|
|
4078
|
+
if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(rawName)) {
|
|
4079
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.name-invalid.title', '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.name-invalid.description', 'Invalid name', 'Use letters, numbers, underscores, and hyphens.');
|
|
4080
|
+
}
|
|
4081
|
+
const taken = this.collectOutcomeNames(options.value, options.excludeItemId);
|
|
4082
|
+
if (taken.has(rawName)) {
|
|
4083
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.duplicate-name', '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.duplicate-name', 'Duplicate name', 'Another outcome already uses this name.');
|
|
4084
|
+
}
|
|
4085
|
+
const title = context.title;
|
|
4086
|
+
if (isEffectivelyEmptyLocalizedValue(title)) {
|
|
4087
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.title-required.title', '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.title-required.description', 'Title required', 'Enter a display title for this outcome.');
|
|
4088
|
+
}
|
|
4089
|
+
const expression = String(context.expression ?? '').trim();
|
|
4090
|
+
if (!expression) {
|
|
4091
|
+
await validationFailed('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.expression-required.title', '@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.expression-required.description', 'Expression required', 'Enter an expression for this outcome.');
|
|
4092
|
+
}
|
|
4093
|
+
});
|
|
4094
|
+
})
|
|
4095
|
+
.show();
|
|
4096
|
+
if (!result) {
|
|
4097
|
+
return null;
|
|
4098
|
+
}
|
|
4099
|
+
const form = result.values;
|
|
4100
|
+
const name = normalizeOutcomeName(form.name);
|
|
4101
|
+
const title = this.normalizeLocalizedField(form.title);
|
|
4102
|
+
const description = this.normalizeLocalizedField(form.description);
|
|
4103
|
+
const resultKind = this.coerceResultKind(form.resultKind);
|
|
4104
|
+
const expression = String(form.expression ?? '').trim();
|
|
4105
|
+
const displayRules = this.normalizeDisplayRulesFromForm(form.displayRules, resultKind);
|
|
4106
|
+
const id = options.mode === 'edit' && options.existingItem
|
|
4107
|
+
? String(options.existingItem.id)
|
|
4108
|
+
: AXPDataGenerator.uuid();
|
|
4109
|
+
return {
|
|
4110
|
+
...(options.existingItem ?? {}),
|
|
4111
|
+
id,
|
|
4112
|
+
name,
|
|
4113
|
+
title,
|
|
4114
|
+
description,
|
|
4115
|
+
resultKind,
|
|
4116
|
+
expression,
|
|
4117
|
+
displayRules,
|
|
4118
|
+
order: options.existingItem?.order ?? 0,
|
|
4119
|
+
isNewlyAdded: options.mode === 'add',
|
|
4120
|
+
};
|
|
4121
|
+
}
|
|
4122
|
+
catch (error) {
|
|
4123
|
+
if (error instanceof Error && error.message === 'QuestionnaireOutcomeEditValidation') {
|
|
4124
|
+
return null;
|
|
4125
|
+
}
|
|
4126
|
+
console.error('Error editing outcome:', error);
|
|
4127
|
+
return null;
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
//#endregion
|
|
4131
|
+
//#region ---- Utility ----
|
|
4132
|
+
ensureMinOneSection(value) {
|
|
4133
|
+
if (value.sections.length > 0) {
|
|
4134
|
+
return value;
|
|
4135
|
+
}
|
|
4136
|
+
const section = createDefaultOutcomeSection(0);
|
|
4137
|
+
return outcomesValueToBuilderValue({ sections: [section] });
|
|
4138
|
+
}
|
|
4139
|
+
collectOutcomeNames(value, excludeItemId) {
|
|
4140
|
+
const names = new Set();
|
|
4141
|
+
for (const section of value.sections) {
|
|
4142
|
+
for (const item of section.items) {
|
|
4143
|
+
if (excludeItemId != null && item.id === excludeItemId) {
|
|
4144
|
+
continue;
|
|
4145
|
+
}
|
|
4146
|
+
const name = normalizeOutcomeName(String(item['name'] ?? ''));
|
|
4147
|
+
if (name) {
|
|
4148
|
+
names.add(name);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
return names;
|
|
4153
|
+
}
|
|
4154
|
+
allocateOutcomeName(taken) {
|
|
4155
|
+
let index = taken.size + 1;
|
|
4156
|
+
let name = `outcome_${index}`;
|
|
4157
|
+
while (taken.has(name)) {
|
|
4158
|
+
index += 1;
|
|
4159
|
+
name = `outcome_${index}`;
|
|
4160
|
+
}
|
|
4161
|
+
return name;
|
|
4162
|
+
}
|
|
4163
|
+
coerceResultKind(value) {
|
|
4164
|
+
if (value === 'number' || value === 'string' || value === 'boolean') {
|
|
4165
|
+
return value;
|
|
4166
|
+
}
|
|
4167
|
+
if (value != null && typeof value === 'object' && 'id' in value) {
|
|
4168
|
+
const id = value.id;
|
|
4169
|
+
if (id === 'number' || id === 'string' || id === 'boolean') {
|
|
4170
|
+
return id;
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
return 'number';
|
|
4174
|
+
}
|
|
4175
|
+
coerceDisplayOperator(value, resultKind) {
|
|
4176
|
+
let operator;
|
|
4177
|
+
if (value === 'eq' || value === 'neq' || value === 'gt' || value === 'gte' || value === 'lt' || value === 'lte') {
|
|
4178
|
+
operator = value;
|
|
4179
|
+
}
|
|
4180
|
+
else if (value != null && typeof value === 'object' && 'id' in value) {
|
|
4181
|
+
const id = value.id;
|
|
4182
|
+
if (id === 'eq' || id === 'neq' || id === 'gt' || id === 'gte' || id === 'lt' || id === 'lte') {
|
|
4183
|
+
operator = id;
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
if (resultKind === 'boolean') {
|
|
4187
|
+
return operator === 'eq' || operator === 'neq' ? operator : 'eq';
|
|
4188
|
+
}
|
|
4189
|
+
if (resultKind === 'string') {
|
|
4190
|
+
return operator === 'eq' || operator === 'neq' ? operator : 'eq';
|
|
4191
|
+
}
|
|
4192
|
+
return operator ?? 'gte';
|
|
4193
|
+
}
|
|
4194
|
+
coerceDisplayCompareValue(value, resultKind) {
|
|
4195
|
+
if (resultKind === 'boolean') {
|
|
4196
|
+
if (typeof value === 'boolean') {
|
|
4197
|
+
return value;
|
|
4198
|
+
}
|
|
4199
|
+
if (value === 'true') {
|
|
4200
|
+
return true;
|
|
4201
|
+
}
|
|
4202
|
+
if (value === 'false') {
|
|
4203
|
+
return false;
|
|
4204
|
+
}
|
|
4205
|
+
return undefined;
|
|
4206
|
+
}
|
|
4207
|
+
if (resultKind === 'number') {
|
|
4208
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
4209
|
+
return value;
|
|
4210
|
+
}
|
|
4211
|
+
if (typeof value === 'string') {
|
|
4212
|
+
const trimmed = value.trim();
|
|
4213
|
+
if (!trimmed) {
|
|
4214
|
+
return undefined;
|
|
4215
|
+
}
|
|
4216
|
+
const asNumber = Number(trimmed);
|
|
4217
|
+
return Number.isFinite(asNumber) ? asNumber : undefined;
|
|
4218
|
+
}
|
|
4219
|
+
return undefined;
|
|
4220
|
+
}
|
|
4221
|
+
if (typeof value === 'string') {
|
|
4222
|
+
const trimmed = value.trim();
|
|
4223
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
4224
|
+
}
|
|
4225
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
4226
|
+
return String(value);
|
|
4227
|
+
}
|
|
4228
|
+
if (typeof value === 'boolean') {
|
|
4229
|
+
return value ? 'true' : 'false';
|
|
4230
|
+
}
|
|
4231
|
+
return undefined;
|
|
4232
|
+
}
|
|
4233
|
+
normalizeDisplayColorValue(value) {
|
|
4234
|
+
if (typeof value !== 'string') {
|
|
4235
|
+
return undefined;
|
|
4236
|
+
}
|
|
4237
|
+
const trimmed = value.trim();
|
|
4238
|
+
const parts = trimmed.split(/\s+/);
|
|
4239
|
+
if (parts.length !== 3) {
|
|
4240
|
+
return undefined;
|
|
4241
|
+
}
|
|
4242
|
+
return trimmed;
|
|
4243
|
+
}
|
|
4244
|
+
coerceDisplayEmphasis(value) {
|
|
4245
|
+
if (value === 'normal' || value === 'medium' || value === 'bold') {
|
|
4246
|
+
return value;
|
|
4247
|
+
}
|
|
4248
|
+
if (value != null && typeof value === 'object' && 'id' in value) {
|
|
4249
|
+
const id = value.id;
|
|
4250
|
+
if (id === 'normal' || id === 'medium' || id === 'bold') {
|
|
4251
|
+
return id;
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
return 'normal';
|
|
4255
|
+
}
|
|
4256
|
+
normalizeDisplayIconValue(value) {
|
|
4257
|
+
if (value == null || value === '') {
|
|
4258
|
+
return undefined;
|
|
4259
|
+
}
|
|
4260
|
+
if (typeof value === 'string') {
|
|
4261
|
+
const trimmed = value.trim();
|
|
4262
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
4263
|
+
}
|
|
4264
|
+
if (typeof value === 'object') {
|
|
4265
|
+
const styleClass = String(get(value, 'styleClass') ?? '').trim();
|
|
4266
|
+
const iconClass = String(get(value, 'iconClass') ?? '').trim();
|
|
4267
|
+
const combined = [styleClass, iconClass].filter(Boolean).join(' ');
|
|
4268
|
+
return combined.length > 0 ? combined : undefined;
|
|
4269
|
+
}
|
|
4270
|
+
return undefined;
|
|
4271
|
+
}
|
|
4272
|
+
toDisplayRulesFormContext(rules) {
|
|
4273
|
+
return normalizeQuestionnaireOutcomeDisplayRules(rules).map((rule) => ({
|
|
4274
|
+
id: rule.id,
|
|
4275
|
+
operator: toOutcomeDisplayOperatorSelectValue(rule.operator),
|
|
4276
|
+
compareValue: rule.compareValue,
|
|
4277
|
+
color: rule.color,
|
|
4278
|
+
emphasis: toOutcomeDisplayEmphasisSelectValue(rule.emphasis ?? 'normal'),
|
|
4279
|
+
icon: rule.icon,
|
|
4280
|
+
}));
|
|
4281
|
+
}
|
|
4282
|
+
normalizeDisplayRulesFromForm(raw, resultKind) {
|
|
4283
|
+
if (!Array.isArray(raw)) {
|
|
4284
|
+
return [];
|
|
4285
|
+
}
|
|
4286
|
+
const rows = [];
|
|
4287
|
+
for (const [index, row] of raw.entries()) {
|
|
4288
|
+
const compareValue = this.coerceDisplayCompareValue(get(row, 'compareValue'), resultKind);
|
|
4289
|
+
const color = this.normalizeDisplayColorValue(get(row, 'color'));
|
|
4290
|
+
if (compareValue === undefined || !color) {
|
|
4291
|
+
continue;
|
|
4292
|
+
}
|
|
4293
|
+
rows.push({
|
|
4294
|
+
id: String(get(row, 'id') ?? AXPDataGenerator.uuid()),
|
|
4295
|
+
order: index,
|
|
4296
|
+
operator: this.coerceDisplayOperator(get(row, 'operator'), resultKind),
|
|
4297
|
+
compareValue,
|
|
4298
|
+
color,
|
|
4299
|
+
emphasis: this.coerceDisplayEmphasis(get(row, 'emphasis')),
|
|
4300
|
+
icon: this.normalizeDisplayIconValue(get(row, 'icon')),
|
|
4301
|
+
});
|
|
4302
|
+
}
|
|
4303
|
+
return normalizeQuestionnaireOutcomeDisplayRules(rows);
|
|
4304
|
+
}
|
|
4305
|
+
normalizeLocalizedField(value) {
|
|
4306
|
+
if (value == null || value === '') {
|
|
4307
|
+
return undefined;
|
|
4308
|
+
}
|
|
4309
|
+
if (typeof value === 'string') {
|
|
4310
|
+
const trimmed = value.trim();
|
|
4311
|
+
return trimmed ? createMultiLanguageString(trimmed, trimmed) : undefined;
|
|
4312
|
+
}
|
|
4313
|
+
if (typeof value === 'object') {
|
|
4314
|
+
return value;
|
|
4315
|
+
}
|
|
4316
|
+
return undefined;
|
|
4317
|
+
}
|
|
4318
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4319
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireOutcomesBuilderComponent, isStandalone: true, selector: "axm-questionnaire-outcomes-builder", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "standardRef", first: true, predicate: AXPStandardSectionItemsBuilderComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"axm-questionnaire-outcomes-builder\">\n @if (showHeader()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n @if (!readonly()) {\n <ax-button\n class=\"ax-sm\"\n [text]=\"\n ('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-section.title'\n | translate\n | async) || 'Add Section'\n \"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n #standardRef\n class=\"ax-block ax-min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\" />\n</div>\n", styles: [".axm-questionnaire-outcomes-builder{display:flex;height:100%;width:100%;flex-direction:column}.axm-questionnaire-outcomes-builder .__header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-bottom-width:1px;padding:.75rem}.axm-questionnaire-outcomes-builder .__header .__header-left,.axm-questionnaire-outcomes-builder .__header .__header-right{display:flex;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStandardSectionItemsBuilderComponent, selector: "axp-standard-section-items-builder", inputs: ["value", "config", "readonly"], outputs: ["valueChange"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4320
|
+
}
|
|
4321
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesBuilderComponent, decorators: [{
|
|
4322
|
+
type: Component,
|
|
4323
|
+
args: [{ selector: 'axm-questionnaire-outcomes-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
4324
|
+
CommonModule,
|
|
4325
|
+
AXButtonModule,
|
|
4326
|
+
AXDecoratorModule,
|
|
4327
|
+
AXTranslationModule,
|
|
4328
|
+
AXPStandardSectionItemsBuilderComponent,
|
|
4329
|
+
], template: "<div class=\"axm-questionnaire-outcomes-builder\">\n @if (showHeader()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n @if (!readonly()) {\n <ax-button\n class=\"ax-sm\"\n [text]=\"\n ('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-section.title'\n | translate\n | async) || 'Add Section'\n \"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n }\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n #standardRef\n class=\"ax-block ax-min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\" />\n</div>\n", styles: [".axm-questionnaire-outcomes-builder{display:flex;height:100%;width:100%;flex-direction:column}.axm-questionnaire-outcomes-builder .__header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;border-bottom-width:1px;padding:.75rem}.axm-questionnaire-outcomes-builder .__header .__header-left,.axm-questionnaire-outcomes-builder .__header .__header-right{display:flex;gap:.5rem}\n"] }]
|
|
4330
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], standardRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPStandardSectionItemsBuilderComponent), { isSignal: true }] }] } });
|
|
4331
|
+
|
|
4332
|
+
/** Component key for the questionnaire Outcomes page tab. Register via AXP_PAGE_COMPONENT_PROVIDER. */
|
|
4333
|
+
const QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY = 'questionnaire-outcomes-page';
|
|
4334
|
+
|
|
4335
|
+
const QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND = 'Questionnaire:Outcomes:Save';
|
|
4336
|
+
/**
|
|
4337
|
+
* Command to save the questionnaire outcomes field.
|
|
4338
|
+
* Patches entity with { outcomes }.
|
|
4339
|
+
*/
|
|
4340
|
+
class AXMSaveQuestionnaireOutcomesCommand {
|
|
4341
|
+
constructor() {
|
|
4342
|
+
this.entityService = inject(AXPEntityService);
|
|
4343
|
+
this.translationService = inject(AXTranslationService);
|
|
4344
|
+
}
|
|
4345
|
+
async execute(input) {
|
|
4346
|
+
const { id, outcomes } = input;
|
|
4347
|
+
if (!id) {
|
|
4348
|
+
return {
|
|
4349
|
+
success: false,
|
|
4350
|
+
message: {
|
|
4351
|
+
text: await this.translationService.translateAsync('@general:messages.entity.invalid-data'),
|
|
4352
|
+
},
|
|
4353
|
+
};
|
|
4354
|
+
}
|
|
4355
|
+
try {
|
|
4356
|
+
const entityRef = `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}`;
|
|
4357
|
+
const dataAccessor = this.entityService.withEntity(entityRef).data();
|
|
4358
|
+
await dataAccessor.update(id, { outcomes });
|
|
4359
|
+
return {
|
|
4360
|
+
success: true,
|
|
4361
|
+
data: { id, outcomes },
|
|
4362
|
+
message: {
|
|
4363
|
+
text: await this.translationService.translateAsync('@general:messages.generic.success.description'),
|
|
4364
|
+
},
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
catch (error) {
|
|
4368
|
+
const message = error instanceof Error
|
|
4369
|
+
? error.message
|
|
4370
|
+
: await this.translationService.translateAsync('@general:messages.generic.error.description');
|
|
4371
|
+
return {
|
|
4372
|
+
success: false,
|
|
4373
|
+
message: { text: message },
|
|
4374
|
+
};
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireOutcomesCommand, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4378
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireOutcomesCommand, providedIn: 'root' }); }
|
|
4379
|
+
}
|
|
4380
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMSaveQuestionnaireOutcomesCommand, decorators: [{
|
|
4381
|
+
type: Injectable,
|
|
4382
|
+
args: [{
|
|
4383
|
+
providedIn: 'root',
|
|
4384
|
+
}]
|
|
4385
|
+
}] });
|
|
4386
|
+
|
|
4387
|
+
var saveQuestionnaireOutcomes_command = /*#__PURE__*/Object.freeze({
|
|
4388
|
+
__proto__: null,
|
|
4389
|
+
AXMSaveQuestionnaireOutcomesCommand: AXMSaveQuestionnaireOutcomesCommand,
|
|
4390
|
+
QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND: QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND
|
|
4391
|
+
});
|
|
4392
|
+
|
|
4393
|
+
const QUESTIONNAIRE_OUTCOMES_DISCARD_COMMAND = 'Questionnaire:Outcomes:Discard';
|
|
4394
|
+
const QUESTIONNAIRE_OUTCOMES_ADD_SECTION_COMMAND = 'Questionnaire:Outcomes:AddSection';
|
|
4395
|
+
//#region ---- Questionnaire Outcomes Page Component ----
|
|
4396
|
+
class AXMQuestionnaireOutcomesPageComponent extends AXPPageLayoutBaseComponent {
|
|
4397
|
+
//#endregion
|
|
4398
|
+
//#region ---- Lifecycle ----
|
|
4399
|
+
constructor() {
|
|
4400
|
+
super();
|
|
4401
|
+
//#region ---- Inputs ----
|
|
4402
|
+
this.rootContext = input(...(ngDevMode ? [undefined, { debugName: "rootContext" }] : /* istanbul ignore next */ []));
|
|
4403
|
+
this.pageConfig = input(...(ngDevMode ? [undefined, { debugName: "pageConfig" }] : /* istanbul ignore next */ []));
|
|
4404
|
+
//#endregion
|
|
4405
|
+
//#region ---- Services ----
|
|
4406
|
+
this.commandService = inject(AXPCommandService);
|
|
4407
|
+
this.eventService = inject(AXPBroadcastEventService);
|
|
4408
|
+
this.hostPageLayout = inject(AXPPageLayoutBase, { optional: true, skipSelf: true });
|
|
4409
|
+
//#endregion
|
|
4410
|
+
//#region ---- View References ----
|
|
4411
|
+
this.builderRef = viewChild('builderRef', ...(ngDevMode ? [{ debugName: "builderRef" }] : /* istanbul ignore next */ []));
|
|
4412
|
+
//#endregion
|
|
4413
|
+
//#region ---- State ----
|
|
4414
|
+
this.localContext = signal(null, ...(ngDevMode ? [{ debugName: "localContext" }] : /* istanbul ignore next */ []));
|
|
4415
|
+
this.ignoreNextValueChange = signal(false, ...(ngDevMode ? [{ debugName: "ignoreNextValueChange" }] : /* istanbul ignore next */ []));
|
|
4416
|
+
this.baselineOutcomes = signal(null, ...(ngDevMode ? [{ debugName: "baselineOutcomes" }] : /* istanbul ignore next */ []));
|
|
4417
|
+
this.outcomesBaselinePendingReconcile = signal(false, ...(ngDevMode ? [{ debugName: "outcomesBaselinePendingReconcile" }] : /* istanbul ignore next */ []));
|
|
4418
|
+
this.isDirty = signal(false, ...(ngDevMode ? [{ debugName: "isDirty" }] : /* istanbul ignore next */ []));
|
|
4419
|
+
//#endregion
|
|
4420
|
+
//#region ---- Computed ----
|
|
4421
|
+
this.context = computed(() => {
|
|
4422
|
+
const local = this.localContext();
|
|
4423
|
+
if (local != null)
|
|
4424
|
+
return local;
|
|
4425
|
+
return this.rootContext() ?? {};
|
|
4426
|
+
}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
4427
|
+
this.outcomesValue = computed(() => {
|
|
4428
|
+
const ctx = this.context();
|
|
4429
|
+
return normalizeQuestionnaireOutcomesValue(ctx['outcomes']);
|
|
4430
|
+
}, ...(ngDevMode ? [{ debugName: "outcomesValue" }] : /* istanbul ignore next */ []));
|
|
4431
|
+
let previousRootId = undefined;
|
|
4432
|
+
effect(() => {
|
|
4433
|
+
const ctx = this.rootContext();
|
|
4434
|
+
const currentId = ctx != null && typeof ctx === 'object' ? ctx['id'] : undefined;
|
|
4435
|
+
if (currentId !== previousRootId) {
|
|
4436
|
+
previousRootId = currentId;
|
|
4437
|
+
this.localContext.set(null);
|
|
4438
|
+
const rootOutcomes = normalizeQuestionnaireOutcomesValue(ctx?.['outcomes']);
|
|
4439
|
+
this.baselineOutcomes.set(this.cloneOutcomes(rootOutcomes));
|
|
4440
|
+
this.isDirty.set(false);
|
|
4441
|
+
this.outcomesBaselinePendingReconcile.set(true);
|
|
4442
|
+
}
|
|
4443
|
+
});
|
|
4444
|
+
}
|
|
4445
|
+
//#endregion
|
|
4446
|
+
//#region ---- Page Actions ----
|
|
4447
|
+
async getPrimaryMenuItems() {
|
|
4448
|
+
const addSectionTitle = (await this.translateService.translateAsync('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.actions.add-section.title')) || 'Add Section';
|
|
4449
|
+
const discardTitle = (await this.translateService.translateAsync('@general:actions.discard.title')) || 'Discard';
|
|
4450
|
+
const saveTitle = (await this.translateService.translateAsync('@general:actions.save.title')) || 'Save';
|
|
4451
|
+
const addSectionAction = {
|
|
4452
|
+
title: addSectionTitle,
|
|
4453
|
+
icon: 'fa-light fa-layer-group',
|
|
4454
|
+
zone: 'header',
|
|
4455
|
+
priority: 'primary',
|
|
4456
|
+
color: 'primary',
|
|
4457
|
+
command: {
|
|
4458
|
+
name: QUESTIONNAIRE_OUTCOMES_ADD_SECTION_COMMAND,
|
|
4459
|
+
options: {},
|
|
4460
|
+
},
|
|
4461
|
+
};
|
|
4462
|
+
const discardAction = {
|
|
4463
|
+
title: discardTitle,
|
|
4464
|
+
icon: 'fa-light fa-rotate-left',
|
|
4465
|
+
zone: 'footer',
|
|
4466
|
+
priority: 'secondary',
|
|
4467
|
+
color: 'default',
|
|
4468
|
+
visible: this.isDirty(),
|
|
4469
|
+
command: {
|
|
4470
|
+
name: QUESTIONNAIRE_OUTCOMES_DISCARD_COMMAND,
|
|
4471
|
+
options: {},
|
|
4472
|
+
},
|
|
4473
|
+
};
|
|
4474
|
+
const saveAction = {
|
|
4475
|
+
title: saveTitle,
|
|
4476
|
+
icon: 'fa-light fa-floppy-disk',
|
|
4477
|
+
zone: 'footer',
|
|
4478
|
+
priority: 'primary',
|
|
4479
|
+
color: 'primary',
|
|
4480
|
+
visible: this.isDirty(),
|
|
4481
|
+
command: {
|
|
4482
|
+
name: QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND,
|
|
4483
|
+
options: {},
|
|
4484
|
+
},
|
|
4485
|
+
};
|
|
4486
|
+
return [addSectionAction, discardAction, saveAction];
|
|
4487
|
+
}
|
|
4488
|
+
//#endregion
|
|
4489
|
+
//#region ---- Command Handling ----
|
|
4490
|
+
execute(command) {
|
|
4491
|
+
if (command.name === QUESTIONNAIRE_OUTCOMES_DISCARD_COMMAND) {
|
|
4492
|
+
this.ignoreNextValueChange.set(true);
|
|
4493
|
+
this.localContext.set(null);
|
|
4494
|
+
this.isDirty.set(false);
|
|
4495
|
+
this.outcomesBaselinePendingReconcile.set(true);
|
|
4496
|
+
this.recompute();
|
|
4497
|
+
return;
|
|
4498
|
+
}
|
|
4499
|
+
if (command.name === QUESTIONNAIRE_OUTCOMES_ADD_SECTION_COMMAND) {
|
|
4500
|
+
void this.builderRef()?.addSection();
|
|
4501
|
+
return;
|
|
4502
|
+
}
|
|
4503
|
+
if (command.name !== QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND) {
|
|
4504
|
+
return;
|
|
4505
|
+
}
|
|
4506
|
+
return this.handleSaveExecute();
|
|
4507
|
+
}
|
|
4508
|
+
async handleSaveExecute() {
|
|
4509
|
+
const ctx = this.localContext() ?? this.rootContext() ?? {};
|
|
4510
|
+
const id = typeof ctx['id'] === 'string' ? ctx['id'] : undefined;
|
|
4511
|
+
const outcomes = normalizeQuestionnaireOutcomesValue(ctx['outcomes']);
|
|
4512
|
+
if (!id) {
|
|
4513
|
+
return {
|
|
4514
|
+
success: false,
|
|
4515
|
+
message: {
|
|
4516
|
+
text: await this.translateService.translateAsync('@general:messages.entity.invalid-data'),
|
|
4517
|
+
},
|
|
4518
|
+
};
|
|
4519
|
+
}
|
|
4520
|
+
if (findDuplicateOutcomeNames(outcomes).length > 0) {
|
|
4521
|
+
return {
|
|
4522
|
+
success: false,
|
|
4523
|
+
message: {
|
|
4524
|
+
text: await this.translateService.translateAsync('@assessment-management:questionnaires.components.questionnaire-outcomes-builder.validation.duplicate-name'),
|
|
4525
|
+
},
|
|
4526
|
+
};
|
|
4527
|
+
}
|
|
4528
|
+
const input = { id, outcomes };
|
|
4529
|
+
const result = await this.commandService.execute(QUESTIONNAIRE_OUTCOMES_SAVE_COMMAND, input);
|
|
4530
|
+
const execResult = (result ?? { success: false });
|
|
4531
|
+
if (execResult.success) {
|
|
4532
|
+
this.baselineOutcomes.set(this.cloneOutcomes(outcomes));
|
|
4533
|
+
this.localContext.set(null);
|
|
4534
|
+
this.isDirty.set(false);
|
|
4535
|
+
this.outcomesBaselinePendingReconcile.set(true);
|
|
4536
|
+
this.recompute();
|
|
4537
|
+
this.eventService.publish(AXPEntityEventsKeys.REFRESH_LAYOUT, {
|
|
4538
|
+
name: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}`,
|
|
4539
|
+
});
|
|
4540
|
+
}
|
|
4541
|
+
return execResult;
|
|
4542
|
+
}
|
|
4543
|
+
//#endregion
|
|
4544
|
+
//#region ---- UI Handlers ----
|
|
4545
|
+
onOutcomesChange(value) {
|
|
4546
|
+
if (this.ignoreNextValueChange()) {
|
|
4547
|
+
this.ignoreNextValueChange.set(false);
|
|
4548
|
+
return;
|
|
4549
|
+
}
|
|
4550
|
+
const current = this.outcomesValue();
|
|
4551
|
+
if (this.areOutcomesEqual(current, value)) {
|
|
4552
|
+
if (this.outcomesBaselinePendingReconcile()) {
|
|
4553
|
+
this.baselineOutcomes.set(this.cloneOutcomes(current));
|
|
4554
|
+
this.outcomesBaselinePendingReconcile.set(false);
|
|
4555
|
+
this.isDirty.set(false);
|
|
4556
|
+
}
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4559
|
+
const base = this.localContext() ?? this.rootContext() ?? {};
|
|
4560
|
+
if (this.outcomesBaselinePendingReconcile() && this.localContext() == null) {
|
|
4561
|
+
this.baselineOutcomes.set(this.cloneOutcomes(value));
|
|
4562
|
+
this.isDirty.set(false);
|
|
4563
|
+
this.outcomesBaselinePendingReconcile.set(false);
|
|
4564
|
+
this.localContext.set({ ...base, outcomes: value });
|
|
4565
|
+
this.recompute();
|
|
4566
|
+
return;
|
|
4567
|
+
}
|
|
4568
|
+
this.localContext.set({ ...base, outcomes: value });
|
|
4569
|
+
const baseline = this.baselineOutcomes();
|
|
4570
|
+
this.isDirty.set(!this.areOutcomesEqual(baseline, value));
|
|
4571
|
+
this.recompute();
|
|
4572
|
+
}
|
|
4573
|
+
//#endregion
|
|
4574
|
+
//#region ---- Utility ----
|
|
4575
|
+
areOutcomesEqual(a, b) {
|
|
4576
|
+
return isEqual(normalizeQuestionnaireOutcomesValue(a), normalizeQuestionnaireOutcomesValue(b));
|
|
4577
|
+
}
|
|
4578
|
+
cloneOutcomes(value) {
|
|
4579
|
+
if (isNil(value)) {
|
|
4580
|
+
return { sections: [] };
|
|
4581
|
+
}
|
|
4582
|
+
return cloneDeep(normalizeQuestionnaireOutcomesValue(value));
|
|
4583
|
+
}
|
|
4584
|
+
recompute() {
|
|
4585
|
+
super.recompute();
|
|
4586
|
+
const maybeLayout = this.hostPageLayout;
|
|
4587
|
+
maybeLayout.recompute?.();
|
|
4588
|
+
}
|
|
4589
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4590
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.9", type: AXMQuestionnaireOutcomesPageComponent, isStandalone: true, selector: "axm-questionnaire-outcomes-page", inputs: { rootContext: { classPropertyName: "rootContext", publicName: "rootContext", isSignal: true, isRequired: false, transformFunction: null }, pageConfig: { classPropertyName: "pageConfig", publicName: "pageConfig", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
4591
|
+
{
|
|
4592
|
+
provide: AXPPageLayoutBase,
|
|
4593
|
+
useExisting: AXMQuestionnaireOutcomesPageComponent,
|
|
4594
|
+
},
|
|
4595
|
+
], viewQueries: [{ propertyName: "builderRef", first: true, predicate: ["builderRef"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
4596
|
+
<axm-questionnaire-outcomes-builder
|
|
4597
|
+
#builderRef
|
|
4598
|
+
[value]="outcomesValue()"
|
|
4599
|
+
[showHeader]="false"
|
|
4600
|
+
(valueChange)="onOutcomesChange($event)">
|
|
4601
|
+
</axm-questionnaire-outcomes-builder>
|
|
4602
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AXMQuestionnaireOutcomesBuilderComponent, selector: "axm-questionnaire-outcomes-builder", inputs: ["value", "readonly", "showHeader"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4603
|
+
}
|
|
4604
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesPageComponent, decorators: [{
|
|
4605
|
+
type: Component,
|
|
1536
4606
|
args: [{
|
|
1537
|
-
|
|
4607
|
+
selector: 'axm-questionnaire-outcomes-page',
|
|
4608
|
+
standalone: true,
|
|
4609
|
+
imports: [AXMQuestionnaireOutcomesBuilderComponent],
|
|
4610
|
+
template: `
|
|
4611
|
+
<axm-questionnaire-outcomes-builder
|
|
4612
|
+
#builderRef
|
|
4613
|
+
[value]="outcomesValue()"
|
|
4614
|
+
[showHeader]="false"
|
|
4615
|
+
(valueChange)="onOutcomesChange($event)">
|
|
4616
|
+
</axm-questionnaire-outcomes-builder>
|
|
4617
|
+
`,
|
|
4618
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4619
|
+
providers: [
|
|
4620
|
+
{
|
|
4621
|
+
provide: AXPPageLayoutBase,
|
|
4622
|
+
useExisting: AXMQuestionnaireOutcomesPageComponent,
|
|
4623
|
+
},
|
|
4624
|
+
],
|
|
1538
4625
|
}]
|
|
4626
|
+
}], ctorParameters: () => [], propDecorators: { rootContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootContext", required: false }] }], pageConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageConfig", required: false }] }], builderRef: [{ type: i0.ViewChild, args: ['builderRef', { isSignal: true }] }] } });
|
|
4627
|
+
|
|
4628
|
+
var questionnaireOutcomesPage_component = /*#__PURE__*/Object.freeze({
|
|
4629
|
+
__proto__: null,
|
|
4630
|
+
AXMQuestionnaireOutcomesPageComponent: AXMQuestionnaireOutcomesPageComponent
|
|
4631
|
+
});
|
|
4632
|
+
|
|
4633
|
+
//#region ---- Questionnaire Outcomes Page Component Provider ----
|
|
4634
|
+
class AXMQuestionnaireOutcomesPageComponentProvider {
|
|
4635
|
+
async components() {
|
|
4636
|
+
return [
|
|
4637
|
+
{
|
|
4638
|
+
key: QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY,
|
|
4639
|
+
loader: () => Promise.resolve().then(function () { return questionnaireOutcomesPage_component; }).then((m) => m.AXMQuestionnaireOutcomesPageComponent),
|
|
4640
|
+
},
|
|
4641
|
+
];
|
|
4642
|
+
}
|
|
4643
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesPageComponentProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4644
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesPageComponentProvider }); }
|
|
4645
|
+
}
|
|
4646
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomesPageComponentProvider, decorators: [{
|
|
4647
|
+
type: Injectable
|
|
1539
4648
|
}] });
|
|
1540
4649
|
|
|
4650
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
4651
|
+
__proto__: null,
|
|
4652
|
+
AXMQuestionnaireOutcomesPageComponent: AXMQuestionnaireOutcomesPageComponent,
|
|
4653
|
+
AXMQuestionnaireOutcomesPageComponentProvider: AXMQuestionnaireOutcomesPageComponentProvider,
|
|
4654
|
+
QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY: QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY
|
|
4655
|
+
});
|
|
4656
|
+
|
|
4657
|
+
//#region ---- Outcomes builder exports ----
|
|
4658
|
+
//#endregion
|
|
4659
|
+
|
|
4660
|
+
//#region ---- Questionnaire builder feature exports ----
|
|
4661
|
+
//#endregion
|
|
4662
|
+
|
|
1541
4663
|
//#region ---- Imports ----
|
|
1542
4664
|
//#endregion
|
|
1543
4665
|
/** Guards concurrent `refreshVisibility` runs; incremented on each refresh. */
|
|
@@ -1558,7 +4680,7 @@ function persistedItemName(item, index) {
|
|
|
1558
4680
|
const id = typeof legacy.id === 'string' ? legacy.id.trim() : '';
|
|
1559
4681
|
return id || `item-${index}`;
|
|
1560
4682
|
}
|
|
1561
|
-
function normalizeValidationStrategy
|
|
4683
|
+
function normalizeValidationStrategy(value) {
|
|
1562
4684
|
if (value === 'step' || value === 'end') {
|
|
1563
4685
|
return value;
|
|
1564
4686
|
}
|
|
@@ -1566,7 +4688,7 @@ function normalizeValidationStrategy$1(value) {
|
|
|
1566
4688
|
typeof value === 'object' &&
|
|
1567
4689
|
'id' in value &&
|
|
1568
4690
|
typeof value.id === 'string') {
|
|
1569
|
-
return normalizeValidationStrategy
|
|
4691
|
+
return normalizeValidationStrategy(value.id);
|
|
1570
4692
|
}
|
|
1571
4693
|
return 'step';
|
|
1572
4694
|
}
|
|
@@ -1963,8 +5085,8 @@ const AXMQuestionnaireViewerViewModel = signalStore(withState(() => ({
|
|
|
1963
5085
|
const displaySettings = structure?.displaySettings;
|
|
1964
5086
|
const displaySettingsValue = displaySettings?.validationStrategy;
|
|
1965
5087
|
return configValue !== undefined
|
|
1966
|
-
? normalizeValidationStrategy
|
|
1967
|
-
: normalizeValidationStrategy
|
|
5088
|
+
? normalizeValidationStrategy(configValue)
|
|
5089
|
+
: normalizeValidationStrategy(displaySettingsValue);
|
|
1968
5090
|
}),
|
|
1969
5091
|
//#endregion
|
|
1970
5092
|
//#region ---- Navigation ----
|
|
@@ -3483,7 +6605,7 @@ class AXMQuestionnaireViewerQuestionComponent {
|
|
|
3483
6605
|
</div>
|
|
3484
6606
|
}
|
|
3485
6607
|
</div>
|
|
3486
|
-
`, isInline: true, styles: ["axm-questionnaire-viewer-question{display:block}axm-questionnaire-viewer-question .__question-item{display:flex;flex-direction:column;gap:.25rem;padding:1rem;text-align:start;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}axm-questionnaire-viewer-question .__question-item.__answered{border-radius:.5rem;background:rgba(var(--ax-sys-color-primary-surface),.14)}axm-questionnaire-viewer-question .__question-item.__answered:not(.__view-mode){border-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1))}axm-questionnaire-viewer-question .__question-item .__question-header{display:flex;width:100%;min-width:0px;align-items:flex-start;justify-content:space-between;gap:1rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left{display:flex;flex-shrink:0;align-items:center;gap:.75rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left .__question-number{font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-600),var(--tw-text-opacity, 1))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left .__question-counter{font-size:.75rem;line-height:1rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right{display:flex;min-width:0px;flex:1 1 0%;flex-wrap:wrap;align-items:flex-start;gap:.5rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block{min-width:0px;flex:1 1 0%;text-align:start}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title{margin:0;min-width:0px;flex:1 1 0%;text-align:start;font-size:1rem;line-height:1.5rem;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block h3.__question-title{font-weight:500}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich{width:100%;max-width:100%;text-align:start;font-size:1rem;line-height:1.5rem;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich p{margin:0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich p:first-child{margin-top:0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich li{margin-block:.125rem;padding-inline-start:.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ul ul{list-style-type:circle;margin-block:.25rem 0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title.__question-title--rich{font-weight:400}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__answered-badge{border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500;background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__required-badge{border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500;background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-note{font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-note p{margin:0}axm-questionnaire-viewer-question .__question-item .__question-note p:first-child{margin-top:0}axm-questionnaire-viewer-question .__question-item .__question-note ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-note ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-note li{margin-block:.125rem}axm-questionnaire-viewer-question .__question-item .__question-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-widget{text-align:start}axm-questionnaire-viewer-question .__question-item .__question-widget>*{margin-bottom:0}axm-questionnaire-viewer-question .__question-item .__widget-placeholder{border-radius:.25rem;border-width:1px;border-style:dashed;padding:1rem;font-size:.875rem;line-height:1.25rem;font-style:italic;color:rgb(var(--ax-sys-color-on-surface-variant));--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-comment{display:flex;width:100%;flex-direction:column;gap:.25rem}axm-questionnaire-viewer-question .__question-item .__question-comment ax-text-area{margin-top:.5rem}axm-questionnaire-viewer-question .__question-item .__question-comment--readonly{margin-top:.5rem}axm-questionnaire-viewer-question .__question-item .__question-comment-text{margin:0;width:100%;font-size:.875rem;line-height:1.25rem;white-space:pre-wrap;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-comment-label{font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-comment-required{color:rgb(var(--ax-sys-color-danger-600))}axm-questionnaire-viewer-question .__question-item .__attachments{border-top-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));padding-top:.75rem}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-label{margin-inline-end:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list{margin:0;margin-top:.25rem;list-style-type:none;padding-left:0}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li{margin-top:.25rem}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link{display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;line-height:1.25rem;text-decoration-line:underline;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;color:rgb(var(--ax-sys-color-primary-dark-surface))}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link:hover{opacity:.9}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link i{flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXAlertModule }, { kind: "component", type: i2.AXAlertComponent, selector: "ax-alert", inputs: ["color", "timeOut"], outputs: ["colorChange", "onClosed", "timeOutChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTextAreaModule }, { kind: "component", type: i4.AXTextAreaComponent, selector: "ax-text-area", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "placeholder", "maxLength", "look", "rows", "allowResize", "showCounter", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXSafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
6608
|
+
`, isInline: true, styles: ["axm-questionnaire-viewer-question{display:block}axm-questionnaire-viewer-question .__question-item{display:flex;flex-direction:column;gap:.25rem;padding:1rem;text-align:start;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}axm-questionnaire-viewer-question .__question-item.__answered{border-radius:.5rem;background:rgba(var(--ax-sys-color-primary-surface),.14)}axm-questionnaire-viewer-question .__question-item.__answered:not(.__view-mode){border-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1))}axm-questionnaire-viewer-question .__question-item .__question-header{display:flex;width:100%;min-width:0px;align-items:flex-start;justify-content:space-between;gap:1rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left{display:flex;flex-shrink:0;align-items:center;gap:.75rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left .__question-number{font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-600),var(--tw-text-opacity, 1))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-left .__question-counter{font-size:.75rem;line-height:1rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right{display:flex;min-width:0px;flex:1 1 0%;flex-wrap:wrap;align-items:flex-start;gap:.5rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block{min-width:0px;flex:1 1 0%;text-align:start}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title{margin:0;min-width:0px;flex:1 1 0%;text-align:start;font-size:1rem;line-height:1.5rem;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block h3.__question-title{font-weight:500}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich{width:100%;max-width:100%;text-align:start;font-size:1rem;line-height:1.5rem;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich p{margin:0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich p:first-child{margin-top:0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich li{margin-block:.125rem;padding-inline-start:.25rem}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title--rich ul ul{list-style-type:circle;margin-block:.25rem 0}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__question-title-block .__question-title.__question-title--rich{font-weight:400}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__answered-badge{border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500;background-color:rgb(var(--ax-sys-color-success-lighter-surface));color:rgb(var(--ax-sys-color-on-success-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-header .__question-header-right .__required-badge{border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500;background-color:rgb(var(--ax-sys-color-warning-lighter-surface));color:rgb(var(--ax-sys-color-on-warning-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-note{font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-note p{margin:0}axm-questionnaire-viewer-question .__question-item .__question-note p:first-child{margin-top:0}axm-questionnaire-viewer-question .__question-item .__question-note ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-note ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-question .__question-item .__question-note li{margin-block:.125rem}axm-questionnaire-viewer-question .__question-item .__question-description{margin-top:.25rem;font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-widget{text-align:start}axm-questionnaire-viewer-question .__question-item .__question-widget>*{margin-bottom:0}axm-questionnaire-viewer-question .__question-item .__widget-placeholder{border-radius:.25rem;border-width:1px;border-style:dashed;padding:1rem;font-size:.875rem;line-height:1.25rem;font-style:italic;color:rgb(var(--ax-sys-color-on-surface-variant));--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}axm-questionnaire-viewer-question .__question-item .__question-comment{display:flex;width:100%;flex-direction:column;gap:.25rem}axm-questionnaire-viewer-question .__question-item .__question-comment ax-text-area{margin-top:.5rem}axm-questionnaire-viewer-question .__question-item .__question-comment--readonly{margin-top:.5rem}axm-questionnaire-viewer-question .__question-item .__question-comment-text{margin:0;width:100%;font-size:.875rem;line-height:1.25rem;white-space:pre-wrap;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-question .__question-item .__question-comment-label{font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__question-comment-required{color:rgb(var(--ax-sys-color-danger-600))}axm-questionnaire-viewer-question .__question-item .__attachments{border-top-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));padding-top:.75rem}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-label{margin-inline-end:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:500;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list{margin:0;margin-top:.25rem;list-style-type:none;padding-left:0}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li{margin-top:.25rem}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link{display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;line-height:1.25rem;text-decoration-line:underline;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;color:rgb(var(--ax-sys-color-primary-dark-surface))}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link:hover{opacity:.9}axm-questionnaire-viewer-question .__question-item .__attachments .__attachments-list li .__attachment-link i{flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "directive", type: i1$1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXAlertModule }, { kind: "component", type: i2$1.AXAlertComponent, selector: "ax-alert", inputs: ["color", "timeOut"], outputs: ["colorChange", "onClosed", "timeOutChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTextAreaModule }, { kind: "component", type: i4$1.AXTextAreaComponent, selector: "ax-text-area", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "placeholder", "maxLength", "look", "rows", "allowResize", "showCounter", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXSafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3487
6609
|
}
|
|
3488
6610
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerQuestionComponent, decorators: [{
|
|
3489
6611
|
type: Component,
|
|
@@ -3685,7 +6807,7 @@ class AXMQuestionnaireViewerSectionHeaderComponent {
|
|
|
3685
6807
|
}
|
|
3686
6808
|
}
|
|
3687
6809
|
</div>
|
|
3688
|
-
`, isInline: true, styles: ["axm-questionnaire-viewer-section-header{display:block;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-header{display:flex;flex-shrink:0;flex-direction:column;gap:.125rem;text-align:start}axm-questionnaire-viewer-section-header .__section-title-lg{margin:0;font-size:1.5rem;line-height:2rem;font-weight:600;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-title-md{margin:0;font-size:1.25rem;line-height:1.75rem;font-weight:600;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-description{margin:0;font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-section-header .__section-description--rich{font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-section-header .__section-description--rich p{margin:0}axm-questionnaire-viewer-section-header .__section-description--rich p:first-child{margin-top:0}axm-questionnaire-viewer-section-header .__section-description--rich ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-section-header .__section-description--rich ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-section-header .__section-description--rich li{margin-block:.125rem;padding-inline-start:.25rem}axm-questionnaire-viewer-section-header .__mb-sm{margin-bottom:.5rem}axm-questionnaire-viewer-section-header .__mb-md{margin-bottom:1rem}\n"], dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4
|
|
6810
|
+
`, isInline: true, styles: ["axm-questionnaire-viewer-section-header{display:block;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-header{display:flex;flex-shrink:0;flex-direction:column;gap:.125rem;text-align:start}axm-questionnaire-viewer-section-header .__section-title-lg{margin:0;font-size:1.5rem;line-height:2rem;font-weight:600;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-title-md{margin:0;font-size:1.25rem;line-height:1.75rem;font-weight:600;color:rgb(var(--ax-sys-color-on-surface))}axm-questionnaire-viewer-section-header .__section-description{margin:0;font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-section-header .__section-description--rich{font-size:.875rem;line-height:1.25rem;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-section-header .__section-description--rich p{margin:0}axm-questionnaire-viewer-section-header .__section-description--rich p:first-child{margin-top:0}axm-questionnaire-viewer-section-header .__section-description--rich ul{list-style-type:disc;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-section-header .__section-description--rich ol{list-style-type:decimal;list-style-position:outside;margin-block:.375rem 0;padding-inline-start:1.25rem}axm-questionnaire-viewer-section-header .__section-description--rich li{margin-block:.125rem;padding-inline-start:.25rem}axm-questionnaire-viewer-section-header .__mb-sm{margin-bottom:.5rem}axm-questionnaire-viewer-section-header .__mb-md{margin-bottom:1rem}\n"], dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXSafePipe, name: "safe" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3689
6811
|
}
|
|
3690
6812
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerSectionHeaderComponent, decorators: [{
|
|
3691
6813
|
type: Component,
|
|
@@ -3918,7 +7040,7 @@ class AXMQuestionnaireViewerSideMenuViewComponent {
|
|
|
3918
7040
|
return null;
|
|
3919
7041
|
}
|
|
3920
7042
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerSideMenuViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3921
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerSideMenuViewComponent, isStandalone: true, selector: "axm-questionnaire-viewer-side-menu-view", viewQueries: [{ propertyName: "tabRef", first: true, predicate: AXTabsComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"__side-menu-container\">\n <!-- Desktop Sidebar (Large screens) -->\n @if (deviceService.isLarge()) {\n <div class=\"__desktop-sidebar\" [axResizable]=\"true\">\n <ax-tabs class=\"__sidebar-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\">\n @for (sectionIndex of vm.sectionIndicesWithVisibleContent(); track sectionIndex) {\n <ax-tab-item\n [text]=\"(vm.sections()[sectionIndex].title | translate | async) || ''\"\n (onClick)=\"handleSectionClick(sectionIndex)\"\n [disabled]=\"isSectionDisabled(sectionIndex)\"\n >\n @if (getSectionBadgeCount(vm.sections()[sectionIndex].name) > 0) {\n <ax-badge\n [text]=\"getSectionBadgeCount(vm.sections()[sectionIndex].name).toString()\"\n [color]=\"'danger'\"\n >\n </ax-badge>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n }\n\n <!-- Mobile/Tablet: Drawer Container -->\n @if (deviceService.isSmall() || deviceService.isMedium()) {\n <ax-drawer-container class=\"__drawer-container\">\n <!-- Sidebar Drawer (Mobile) -->\n <ax-drawer\n #sidebarDrawer\n [location]=\"'start'\"\n [mode]=\"'overlay'\"\n [collapsed]=\"sidebarDrawerCollapsed()\"\n [closeOnBackdropClick]=\"true\"\n (onBackdropClick)=\"sidebarDrawerCollapsed.set(true)\"\n class=\"__sidebar-drawer ax-w-[250px]\"\n >\n <ax-content class=\"__sidebar-content\">\n <ax-tabs class=\"__sidebar-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\">\n @for (sectionIndex of vm.sectionIndicesWithVisibleContent(); track sectionIndex) {\n <ax-tab-item\n [text]=\"(vm.sections()[sectionIndex].title | translate | async) || ''\"\n (onClick)=\"handleSectionClick(sectionIndex)\"\n [active]=\"vm.currentSectionIndex() === sectionIndex\"\n [disabled]=\"isSectionDisabled(sectionIndex)\"\n >\n @if (getSectionBadgeCount(vm.sections()[sectionIndex].name) > 0) {\n <ax-badge\n [text]=\"getSectionBadgeCount(vm.sections()[sectionIndex].name).toString()\"\n [color]=\"'danger'\"\n >\n </ax-badge>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </ax-content>\n </ax-drawer>\n\n <!-- Main Content (Mobile) -->\n <ax-content class=\"__main-content\">\n <!-- Questions Content -->\n @if (vm.currentSection(); as section) {\n @if (vm.isSectionVisible(section)) {\n @if (stickyParent(); as parent) {\n <div class=\"__mobile-header-row\" [axpSticky]=\"'--stuck'\" [stickyParent]=\"parent\" [stickyOffset]=\"0\">\n <div class=\"__mobile-menu-button\">\n <ax-button look=\"blank\" (onClick)=\"sidebarDrawerCollapsed.set(!sidebarDrawerCollapsed())\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n\n <axm-questionnaire-viewer-section-header\n [title]=\"section.title\"\n [description]=\"section.description\"\n [titleSize]=\"'lg'\"\n [marginBottom]=\"'none'\"\n >\n </axm-questionnaire-viewer-section-header>\n </div>\n }\n\n <div class=\"__page-section\">\n <div class=\"__questions-list\">\n @for (question of vm.getVisibleQuestionsInSection(section); track question.name; let i = $index) {\n <axm-questionnaire-viewer-question\n [question]=\"question\"\n [sectionOrder]=\"section.order\"\n [questionIndex]=\"i + 1\"\n [showQuestionNumbers]=\"vm.showQuestionNumbers()\"\n [showQuestionCounter]=\"false\"\n >\n </axm-questionnaire-viewer-question>\n }\n </div>\n </div>\n }\n }\n </ax-content>\n </ax-drawer-container>\n } @else {\n <!-- Desktop Main Content -->\n <div class=\"__main-content\">\n <!-- Questions Content -->\n @if (vm.currentSection(); as section) {\n @if (vm.isSectionVisible(section)) {\n <div class=\"__page-section\">\n @if (stickyParent(); as parent) {\n <div\n class=\"__section-title-sticky\"\n [axpSticky]=\"'--stuck'\"\n [stickyParent]=\"parent\"\n [stickyOffset]=\"0\"\n >\n <axm-questionnaire-viewer-section-header\n [title]=\"section.title\"\n [description]=\"section.description\"\n [titleSize]=\"'lg'\"\n [marginBottom]=\"'none'\"\n >\n </axm-questionnaire-viewer-section-header>\n </div>\n }\n\n <div class=\"__questions-list\">\n @for (question of vm.getVisibleQuestionsInSection(section); track question.name; let i = $index) {\n <axm-questionnaire-viewer-question\n [question]=\"question\"\n [sectionOrder]=\"section.order\"\n [questionIndex]=\"i + 1\"\n [showQuestionNumbers]=\"vm.showQuestionNumbers()\"\n [showQuestionCounter]=\"false\"\n >\n </axm-questionnaire-viewer-question>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: ["axm-questionnaire-viewer-side-menu-view{display:block;min-height:0px;width:100%;overflow:hidden}@media(min-width:640px){axm-questionnaire-viewer-side-menu-view{height:100%}}@media(min-width:1024px){axm-questionnaire-viewer-side-menu-view{height:65vh}}.__side-menu-container{display:flex;height:100%;min-height:0px;width:100%;overflow:hidden}.__drawer-container{display:flex;height:100%;width:100%;overflow:hidden}.__sidebar-drawer{height:100%;border-inline-end-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__sidebar-content{height:100%;overflow-y:auto}.__desktop-sidebar{display:flex;height:100%;min-height:0px;flex-shrink:0;flex-direction:column;overflow:hidden;border-inline-end-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__sidebar-tabs{--ax-comp-tabs-default-border-radius: 0;height:100%;min-height:0px;flex:1 1 0%;overflow-y:auto}.__sidebar-tabs ax-tab-item{margin-top:0;margin-bottom:0;padding-top:.75rem;padding-bottom:.75rem;font-weight:600}.__main-content{display:flex;max-height:83vh;min-height:0px;flex:1 1 0%;flex-direction:column;overflow-y:auto}@media(min-width:768px){.__main-content{max-height:75vh}}.__page-section{display:flex;flex-shrink:0;flex-direction:column;gap:1rem;padding:1rem}.__page-section .__section-title-sticky{position:sticky;top:0;z-index:10;isolation:isolate;min-width:0px;align-self:stretch;border-bottom-width:1px;padding-top:.5rem;padding-bottom:.5rem;transition:padding-block .28s cubic-bezier(.33,1,.68,1),border-color .22s ease-out}.__page-section .__section-title-sticky:before{content:\"\";position:absolute;z-index:-1;inset-block:0;inset-inline:0;pointer-events:none;box-shadow:none;transition:inset-inline .28s cubic-bezier(.22,1,.36,1),box-shadow .28s cubic-bezier(.33,1,.68,1)}@media(prefers-reduced-motion:reduce){.__page-section .__section-title-sticky{transition-duration:1ms;transition-timing-function:linear}.__page-section .__section-title-sticky:before{transition-duration:1ms;transition-timing-function:linear}}.__page-section .__section-title-sticky.--stuck{border-bottom-width:1px;border-style:none;padding-top:.75rem;padding-bottom:.75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__page-section .__section-title-sticky.--stuck:before{inset-inline:-1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.__mobile-header-row{position:sticky;top:0;z-index:10;isolation:isolate;display:flex;flex-shrink:0;align-items:flex-start;gap:.5rem;border-bottom-width:1px;padding:.5rem 1rem;transition:padding-block .28s cubic-bezier(.33,1,.68,1),border-color .22s ease-out}.__mobile-header-row:before{content:\"\";position:absolute;z-index:-1;inset-block:0;inset-inline:0;pointer-events:none;box-shadow:none;transition:inset-inline .28s cubic-bezier(.22,1,.36,1),box-shadow .28s cubic-bezier(.33,1,.68,1)}.__mobile-header-row.--stuck{border-bottom-width:1px;border-style:none;padding-top:.75rem;padding-bottom:.75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__mobile-header-row.--stuck:before{inset-inline:-1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.__mobile-menu-button{margin-inline-start:-.5rem;flex-shrink:0}.__questions-list{display:flex;flex-direction:column;gap:1rem}\n"], dependencies: [{ kind: "component", type: AXMQuestionnaireViewerQuestionComponent, selector: "axm-questionnaire-viewer-question", inputs: ["question", "contextData", "sectionOrder", "questionIndex", "showQuestionNumbers", "showQuestionCounter", "currentPosition", "mode"] }, { kind: "component", type: AXMQuestionnaireViewerSectionHeaderComponent, selector: "axm-questionnaire-viewer-section-header", inputs: ["title", "description", "titleSize", "marginBottom"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i1$1.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i1$1.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "component", type: i3$1.AXDrawerComponent, selector: "ax-drawer", inputs: ["location", "showBackdrop", "mode", "transition", "closeOnBackdropClick", "backdropClass", "collapsed", "singleOpenMode"], outputs: ["onBackdropClick", "collapsedStateChanged"] }, { kind: "component", type: i3$1.AXDrawerContainerComponent, selector: "ax-drawer-container" }, { kind: "ngmodule", type: AXDrawerDirectiveModule }, { kind: "directive", type: AXResizableDirective, selector: "[axResizable]", inputs: ["axResizable", "minWidth", "maxWidth", "dblClickAction", "width", "defaultWidth"], outputs: ["axResizableChange", "minWidthChange", "maxWidthChange", "dblClickActionChange", "widthChange", "defaultWidthChange", "onResizingStarted", "onResizingEnded", "onResizingDblClick"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1$2.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "directive", type: AXPStickyDirective, selector: "[axpSticky]", inputs: ["axpSticky", "stickyOffset", "stickyParent", "stickyTarget"], outputs: ["isStickyChange"], exportAs: ["axpSticky"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: i4$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
7043
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerSideMenuViewComponent, isStandalone: true, selector: "axm-questionnaire-viewer-side-menu-view", viewQueries: [{ propertyName: "tabRef", first: true, predicate: AXTabsComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"__side-menu-container\">\n <!-- Desktop Sidebar (Large screens) -->\n @if (deviceService.isLarge()) {\n <div class=\"__desktop-sidebar\" [axResizable]=\"true\">\n <ax-tabs class=\"__sidebar-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\">\n @for (sectionIndex of vm.sectionIndicesWithVisibleContent(); track sectionIndex) {\n <ax-tab-item\n [text]=\"(vm.sections()[sectionIndex].title | translate | async) || ''\"\n (onClick)=\"handleSectionClick(sectionIndex)\"\n [disabled]=\"isSectionDisabled(sectionIndex)\"\n >\n @if (getSectionBadgeCount(vm.sections()[sectionIndex].name) > 0) {\n <ax-badge\n [text]=\"getSectionBadgeCount(vm.sections()[sectionIndex].name).toString()\"\n [color]=\"'danger'\"\n >\n </ax-badge>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </div>\n }\n\n <!-- Mobile/Tablet: Drawer Container -->\n @if (deviceService.isSmall() || deviceService.isMedium()) {\n <ax-drawer-container class=\"__drawer-container\">\n <!-- Sidebar Drawer (Mobile) -->\n <ax-drawer\n #sidebarDrawer\n [location]=\"'start'\"\n [mode]=\"'overlay'\"\n [collapsed]=\"sidebarDrawerCollapsed()\"\n [closeOnBackdropClick]=\"true\"\n (onBackdropClick)=\"sidebarDrawerCollapsed.set(true)\"\n class=\"__sidebar-drawer ax-w-[250px]\"\n >\n <ax-content class=\"__sidebar-content\">\n <ax-tabs class=\"__sidebar-tabs\" [look]=\"'with-line-color'\" [location]=\"'end'\" [fitParent]=\"true\">\n @for (sectionIndex of vm.sectionIndicesWithVisibleContent(); track sectionIndex) {\n <ax-tab-item\n [text]=\"(vm.sections()[sectionIndex].title | translate | async) || ''\"\n (onClick)=\"handleSectionClick(sectionIndex)\"\n [active]=\"vm.currentSectionIndex() === sectionIndex\"\n [disabled]=\"isSectionDisabled(sectionIndex)\"\n >\n @if (getSectionBadgeCount(vm.sections()[sectionIndex].name) > 0) {\n <ax-badge\n [text]=\"getSectionBadgeCount(vm.sections()[sectionIndex].name).toString()\"\n [color]=\"'danger'\"\n >\n </ax-badge>\n }\n </ax-tab-item>\n }\n </ax-tabs>\n </ax-content>\n </ax-drawer>\n\n <!-- Main Content (Mobile) -->\n <ax-content class=\"__main-content\">\n <!-- Questions Content -->\n @if (vm.currentSection(); as section) {\n @if (vm.isSectionVisible(section)) {\n @if (stickyParent(); as parent) {\n <div class=\"__mobile-header-row\" [axpSticky]=\"'--stuck'\" [stickyParent]=\"parent\" [stickyOffset]=\"0\">\n <div class=\"__mobile-menu-button\">\n <ax-button look=\"blank\" (onClick)=\"sidebarDrawerCollapsed.set(!sidebarDrawerCollapsed())\">\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-bars\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n\n <axm-questionnaire-viewer-section-header\n [title]=\"section.title\"\n [description]=\"section.description\"\n [titleSize]=\"'lg'\"\n [marginBottom]=\"'none'\"\n >\n </axm-questionnaire-viewer-section-header>\n </div>\n }\n\n <div class=\"__page-section\">\n <div class=\"__questions-list\">\n @for (question of vm.getVisibleQuestionsInSection(section); track question.name; let i = $index) {\n <axm-questionnaire-viewer-question\n [question]=\"question\"\n [sectionOrder]=\"section.order\"\n [questionIndex]=\"i + 1\"\n [showQuestionNumbers]=\"vm.showQuestionNumbers()\"\n [showQuestionCounter]=\"false\"\n >\n </axm-questionnaire-viewer-question>\n }\n </div>\n </div>\n }\n }\n </ax-content>\n </ax-drawer-container>\n } @else {\n <!-- Desktop Main Content -->\n <div class=\"__main-content\">\n <!-- Questions Content -->\n @if (vm.currentSection(); as section) {\n @if (vm.isSectionVisible(section)) {\n <div class=\"__page-section\">\n @if (stickyParent(); as parent) {\n <div\n class=\"__section-title-sticky\"\n [axpSticky]=\"'--stuck'\"\n [stickyParent]=\"parent\"\n [stickyOffset]=\"0\"\n >\n <axm-questionnaire-viewer-section-header\n [title]=\"section.title\"\n [description]=\"section.description\"\n [titleSize]=\"'lg'\"\n [marginBottom]=\"'none'\"\n >\n </axm-questionnaire-viewer-section-header>\n </div>\n }\n\n <div class=\"__questions-list\">\n @for (question of vm.getVisibleQuestionsInSection(section); track question.name; let i = $index) {\n <axm-questionnaire-viewer-question\n [question]=\"question\"\n [sectionOrder]=\"section.order\"\n [questionIndex]=\"i + 1\"\n [showQuestionNumbers]=\"vm.showQuestionNumbers()\"\n [showQuestionCounter]=\"false\"\n >\n </axm-questionnaire-viewer-question>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: ["axm-questionnaire-viewer-side-menu-view{display:block;min-height:0px;width:100%;overflow:hidden}@media(min-width:640px){axm-questionnaire-viewer-side-menu-view{height:100%}}@media(min-width:1024px){axm-questionnaire-viewer-side-menu-view{height:65vh}}.__side-menu-container{display:flex;height:100%;min-height:0px;width:100%;overflow:hidden}.__drawer-container{display:flex;height:100%;width:100%;overflow:hidden}.__sidebar-drawer{height:100%;border-inline-end-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__sidebar-content{height:100%;overflow-y:auto}.__desktop-sidebar{display:flex;height:100%;min-height:0px;flex-shrink:0;flex-direction:column;overflow:hidden;border-inline-end-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__sidebar-tabs{--ax-comp-tabs-default-border-radius: 0;height:100%;min-height:0px;flex:1 1 0%;overflow-y:auto}.__sidebar-tabs ax-tab-item{margin-top:0;margin-bottom:0;padding-top:.75rem;padding-bottom:.75rem;font-weight:600}.__main-content{display:flex;max-height:83vh;min-height:0px;flex:1 1 0%;flex-direction:column;overflow-y:auto}@media(min-width:768px){.__main-content{max-height:75vh}}.__page-section{display:flex;flex-shrink:0;flex-direction:column;gap:1rem;padding:1rem}.__page-section .__section-title-sticky{position:sticky;top:0;z-index:10;isolation:isolate;min-width:0px;align-self:stretch;border-bottom-width:1px;padding-top:.5rem;padding-bottom:.5rem;transition:padding-block .28s cubic-bezier(.33,1,.68,1),border-color .22s ease-out}.__page-section .__section-title-sticky:before{content:\"\";position:absolute;z-index:-1;inset-block:0;inset-inline:0;pointer-events:none;box-shadow:none;transition:inset-inline .28s cubic-bezier(.22,1,.36,1),box-shadow .28s cubic-bezier(.33,1,.68,1)}@media(prefers-reduced-motion:reduce){.__page-section .__section-title-sticky{transition-duration:1ms;transition-timing-function:linear}.__page-section .__section-title-sticky:before{transition-duration:1ms;transition-timing-function:linear}}.__page-section .__section-title-sticky.--stuck{border-bottom-width:1px;border-style:none;padding-top:.75rem;padding-bottom:.75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__page-section .__section-title-sticky.--stuck:before{inset-inline:-1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.__mobile-header-row{position:sticky;top:0;z-index:10;isolation:isolate;display:flex;flex-shrink:0;align-items:flex-start;gap:.5rem;border-bottom-width:1px;padding:.5rem 1rem;transition:padding-block .28s cubic-bezier(.33,1,.68,1),border-color .22s ease-out}.__mobile-header-row:before{content:\"\";position:absolute;z-index:-1;inset-block:0;inset-inline:0;pointer-events:none;box-shadow:none;transition:inset-inline .28s cubic-bezier(.22,1,.36,1),box-shadow .28s cubic-bezier(.33,1,.68,1)}.__mobile-header-row.--stuck{border-bottom-width:1px;border-style:none;padding-top:.75rem;padding-bottom:.75rem;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface))}.__mobile-header-row.--stuck:before{inset-inline:-1rem;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.__mobile-menu-button{margin-inline-start:-.5rem;flex-shrink:0}.__questions-list{display:flex;flex-direction:column;gap:1rem}\n"], dependencies: [{ kind: "component", type: AXMQuestionnaireViewerQuestionComponent, selector: "axm-questionnaire-viewer-question", inputs: ["question", "contextData", "sectionOrder", "questionIndex", "showQuestionNumbers", "showQuestionCounter", "currentPosition", "mode"] }, { kind: "component", type: AXMQuestionnaireViewerSectionHeaderComponent, selector: "axm-questionnaire-viewer-section-header", inputs: ["title", "description", "titleSize", "marginBottom"] }, { kind: "ngmodule", type: AXTabsModule }, { kind: "component", type: i1$2.AXTabsComponent, selector: "ax-tabs", inputs: ["look", "location", "fitParent", "minWidth", "content"], outputs: ["onActiveTabChanged"] }, { kind: "component", type: i1$2.AXTabItemComponent, selector: "ax-tab-item", inputs: ["disabled", "text", "key", "headerTemplate", "active"], outputs: ["disabledChange", "onClick", "onBlur", "onFocus", "activeChange"] }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i2$2.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDrawerModule }, { kind: "component", type: i3$1.AXDrawerComponent, selector: "ax-drawer", inputs: ["location", "showBackdrop", "mode", "transition", "closeOnBackdropClick", "backdropClass", "collapsed", "singleOpenMode"], outputs: ["onBackdropClick", "collapsedStateChanged"] }, { kind: "component", type: i3$1.AXDrawerContainerComponent, selector: "ax-drawer-container" }, { kind: "ngmodule", type: AXDrawerDirectiveModule }, { kind: "directive", type: AXResizableDirective, selector: "[axResizable]", inputs: ["axResizable", "minWidth", "maxWidth", "dblClickAction", "width", "defaultWidth"], outputs: ["axResizableChange", "minWidthChange", "maxWidthChange", "dblClickActionChange", "widthChange", "defaultWidthChange", "onResizingStarted", "onResizingEnded", "onResizingDblClick"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "directive", type: AXPStickyDirective, selector: "[axpSticky]", inputs: ["axpSticky", "stickyOffset", "stickyParent", "stickyTarget"], outputs: ["isStickyChange"], exportAs: ["axpSticky"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
3922
7044
|
}
|
|
3923
7045
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerSideMenuViewComponent, decorators: [{
|
|
3924
7046
|
type: Component,
|
|
@@ -4183,9 +7305,9 @@ class AXMQuestionnaireViewerComponent {
|
|
|
4183
7305
|
this.answersChanged.emit(answers);
|
|
4184
7306
|
}
|
|
4185
7307
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4186
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerComponent, isStandalone: true, selector: "axm-questionnaire-viewer", inputs: { questionnaireId: { classPropertyName: "questionnaireId", publicName: "questionnaireId", isSignal: true, isRequired: false, transformFunction: null }, structure: { classPropertyName: "structure", publicName: "structure", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, initialAnswers: { classPropertyName: "initialAnswers", publicName: "initialAnswers", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { answersChanged: "answersChanged", questionAnswered: "questionAnswered" }, host: { classAttribute: "axm-questionnaire-viewer" }, providers: [AXMQuestionnaireViewerViewModel], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<axp-widgets-container #widgetContainer [attr.dir]=\"layoutDirection()\" [context]=\"{}\"\n (onContextChanged)=\"handleContextChanged()\">\n @if (vm.isLoading()) {\n <div class=\"__loading\">\n <axp-state-message icon=\"fa-light fa-spinner fa-spin\"\n [title]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.loading.title' | translate | async) || ''\"\n [description]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.loading.description' | translate | async) || ''\">\n </axp-state-message>\n </div>\n } @else if (vm.error()) {\n <div class=\"__error\">\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.error.title' | translate | async) || ''\"\n [description]=\"vm.error() || ''\">\n </axp-state-message>\n </div>\n } @else if (vm.questionnaireData()) {\n <div class=\"__questionnaire-container\">\n <ax-form #form>\n @if (vm.viewMode() === 'single-page') {\n <axm-questionnaire-viewer-single-page-view></axm-questionnaire-viewer-single-page-view>\n } @else if (vm.viewMode() === 'page-per-group') {\n <axm-questionnaire-viewer-page-per-group-view></axm-questionnaire-viewer-page-per-group-view>\n } @else if (vm.viewMode() === 'page-per-question') {\n <axm-questionnaire-viewer-page-per-question-view></axm-questionnaire-viewer-page-per-question-view>\n } @else if (vm.viewMode() === 'side-menu') {\n <axm-questionnaire-viewer-side-menu-view></axm-questionnaire-viewer-side-menu-view>\n }\n </ax-form>\n </div>\n }\n</axp-widgets-container>\n", styles: [".axm-questionnaire-viewer{display:flex;height:100%;max-height:100%;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer ax-form{display:flex;height:100%;min-height:0px;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer axp-widgets-container{display:flex;height:100%;min-height:0px;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer .__loading,.axm-questionnaire-viewer .__error{display:flex;height:100%;align-items:center;justify-content:center}.axm-questionnaire-viewer .__questionnaire-container{display:flex;min-height:0px;flex:1 1 0%;flex-direction:column;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "look"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i1$3.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "component", type:
|
|
7308
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerComponent, isStandalone: true, selector: "axm-questionnaire-viewer", inputs: { questionnaireId: { classPropertyName: "questionnaireId", publicName: "questionnaireId", isSignal: true, isRequired: false, transformFunction: null }, structure: { classPropertyName: "structure", publicName: "structure", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, initialAnswers: { classPropertyName: "initialAnswers", publicName: "initialAnswers", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { answersChanged: "answersChanged", questionAnswered: "questionAnswered" }, host: { classAttribute: "axm-questionnaire-viewer" }, providers: [AXMQuestionnaireViewerViewModel], viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, isSignal: true }, { propertyName: "widgetContainer", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<axp-widgets-container #widgetContainer [attr.dir]=\"layoutDirection()\" [context]=\"{}\"\n (onContextChanged)=\"handleContextChanged()\">\n @if (vm.isLoading()) {\n <div class=\"__loading\">\n <axp-state-message icon=\"fa-light fa-spinner fa-spin\"\n [title]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.loading.title' | translate | async) || ''\"\n [description]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.loading.description' | translate | async) || ''\">\n </axp-state-message>\n </div>\n } @else if (vm.error()) {\n <div class=\"__error\">\n <axp-state-message icon=\"fa-light fa-exclamation-triangle\"\n [title]=\"('@assessment-management:questionnaires.components.questionnaire-viewer.error.title' | translate | async) || ''\"\n [description]=\"vm.error() || ''\">\n </axp-state-message>\n </div>\n } @else if (vm.questionnaireData()) {\n <div class=\"__questionnaire-container\">\n <ax-form #form>\n @if (vm.viewMode() === 'single-page') {\n <axm-questionnaire-viewer-single-page-view></axm-questionnaire-viewer-single-page-view>\n } @else if (vm.viewMode() === 'page-per-group') {\n <axm-questionnaire-viewer-page-per-group-view></axm-questionnaire-viewer-page-per-group-view>\n } @else if (vm.viewMode() === 'page-per-question') {\n <axm-questionnaire-viewer-page-per-question-view></axm-questionnaire-viewer-page-per-question-view>\n } @else if (vm.viewMode() === 'side-menu') {\n <axm-questionnaire-viewer-side-menu-view></axm-questionnaire-viewer-side-menu-view>\n }\n </ax-form>\n </div>\n }\n</axp-widgets-container>\n", styles: [".axm-questionnaire-viewer{display:flex;height:100%;max-height:100%;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer ax-form{display:flex;height:100%;min-height:0px;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer axp-widgets-container{display:flex;height:100%;min-height:0px;flex:1 1 0%;flex-direction:column}.axm-questionnaire-viewer .__loading,.axm-questionnaire-viewer .__error{display:flex;height:100%;align-items:center;justify-content:center}.axm-questionnaire-viewer .__questionnaire-container{display:flex;min-height:0px;flex:1 1 0%;flex-direction:column;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPStateMessageComponent, selector: "axp-state-message", inputs: ["mode", "icon", "title", "description", "look"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i1$3.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn", "inUserInteractionActive"], outputs: ["onValidate", "updateOnChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "component", type:
|
|
4187
7309
|
// View components
|
|
4188
|
-
AXMQuestionnaireViewerSinglePageViewComponent, selector: "axm-questionnaire-viewer-single-page-view" }, { kind: "component", type: AXMQuestionnaireViewerPagePerGroupViewComponent, selector: "axm-questionnaire-viewer-page-per-group-view" }, { kind: "component", type: AXMQuestionnaireViewerPagePerQuestionViewComponent, selector: "axm-questionnaire-viewer-page-per-question-view" }, { kind: "component", type: AXMQuestionnaireViewerSideMenuViewComponent, selector: "axm-questionnaire-viewer-side-menu-view" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4
|
|
7310
|
+
AXMQuestionnaireViewerSinglePageViewComponent, selector: "axm-questionnaire-viewer-single-page-view" }, { kind: "component", type: AXMQuestionnaireViewerPagePerGroupViewComponent, selector: "axm-questionnaire-viewer-page-per-group-view" }, { kind: "component", type: AXMQuestionnaireViewerPagePerQuestionViewComponent, selector: "axm-questionnaire-viewer-page-per-question-view" }, { kind: "component", type: AXMQuestionnaireViewerSideMenuViewComponent, selector: "axm-questionnaire-viewer-side-menu-view" }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4189
7311
|
}
|
|
4190
7312
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerComponent, decorators: [{
|
|
4191
7313
|
type: Component,
|
|
@@ -4255,7 +7377,6 @@ class AXMQuestionnaireEvaluatorScopeProvider {
|
|
|
4255
7377
|
async provide(context) {
|
|
4256
7378
|
const questionnaireEntity = `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}`;
|
|
4257
7379
|
const questionBankEntity = `${RootConfig.module.name}.${RootConfig.entities.questionBankItem.name}`;
|
|
4258
|
-
const questionnaireCalculationEntity = `${RootConfig.module.name}.${RootConfig.entities.questionnaireCalculation.name}`;
|
|
4259
7380
|
const filterDefinitionsImpl = async (questionnaireId) => {
|
|
4260
7381
|
if (!questionnaireId) {
|
|
4261
7382
|
return [];
|
|
@@ -4346,27 +7467,20 @@ class AXMQuestionnaireEvaluatorScopeProvider {
|
|
|
4346
7467
|
return [];
|
|
4347
7468
|
}
|
|
4348
7469
|
};
|
|
4349
|
-
/** Filter definitions from questionnaire
|
|
7470
|
+
/** Filter definitions from embedded questionnaire outcomes (for automation condition: rules.ruleName). */
|
|
4350
7471
|
const forRules = async (questionnaireId) => {
|
|
4351
7472
|
if (!questionnaireId) {
|
|
4352
7473
|
return [];
|
|
4353
7474
|
}
|
|
4354
7475
|
try {
|
|
4355
|
-
const dataAccessor = this.entityService.withEntity(
|
|
4356
|
-
const
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
filter: {
|
|
4360
|
-
field: 'questionnaireId',
|
|
4361
|
-
operator: { type: 'equal' },
|
|
4362
|
-
value: questionnaireId,
|
|
4363
|
-
},
|
|
4364
|
-
});
|
|
4365
|
-
const rules = (queryResult?.items ?? []);
|
|
7476
|
+
const dataAccessor = this.entityService.withEntity(questionnaireEntity).data();
|
|
7477
|
+
const questionnaire = await dataAccessor.byKey(questionnaireId);
|
|
7478
|
+
const rules = flattenQuestionnaireOutcomeItems(questionnaire?.outcomes);
|
|
7479
|
+
const locale = this.translationService.getActiveLang() ?? 'en-US';
|
|
4366
7480
|
return rules.map((rule, order) => ({
|
|
4367
7481
|
id: rule.id,
|
|
4368
7482
|
field: `rules.${rule.name}`,
|
|
4369
|
-
title: rule.title
|
|
7483
|
+
title: resolveMultiLanguageString(rule.title, locale) || rule.name,
|
|
4370
7484
|
operator: { type: 'equal' },
|
|
4371
7485
|
widget: {
|
|
4372
7486
|
type: 'string-filter',
|
|
@@ -4389,7 +7503,7 @@ class AXMQuestionnaireEvaluatorScopeProvider {
|
|
|
4389
7503
|
context.addScope('questionnaire', {
|
|
4390
7504
|
/** Filter definitions from questionnaire answers (e.g. visibility / automation conditions). */
|
|
4391
7505
|
answers: filterDefinitionsImpl,
|
|
4392
|
-
/** Filter definitions from questionnaire
|
|
7506
|
+
/** Filter definitions from questionnaire outcomes for automation condition builder (rules.ruleName). */
|
|
4393
7507
|
rules: forRules,
|
|
4394
7508
|
});
|
|
4395
7509
|
// Automation condition builder: provide rules for refType = AssessmentManagement.Questionnaire
|
|
@@ -4422,31 +7536,35 @@ class AXMQuestionnaireViewerFeatureModule {
|
|
|
4422
7536
|
provideCommandSetups([
|
|
4423
7537
|
{
|
|
4424
7538
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}:Preview`,
|
|
4425
|
-
command: () => import('./acorex-modules-assessment-management-preview-questionnaire.command-
|
|
7539
|
+
command: () => import('./acorex-modules-assessment-management-preview-questionnaire.command-S-8MDeB7.mjs').then((c) => c.PreviewQuestionnaireCommand),
|
|
4426
7540
|
},
|
|
4427
7541
|
{
|
|
4428
7542
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}:PreviewQuestion`,
|
|
4429
|
-
command: () => import('./acorex-modules-assessment-management-preview-question.command-
|
|
7543
|
+
command: () => import('./acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs').then((c) => c.PreviewQuestionCommand),
|
|
4430
7544
|
},
|
|
4431
7545
|
{
|
|
4432
7546
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionBankItem.name}:Preview`,
|
|
4433
|
-
command: () => import('./acorex-modules-assessment-management-preview-question.command-
|
|
7547
|
+
command: () => import('./acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs').then((c) => c.PreviewQuestionCommand),
|
|
4434
7548
|
},
|
|
4435
7549
|
{
|
|
4436
7550
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:ViewAnswers`,
|
|
4437
|
-
command: () => import('./acorex-modules-assessment-management-view-session-answers.command-
|
|
7551
|
+
command: () => import('./acorex-modules-assessment-management-view-session-answers.command-COTVoRRG.mjs').then((c) => c.ViewSessionAnswersCommand),
|
|
7552
|
+
},
|
|
7553
|
+
{
|
|
7554
|
+
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:ViewOutcomes`,
|
|
7555
|
+
command: () => import('./acorex-modules-assessment-management-view-session-outcomes.command-2buH7ydV.mjs').then((c) => c.ViewSessionOutcomesCommand),
|
|
4438
7556
|
},
|
|
4439
7557
|
{
|
|
4440
7558
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:Fill`,
|
|
4441
|
-
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-
|
|
7559
|
+
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs').then((c) => c.FillAssessmentSessionCommand),
|
|
4442
7560
|
},
|
|
4443
7561
|
{
|
|
4444
7562
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentCase.name}:Fill`,
|
|
4445
|
-
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-
|
|
7563
|
+
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs').then((c) => c.FillAssessmentSessionCommand),
|
|
4446
7564
|
},
|
|
4447
7565
|
{
|
|
4448
7566
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentCase.name}:ViewLastSessionAnswers`,
|
|
4449
|
-
command: () => import('./acorex-modules-assessment-management-view-case-last-session-answers.command-
|
|
7567
|
+
command: () => import('./acorex-modules-assessment-management-view-case-last-session-answers.command-Ds-QGMPy.mjs').then((c) => c.ViewCaseLastSessionAnswersCommand),
|
|
4450
7568
|
},
|
|
4451
7569
|
]),
|
|
4452
7570
|
], imports: [AXPWidgetCoreModule,
|
|
@@ -4473,31 +7591,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
4473
7591
|
provideCommandSetups([
|
|
4474
7592
|
{
|
|
4475
7593
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}:Preview`,
|
|
4476
|
-
command: () => import('./acorex-modules-assessment-management-preview-questionnaire.command-
|
|
7594
|
+
command: () => import('./acorex-modules-assessment-management-preview-questionnaire.command-S-8MDeB7.mjs').then((c) => c.PreviewQuestionnaireCommand),
|
|
4477
7595
|
},
|
|
4478
7596
|
{
|
|
4479
7597
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionnaire.name}:PreviewQuestion`,
|
|
4480
|
-
command: () => import('./acorex-modules-assessment-management-preview-question.command-
|
|
7598
|
+
command: () => import('./acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs').then((c) => c.PreviewQuestionCommand),
|
|
4481
7599
|
},
|
|
4482
7600
|
{
|
|
4483
7601
|
key: `${RootConfig.module.name}.${RootConfig.entities.questionBankItem.name}:Preview`,
|
|
4484
|
-
command: () => import('./acorex-modules-assessment-management-preview-question.command-
|
|
7602
|
+
command: () => import('./acorex-modules-assessment-management-preview-question.command-Ce7yOnJY.mjs').then((c) => c.PreviewQuestionCommand),
|
|
4485
7603
|
},
|
|
4486
7604
|
{
|
|
4487
7605
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:ViewAnswers`,
|
|
4488
|
-
command: () => import('./acorex-modules-assessment-management-view-session-answers.command-
|
|
7606
|
+
command: () => import('./acorex-modules-assessment-management-view-session-answers.command-COTVoRRG.mjs').then((c) => c.ViewSessionAnswersCommand),
|
|
7607
|
+
},
|
|
7608
|
+
{
|
|
7609
|
+
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:ViewOutcomes`,
|
|
7610
|
+
command: () => import('./acorex-modules-assessment-management-view-session-outcomes.command-2buH7ydV.mjs').then((c) => c.ViewSessionOutcomesCommand),
|
|
4489
7611
|
},
|
|
4490
7612
|
{
|
|
4491
7613
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentSession.name}:Fill`,
|
|
4492
|
-
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-
|
|
7614
|
+
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs').then((c) => c.FillAssessmentSessionCommand),
|
|
4493
7615
|
},
|
|
4494
7616
|
{
|
|
4495
7617
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentCase.name}:Fill`,
|
|
4496
|
-
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-
|
|
7618
|
+
command: () => import('./acorex-modules-assessment-management-fill-assessment-session.command-CRE8SxzC.mjs').then((c) => c.FillAssessmentSessionCommand),
|
|
4497
7619
|
},
|
|
4498
7620
|
{
|
|
4499
7621
|
key: `${RootConfig.module.name}.${RootConfig.entities.assessmentCase.name}:ViewLastSessionAnswers`,
|
|
4500
|
-
command: () => import('./acorex-modules-assessment-management-view-case-last-session-answers.command-
|
|
7622
|
+
command: () => import('./acorex-modules-assessment-management-view-case-last-session-answers.command-Ds-QGMPy.mjs').then((c) => c.ViewCaseLastSessionAnswersCommand),
|
|
4501
7623
|
},
|
|
4502
7624
|
]),
|
|
4503
7625
|
],
|
|
@@ -4550,8 +7672,10 @@ class AXMAssessmentManagementModule {
|
|
|
4550
7672
|
provideLazyProvider(AXP_PERMISSION_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return permissionDefinition_provider; }).then((m) => m.AXMAssessmentManagementPermissionDefinitionProvider)),
|
|
4551
7673
|
provideLazyProvider(AXP_MENU_PROVIDER, () => Promise.resolve().then(function () { return menu_provider; }).then((m) => m.AXMAssessmentManagementMenuProvider)),
|
|
4552
7674
|
provideLazyProvider(AXP_ENTITY_DEFINITION_LOADER, () => Promise.resolve().then(function () { return entity_provider; }).then((m) => m.AXMAssessmentManagementEntityProvider)),
|
|
4553
|
-
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () =>
|
|
4554
|
-
|
|
7675
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index$1; }).then((m) => m.AXMQuestionnaireQuestionsPageComponentProvider)),
|
|
7676
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index; }).then((m) => m.AXMQuestionnaireOutcomesPageComponentProvider)),
|
|
7677
|
+
provideCommand('Questionnaire:Questions:Save', () => Promise.resolve().then(function () { return saveQuestionnaireQuestions_command; }).then((m) => m.AXMSaveQuestionnaireQuestionsCommand)),
|
|
7678
|
+
provideCommand('Questionnaire:Outcomes:Save', () => Promise.resolve().then(function () { return saveQuestionnaireOutcomes_command; }).then((m) => m.AXMSaveQuestionnaireOutcomesCommand)),
|
|
4555
7679
|
provideLazyProvider(AXP_SEARCH_PROVIDER, () => Promise.resolve().then(function () { return searchCommand_provider; }).then((m) => m.AXMAssessmentManagementSearchCommandProvider)),
|
|
4556
7680
|
], imports: [AXMQuestionnaireBuilderFeatureModule,
|
|
4557
7681
|
AXMQuestionnaireViewerFeatureModule] }); }
|
|
@@ -4583,8 +7707,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
4583
7707
|
provideLazyProvider(AXP_PERMISSION_DEFINITION_PROVIDER, () => Promise.resolve().then(function () { return permissionDefinition_provider; }).then((m) => m.AXMAssessmentManagementPermissionDefinitionProvider)),
|
|
4584
7708
|
provideLazyProvider(AXP_MENU_PROVIDER, () => Promise.resolve().then(function () { return menu_provider; }).then((m) => m.AXMAssessmentManagementMenuProvider)),
|
|
4585
7709
|
provideLazyProvider(AXP_ENTITY_DEFINITION_LOADER, () => Promise.resolve().then(function () { return entity_provider; }).then((m) => m.AXMAssessmentManagementEntityProvider)),
|
|
4586
|
-
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () =>
|
|
4587
|
-
|
|
7710
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index$1; }).then((m) => m.AXMQuestionnaireQuestionsPageComponentProvider)),
|
|
7711
|
+
provideLazyProvider(AXP_PAGE_COMPONENT_PROVIDER, () => Promise.resolve().then(function () { return index; }).then((m) => m.AXMQuestionnaireOutcomesPageComponentProvider)),
|
|
7712
|
+
provideCommand('Questionnaire:Questions:Save', () => Promise.resolve().then(function () { return saveQuestionnaireQuestions_command; }).then((m) => m.AXMSaveQuestionnaireQuestionsCommand)),
|
|
7713
|
+
provideCommand('Questionnaire:Outcomes:Save', () => Promise.resolve().then(function () { return saveQuestionnaireOutcomes_command; }).then((m) => m.AXMSaveQuestionnaireOutcomesCommand)),
|
|
4588
7714
|
provideLazyProvider(AXP_SEARCH_PROVIDER, () => Promise.resolve().then(function () { return searchCommand_provider; }).then((m) => m.AXMAssessmentManagementSearchCommandProvider)),
|
|
4589
7715
|
],
|
|
4590
7716
|
}]
|
|
@@ -4593,109 +7719,136 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
4593
7719
|
//#region ---- QuestionBankItem Model ----
|
|
4594
7720
|
//#endregion
|
|
4595
7721
|
|
|
7722
|
+
//#region ---- Types ----
|
|
7723
|
+
//#endregion
|
|
7724
|
+
|
|
7725
|
+
//#region ---- Types ----
|
|
7726
|
+
//#endregion
|
|
7727
|
+
|
|
4596
7728
|
//#region ---- Imports ----
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
reviewEnabled: false,
|
|
4600
|
-
summaryEnabled: false,
|
|
4601
|
-
showCalculationResults: false,
|
|
4602
|
-
};
|
|
4603
|
-
const DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY = {
|
|
4604
|
-
viewMode: 'single-page',
|
|
4605
|
-
showProgressBar: true,
|
|
4606
|
-
showTimer: false,
|
|
4607
|
-
showQuestionNumbers: true,
|
|
4608
|
-
validationStrategy: 'step',
|
|
4609
|
-
completionMode: 'submit-only',
|
|
4610
|
-
};
|
|
7729
|
+
//#endregion
|
|
7730
|
+
//#region ---- Persistence ----
|
|
4611
7731
|
/**
|
|
4612
|
-
*
|
|
7732
|
+
* Loads a session by id using list query first, then byKey.
|
|
4613
7733
|
*/
|
|
4614
|
-
function
|
|
4615
|
-
|
|
4616
|
-
|
|
7734
|
+
async function loadSessionById(entityService, sessionId) {
|
|
7735
|
+
const sessionAccessor = entityService
|
|
7736
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
7737
|
+
.data();
|
|
7738
|
+
const listMatch = await sessionAccessor.query({
|
|
7739
|
+
skip: 0,
|
|
7740
|
+
take: 1,
|
|
7741
|
+
filter: {
|
|
7742
|
+
field: 'id',
|
|
7743
|
+
operator: { type: 'equal' },
|
|
7744
|
+
value: sessionId,
|
|
7745
|
+
},
|
|
7746
|
+
});
|
|
7747
|
+
const fromQuery = first(listMatch.items);
|
|
7748
|
+
if (fromQuery) {
|
|
7749
|
+
return fromQuery;
|
|
4617
7750
|
}
|
|
4618
|
-
|
|
4619
|
-
...DEFAULT_PRE_QUESTIONNAIRE_CONFIG,
|
|
4620
|
-
...q.pre,
|
|
4621
|
-
enabled: q.pre?.enabled === true,
|
|
4622
|
-
};
|
|
4623
|
-
const post = {
|
|
4624
|
-
...DEFAULT_POST_QUESTIONNAIRE_CONFIG,
|
|
4625
|
-
...q.post,
|
|
4626
|
-
reviewEnabled: q.post?.reviewEnabled === true,
|
|
4627
|
-
summaryEnabled: q.post?.summaryEnabled === true,
|
|
4628
|
-
showCalculationResults: q.post?.showCalculationResults === true,
|
|
4629
|
-
};
|
|
4630
|
-
return { pre, post };
|
|
7751
|
+
return defaultTo(await sessionAccessor.byKey(sessionId), null);
|
|
4631
7752
|
}
|
|
4632
|
-
const VIEW_MODE_VALUES = ['single-page', 'page-per-group', 'page-per-question', 'side-menu'];
|
|
4633
|
-
const VALIDATION_STRATEGY_VALUES = ['step', 'end'];
|
|
4634
|
-
const COMPLETION_MODE_VALUES = ['submit-only', 'save-and-continue'];
|
|
4635
7753
|
/**
|
|
4636
|
-
*
|
|
7754
|
+
* Loads assessment case by id using query first, then byKey.
|
|
4637
7755
|
*/
|
|
4638
|
-
function
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
7756
|
+
async function loadCaseById(entityService, caseId) {
|
|
7757
|
+
const caseAccessor = entityService
|
|
7758
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentCase.name)
|
|
7759
|
+
.data();
|
|
7760
|
+
const listMatch = await caseAccessor.query({
|
|
7761
|
+
skip: 0,
|
|
7762
|
+
take: 1,
|
|
7763
|
+
filter: {
|
|
7764
|
+
field: 'id',
|
|
7765
|
+
operator: { type: 'equal' },
|
|
7766
|
+
value: caseId,
|
|
7767
|
+
},
|
|
7768
|
+
});
|
|
7769
|
+
const fromQuery = first(listMatch.items);
|
|
7770
|
+
if (fromQuery) {
|
|
7771
|
+
return fromQuery;
|
|
4644
7772
|
}
|
|
4645
|
-
return
|
|
7773
|
+
return defaultTo(await caseAccessor.byKey(caseId), null);
|
|
4646
7774
|
}
|
|
4647
7775
|
/**
|
|
4648
|
-
*
|
|
7776
|
+
* Bumps case audit metadata by performing a domain update (history middleware sets auditInfo.updated.at).
|
|
4649
7777
|
*/
|
|
4650
|
-
function
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
7778
|
+
async function touchAssessmentCaseActivity(entityService, caseId) {
|
|
7779
|
+
const assessmentCase = await loadCaseById(entityService, caseId);
|
|
7780
|
+
if (!assessmentCase) {
|
|
7781
|
+
return;
|
|
7782
|
+
}
|
|
7783
|
+
const caseAccessor = entityService
|
|
7784
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentCase.name)
|
|
7785
|
+
.data();
|
|
7786
|
+
const caseStatus = assessmentCase.statusId;
|
|
7787
|
+
const nextCaseStatus = caseStatus === AXPSystemStatusType.Closed || caseStatus === AXPSystemStatusType.Cancelled
|
|
7788
|
+
? caseStatus
|
|
7789
|
+
: AXPSystemStatusType.InProgress;
|
|
7790
|
+
await caseAccessor.update(caseId, { statusId: nextCaseStatus });
|
|
4658
7791
|
}
|
|
4659
7792
|
/**
|
|
4660
|
-
*
|
|
7793
|
+
* Upserts assessment session answers and status; moves case to in-progress when saving or submitting.
|
|
4661
7794
|
*/
|
|
4662
|
-
function
|
|
4663
|
-
|
|
4664
|
-
|
|
7795
|
+
async function persistAssessmentSession(input) {
|
|
7796
|
+
const { entityService, questionnaireViewerService, caseId, sessionId, existingSession, responderId, role, structure, answers, finalize, progressMetrics, timeSpentSeconds, } = input;
|
|
7797
|
+
const calculatedProgress = questionnaireViewerService.calculateProgressFromStructure(structure, answers);
|
|
7798
|
+
const answeredQuestionsCount = defaultTo(get(progressMetrics, 'answeredQuestionsCount'), calculatedProgress.answeredQuestionsCount);
|
|
7799
|
+
const progressPercentage = defaultTo(get(progressMetrics, 'progressPercentage'), calculatedProgress.progressPercentage);
|
|
7800
|
+
const now = new Date();
|
|
7801
|
+
const sessionAccessor = entityService
|
|
7802
|
+
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
7803
|
+
.data();
|
|
7804
|
+
let resolvedSessionId = sessionId;
|
|
7805
|
+
let currentSession = existingSession;
|
|
7806
|
+
if (resolvedSessionId && !currentSession) {
|
|
7807
|
+
currentSession = await loadSessionById(entityService, resolvedSessionId);
|
|
7808
|
+
}
|
|
7809
|
+
const sessionStatusId = finalize
|
|
7810
|
+
? 'submitted'
|
|
7811
|
+
: get(currentSession, 'statusId') === 'submitted'
|
|
7812
|
+
? 'submitted'
|
|
7813
|
+
: AXPSystemStatusType.InProgress;
|
|
7814
|
+
const sessionData = {
|
|
7815
|
+
caseId,
|
|
7816
|
+
responderId,
|
|
7817
|
+
role,
|
|
7818
|
+
answers,
|
|
7819
|
+
progressPercentage,
|
|
7820
|
+
answeredQuestionsCount,
|
|
7821
|
+
lastSavedAt: now,
|
|
7822
|
+
statusId: sessionStatusId,
|
|
7823
|
+
};
|
|
7824
|
+
if (isEmpty(get(currentSession, 'startedAt'))) {
|
|
7825
|
+
sessionData['startedAt'] = now;
|
|
4665
7826
|
}
|
|
4666
|
-
if (
|
|
4667
|
-
|
|
7827
|
+
if (timeSpentSeconds != null && timeSpentSeconds >= 0) {
|
|
7828
|
+
sessionData['timeSpent'] = timeSpentSeconds;
|
|
4668
7829
|
}
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
7830
|
+
const questionnaireId = input.questionnaireId;
|
|
7831
|
+
if (questionnaireId) {
|
|
7832
|
+
const { values } = await questionnaireViewerService.evaluateOutcomes(answers, {
|
|
7833
|
+
questionnaireId,
|
|
7834
|
+
structure,
|
|
7835
|
+
});
|
|
7836
|
+
if (isObject(values) && !isEmpty(values)) {
|
|
7837
|
+
sessionData['outcomes'] = values;
|
|
7838
|
+
}
|
|
4677
7839
|
}
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
};
|
|
7840
|
+
if (resolvedSessionId) {
|
|
7841
|
+
await sessionAccessor.update(resolvedSessionId, sessionData);
|
|
7842
|
+
}
|
|
7843
|
+
else {
|
|
7844
|
+
sessionData['startedAt'] = now;
|
|
7845
|
+
resolvedSessionId = await sessionAccessor.create(sessionData);
|
|
7846
|
+
}
|
|
7847
|
+
await touchAssessmentCaseActivity(entityService, caseId);
|
|
7848
|
+
return { sessionId: resolvedSessionId };
|
|
4687
7849
|
}
|
|
4688
7850
|
//#endregion
|
|
4689
7851
|
|
|
4690
|
-
//#region ---- Types ----
|
|
4691
|
-
//#endregion
|
|
4692
|
-
|
|
4693
|
-
//#region ---- Types ----
|
|
4694
|
-
//#endregion
|
|
4695
|
-
|
|
4696
|
-
//#region ---- Types ----
|
|
4697
|
-
//#endregion
|
|
4698
|
-
|
|
4699
7852
|
//#region ---- Imports ----
|
|
4700
7853
|
//#endregion
|
|
4701
7854
|
//#region ---- Component ----
|
|
@@ -4720,7 +7873,7 @@ class AXMPreQuestionnaireContentComponent {
|
|
|
4720
7873
|
[innerHTML]="content() | translate | async | safe: 'html'"
|
|
4721
7874
|
></div>
|
|
4722
7875
|
</div>
|
|
4723
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4
|
|
7876
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AXSafePipe, name: "safe" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4724
7877
|
}
|
|
4725
7878
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPreQuestionnaireContentComponent, decorators: [{
|
|
4726
7879
|
type: Component,
|
|
@@ -4743,6 +7896,166 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
4743
7896
|
}]
|
|
4744
7897
|
}], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }] } });
|
|
4745
7898
|
|
|
7899
|
+
//#region ---- Imports ----
|
|
7900
|
+
//#endregion
|
|
7901
|
+
//#region ---- Presentation ----
|
|
7902
|
+
/**
|
|
7903
|
+
* Maps questionnaire outcome display metadata to platform value chip classes/styles.
|
|
7904
|
+
*/
|
|
7905
|
+
function mapOutcomeDisplayToValuePresentation(display) {
|
|
7906
|
+
const classes = ['__outcome-value'];
|
|
7907
|
+
if (display?.emphasis === 'medium') {
|
|
7908
|
+
classes.push('__emphasis-medium');
|
|
7909
|
+
}
|
|
7910
|
+
else if (display?.emphasis === 'bold') {
|
|
7911
|
+
classes.push('__emphasis-bold');
|
|
7912
|
+
}
|
|
7913
|
+
if (!display?.color) {
|
|
7914
|
+
classes.push('__tone-default');
|
|
7915
|
+
return { classes: classes.join(' ') };
|
|
7916
|
+
}
|
|
7917
|
+
const parsed = parseQuestionnaireOutcomeDisplayColor(display.color);
|
|
7918
|
+
if (!parsed) {
|
|
7919
|
+
classes.push('__tone-default');
|
|
7920
|
+
return { classes: classes.join(' ') };
|
|
7921
|
+
}
|
|
7922
|
+
if (isQuestionnaireOutcomeDisplayColorHex(parsed.background)) {
|
|
7923
|
+
return {
|
|
7924
|
+
classes: classes.join(' '),
|
|
7925
|
+
color: parsed.foreground,
|
|
7926
|
+
backgroundColor: parsed.background,
|
|
7927
|
+
borderColor: parsed.border,
|
|
7928
|
+
};
|
|
7929
|
+
}
|
|
7930
|
+
return {
|
|
7931
|
+
classes: [...classes, parsed.foreground, parsed.background, parsed.border].join(' '),
|
|
7932
|
+
};
|
|
7933
|
+
}
|
|
7934
|
+
function mapOutcomeRow(entry) {
|
|
7935
|
+
return {
|
|
7936
|
+
key: entry.key,
|
|
7937
|
+
label: entry.label,
|
|
7938
|
+
value: entry.value,
|
|
7939
|
+
iconClass: entry.display?.iconClass,
|
|
7940
|
+
valuePresentation: mapOutcomeDisplayToValuePresentation(entry.display),
|
|
7941
|
+
};
|
|
7942
|
+
}
|
|
7943
|
+
function resolveSectionText(value, locale, fallback) {
|
|
7944
|
+
const resolved = resolveMultiLanguageString(value, locale).trim();
|
|
7945
|
+
return resolved.length > 0 ? resolved : fallback;
|
|
7946
|
+
}
|
|
7947
|
+
//#endregion
|
|
7948
|
+
//#region ---- View model ----
|
|
7949
|
+
/**
|
|
7950
|
+
* Maps post-submit placeholder values or snapshot sections to {@link AXPOutcomeResultsViewModel}.
|
|
7951
|
+
*/
|
|
7952
|
+
function mapToOutcomeResultsViewModel(source, options) {
|
|
7953
|
+
const locale = options?.locale ?? 'en-US';
|
|
7954
|
+
const sections = source?.outcomeSections;
|
|
7955
|
+
if (Array.isArray(sections) && sections.length > 0) {
|
|
7956
|
+
return {
|
|
7957
|
+
sections: sections.map((group) => mapSectionGroup(group, locale)),
|
|
7958
|
+
rows: sections.length === 1 ? sections[0].items.map(mapOutcomeRow) : undefined,
|
|
7959
|
+
};
|
|
7960
|
+
}
|
|
7961
|
+
const outcomes = source?.outcomes;
|
|
7962
|
+
const titles = source?.outcomeTitles;
|
|
7963
|
+
if (!outcomes || typeof outcomes !== 'object') {
|
|
7964
|
+
return { rows: [] };
|
|
7965
|
+
}
|
|
7966
|
+
const rows = Object.entries(outcomes).map(([key, value]) => mapOutcomeRow({
|
|
7967
|
+
key,
|
|
7968
|
+
value,
|
|
7969
|
+
label: (titles?.[key] ?? '').trim() || humanizeOutcomeKey(key),
|
|
7970
|
+
}));
|
|
7971
|
+
return { rows };
|
|
7972
|
+
}
|
|
7973
|
+
function mapSectionGroup(group, locale) {
|
|
7974
|
+
const fallbackTitle = group.sectionName || group.trackKey;
|
|
7975
|
+
return {
|
|
7976
|
+
trackKey: group.trackKey,
|
|
7977
|
+
title: resolveSectionText(group.sectionTitle, locale, fallbackTitle),
|
|
7978
|
+
description: group.sectionDescription
|
|
7979
|
+
? resolveSectionText(group.sectionDescription, locale, '')
|
|
7980
|
+
: undefined,
|
|
7981
|
+
items: group.items.map(mapOutcomeRow),
|
|
7982
|
+
};
|
|
7983
|
+
}
|
|
7984
|
+
function humanizeOutcomeKey(key) {
|
|
7985
|
+
return key
|
|
7986
|
+
.replace(/_/g, ' ')
|
|
7987
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
7988
|
+
.trim()
|
|
7989
|
+
.split(/\s+/)
|
|
7990
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
7991
|
+
.join(' ');
|
|
7992
|
+
}
|
|
7993
|
+
//#endregion
|
|
7994
|
+
|
|
7995
|
+
//#region ---- Imports ----
|
|
7996
|
+
//#endregion
|
|
7997
|
+
//#region ---- Component ----
|
|
7998
|
+
/**
|
|
7999
|
+
* Post-submit outcome results step; delegates presentation to {@link AXPOutcomeResultsViewerComponent}.
|
|
8000
|
+
*/
|
|
8001
|
+
class AXMQuestionnaireOutcomeResultsComponent {
|
|
8002
|
+
constructor() {
|
|
8003
|
+
//#region ---- Services & Dependencies ----
|
|
8004
|
+
this.translationService = inject(AXTranslationService);
|
|
8005
|
+
//#endregion
|
|
8006
|
+
//#region ---- Inputs ----
|
|
8007
|
+
/** Evaluated outcomes, titles, and optional grouped sections from the viewer service. */
|
|
8008
|
+
this.placeholderValues = input(null, ...(ngDevMode ? [{ debugName: "placeholderValues" }] : /* istanbul ignore next */ []));
|
|
8009
|
+
//#endregion
|
|
8010
|
+
//#region ---- Computed ----
|
|
8011
|
+
this.viewModel = computed(() => {
|
|
8012
|
+
const locale = this.translationService.getActiveLang?.() ?? 'en-US';
|
|
8013
|
+
return mapToOutcomeResultsViewModel(this.placeholderValues(), { locale });
|
|
8014
|
+
}, ...(ngDevMode ? [{ debugName: "viewModel" }] : /* istanbul ignore next */ []));
|
|
8015
|
+
}
|
|
8016
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomeResultsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8017
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.9", type: AXMQuestionnaireOutcomeResultsComponent, isStandalone: true, selector: "axm-questionnaire-outcome-results", inputs: { placeholderValues: { classPropertyName: "placeholderValues", publicName: "placeholderValues", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "axm-questionnaire-outcome-results ax-block" }, ngImport: i0, template: `
|
|
8018
|
+
<axp-outcome-results-viewer
|
|
8019
|
+
[model]="viewModel()"
|
|
8020
|
+
[title]="
|
|
8021
|
+
('@assessment-management:questionnaires.components.questionnaire-viewer.flow.outcomes-section-title'
|
|
8022
|
+
| translate
|
|
8023
|
+
| async) ?? ''
|
|
8024
|
+
"
|
|
8025
|
+
[emptyMessage]="
|
|
8026
|
+
('@assessment-management:questionnaires.components.questionnaire-viewer.flow.no-outcomes'
|
|
8027
|
+
| translate
|
|
8028
|
+
| async) ?? ''
|
|
8029
|
+
"
|
|
8030
|
+
/>
|
|
8031
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPOutcomeResultsViewerComponent, selector: "axp-outcome-results-viewer", inputs: ["model", "title", "emptyMessage"] }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
8032
|
+
}
|
|
8033
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireOutcomeResultsComponent, decorators: [{
|
|
8034
|
+
type: Component,
|
|
8035
|
+
args: [{
|
|
8036
|
+
selector: 'axm-questionnaire-outcome-results',
|
|
8037
|
+
template: `
|
|
8038
|
+
<axp-outcome-results-viewer
|
|
8039
|
+
[model]="viewModel()"
|
|
8040
|
+
[title]="
|
|
8041
|
+
('@assessment-management:questionnaires.components.questionnaire-viewer.flow.outcomes-section-title'
|
|
8042
|
+
| translate
|
|
8043
|
+
| async) ?? ''
|
|
8044
|
+
"
|
|
8045
|
+
[emptyMessage]="
|
|
8046
|
+
('@assessment-management:questionnaires.components.questionnaire-viewer.flow.no-outcomes'
|
|
8047
|
+
| translate
|
|
8048
|
+
| async) ?? ''
|
|
8049
|
+
"
|
|
8050
|
+
/>
|
|
8051
|
+
`,
|
|
8052
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
8053
|
+
imports: [AXTranslationModule, AsyncPipe, AXPOutcomeResultsViewerComponent],
|
|
8054
|
+
encapsulation: ViewEncapsulation.None,
|
|
8055
|
+
host: { class: 'axm-questionnaire-outcome-results ax-block' },
|
|
8056
|
+
}]
|
|
8057
|
+
}], propDecorators: { placeholderValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholderValues", required: false }] }] } });
|
|
8058
|
+
|
|
4746
8059
|
//#region ---- Imports ----
|
|
4747
8060
|
//#endregion
|
|
4748
8061
|
//#region ---- Component ----
|
|
@@ -4758,7 +8071,7 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4758
8071
|
this.translationService = inject(AXTranslationService);
|
|
4759
8072
|
//#endregion
|
|
4760
8073
|
//#region ---- Inputs ----
|
|
4761
|
-
/** Display mode: review, summary (rich text), or results (
|
|
8074
|
+
/** Display mode: review, summary (rich text), or results (outcome list). */
|
|
4762
8075
|
this.mode = input('review', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
4763
8076
|
/** Questions with answers for review mode. */
|
|
4764
8077
|
this.questionsWithAnswers = input([], ...(ngDevMode ? [{ debugName: "questionsWithAnswers" }] : /* istanbul ignore next */ []));
|
|
@@ -4766,7 +8079,7 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4766
8079
|
this.reviewContext = input(null, ...(ngDevMode ? [{ debugName: "reviewContext" }] : /* istanbul ignore next */ []));
|
|
4767
8080
|
/** Summary content (rich text). Supports multi-language and placeholders. */
|
|
4768
8081
|
this.summaryContent = input(null, ...(ngDevMode ? [{ debugName: "summaryContent" }] : /* istanbul ignore next */ []));
|
|
4769
|
-
/** Placeholder values: totals, time, and
|
|
8082
|
+
/** Placeholder values: totals, time, and outcome values. */
|
|
4770
8083
|
this.placeholderValues = input(null, ...(ngDevMode ? [{ debugName: "placeholderValues" }] : /* istanbul ignore next */ []));
|
|
4771
8084
|
/** Locale for multi-language content. Defaults to active lang. */
|
|
4772
8085
|
this.locale = input(undefined, ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
@@ -4807,19 +8120,6 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4807
8120
|
}
|
|
4808
8121
|
return groups;
|
|
4809
8122
|
}, ...(ngDevMode ? [{ debugName: "reviewSectionGroups" }] : /* istanbul ignore next */ []));
|
|
4810
|
-
/** Calculation name/value pairs for results step; `label` is entity title or humanized name. */
|
|
4811
|
-
this.outcomeEntries = computed(() => {
|
|
4812
|
-
const pv = this.placeholderValues();
|
|
4813
|
-
const o = pv?.outcomes;
|
|
4814
|
-
const titles = pv?.outcomeTitles;
|
|
4815
|
-
if (!o || typeof o !== 'object')
|
|
4816
|
-
return [];
|
|
4817
|
-
return Object.entries(o).map(([key, value]) => ({
|
|
4818
|
-
key,
|
|
4819
|
-
value,
|
|
4820
|
-
label: (titles?.[key] ?? '').trim() || this.humanizeOutcomeKey(key),
|
|
4821
|
-
}));
|
|
4822
|
-
}, ...(ngDevMode ? [{ debugName: "outcomeEntries" }] : /* istanbul ignore next */ []));
|
|
4823
8123
|
this.summaryContentHtml = computed(() => {
|
|
4824
8124
|
const content = this.summaryContent();
|
|
4825
8125
|
const values = this.placeholderValues();
|
|
@@ -4836,16 +8136,6 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4836
8136
|
}
|
|
4837
8137
|
//#endregion
|
|
4838
8138
|
//#region ---- Helpers ----
|
|
4839
|
-
/** Fallback when no calculation entity title is available. */
|
|
4840
|
-
humanizeOutcomeKey(key) {
|
|
4841
|
-
return key
|
|
4842
|
-
.replace(/_/g, ' ')
|
|
4843
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
4844
|
-
.trim()
|
|
4845
|
-
.split(/\s+/)
|
|
4846
|
-
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
4847
|
-
.join(' ');
|
|
4848
|
-
}
|
|
4849
8139
|
formatAnswer(answer) {
|
|
4850
8140
|
if (answer == null || answer === '')
|
|
4851
8141
|
return '—';
|
|
@@ -4934,43 +8224,7 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4934
8224
|
</div>
|
|
4935
8225
|
</div>
|
|
4936
8226
|
} @else if (mode() === 'results') {
|
|
4937
|
-
<
|
|
4938
|
-
class="axm-post-questionnaire-content __results ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-8 ax-min-h-[200px] ax-text-on-surface"
|
|
4939
|
-
>
|
|
4940
|
-
@if (outcomeEntries().length > 0) {
|
|
4941
|
-
<div class="ax-max-w-2xl ax-w-full">
|
|
4942
|
-
<h3 class="ax-text-base ax-font-semibold ax-mb-3 ax-text-on-surface">
|
|
4943
|
-
{{
|
|
4944
|
-
'@assessment-management:questionnaires.components.questionnaire-viewer.flow.outcomes-section-title'
|
|
4945
|
-
| translate
|
|
4946
|
-
| async
|
|
4947
|
-
}}
|
|
4948
|
-
</h3>
|
|
4949
|
-
<ul
|
|
4950
|
-
class="ax-list-none ax-p-0 ax-m-0 ax-flex ax-flex-col ax-gap-1 ax-rounded-lg ax-border ax-border-surface ax-lighter-surface ax-overflow-hidden"
|
|
4951
|
-
>
|
|
4952
|
-
@for (row of outcomeEntries(); track row.key) {
|
|
4953
|
-
<li
|
|
4954
|
-
class="ax-flex ax-justify-between ax-gap-4 ax-py-3 ax-px-4 ax-border-b ax-border-surface last:ax-border-b-0"
|
|
4955
|
-
>
|
|
4956
|
-
<span class="ax-text-sm ax-font-medium __post-text-muted">{{ row.label }}</span>
|
|
4957
|
-
<span class="ax-text-sm ax-text-on-surface ax-text-right ax-break-all">{{
|
|
4958
|
-
formatAnswer(row.value)
|
|
4959
|
-
}}</span>
|
|
4960
|
-
</li>
|
|
4961
|
-
}
|
|
4962
|
-
</ul>
|
|
4963
|
-
</div>
|
|
4964
|
-
} @else {
|
|
4965
|
-
<p class="ax-text-sm __post-text-muted">
|
|
4966
|
-
{{
|
|
4967
|
-
'@assessment-management:questionnaires.components.questionnaire-viewer.flow.no-outcomes'
|
|
4968
|
-
| translate
|
|
4969
|
-
| async
|
|
4970
|
-
}}
|
|
4971
|
-
</p>
|
|
4972
|
-
}
|
|
4973
|
-
</div>
|
|
8227
|
+
<axm-questionnaire-outcome-results [placeholderValues]="placeholderValues()" />
|
|
4974
8228
|
} @else {
|
|
4975
8229
|
<div
|
|
4976
8230
|
class="axm-post-questionnaire-content __summary ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-8 ax-min-h-[200px] ax-text-on-surface"
|
|
@@ -4978,7 +8232,7 @@ class AXMPostQuestionnaireContentComponent {
|
|
|
4978
8232
|
<div class="ax-max-w-2xl ax-w-full ax-prose ax-text-on-surface" [innerHTML]="summaryContentHtml()"></div>
|
|
4979
8233
|
</div>
|
|
4980
8234
|
}
|
|
4981
|
-
`, isInline: true, styles: [".axm-post-questionnaire-content .__post-text-muted{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "component", type: AXMQuestionnaireViewerQuestionComponent, selector: "axm-questionnaire-viewer-question", inputs: ["question", "contextData", "sectionOrder", "questionIndex", "showQuestionNumbers", "showQuestionCounter", "currentPosition", "mode"] }, { kind: "component", type: AXMQuestionnaireViewerSectionHeaderComponent, selector: "axm-questionnaire-viewer-section-header", inputs: ["title", "description", "titleSize", "marginBottom"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4
|
|
8235
|
+
`, isInline: true, styles: [".axm-post-questionnaire-content .__post-text-muted{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1$1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "component", type: AXMQuestionnaireOutcomeResultsComponent, selector: "axm-questionnaire-outcome-results", inputs: ["placeholderValues"] }, { kind: "component", type: AXMQuestionnaireViewerQuestionComponent, selector: "axm-questionnaire-viewer-question", inputs: ["question", "contextData", "sectionOrder", "questionIndex", "showQuestionNumbers", "showQuestionCounter", "currentPosition", "mode"] }, { kind: "component", type: AXMQuestionnaireViewerSectionHeaderComponent, selector: "axm-questionnaire-viewer-section-header", inputs: ["title", "description", "titleSize", "marginBottom"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
4982
8236
|
}
|
|
4983
8237
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMPostQuestionnaireContentComponent, decorators: [{
|
|
4984
8238
|
type: Component,
|
|
@@ -5056,43 +8310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5056
8310
|
</div>
|
|
5057
8311
|
</div>
|
|
5058
8312
|
} @else if (mode() === 'results') {
|
|
5059
|
-
<
|
|
5060
|
-
class="axm-post-questionnaire-content __results ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-8 ax-min-h-[200px] ax-text-on-surface"
|
|
5061
|
-
>
|
|
5062
|
-
@if (outcomeEntries().length > 0) {
|
|
5063
|
-
<div class="ax-max-w-2xl ax-w-full">
|
|
5064
|
-
<h3 class="ax-text-base ax-font-semibold ax-mb-3 ax-text-on-surface">
|
|
5065
|
-
{{
|
|
5066
|
-
'@assessment-management:questionnaires.components.questionnaire-viewer.flow.outcomes-section-title'
|
|
5067
|
-
| translate
|
|
5068
|
-
| async
|
|
5069
|
-
}}
|
|
5070
|
-
</h3>
|
|
5071
|
-
<ul
|
|
5072
|
-
class="ax-list-none ax-p-0 ax-m-0 ax-flex ax-flex-col ax-gap-1 ax-rounded-lg ax-border ax-border-surface ax-lighter-surface ax-overflow-hidden"
|
|
5073
|
-
>
|
|
5074
|
-
@for (row of outcomeEntries(); track row.key) {
|
|
5075
|
-
<li
|
|
5076
|
-
class="ax-flex ax-justify-between ax-gap-4 ax-py-3 ax-px-4 ax-border-b ax-border-surface last:ax-border-b-0"
|
|
5077
|
-
>
|
|
5078
|
-
<span class="ax-text-sm ax-font-medium __post-text-muted">{{ row.label }}</span>
|
|
5079
|
-
<span class="ax-text-sm ax-text-on-surface ax-text-right ax-break-all">{{
|
|
5080
|
-
formatAnswer(row.value)
|
|
5081
|
-
}}</span>
|
|
5082
|
-
</li>
|
|
5083
|
-
}
|
|
5084
|
-
</ul>
|
|
5085
|
-
</div>
|
|
5086
|
-
} @else {
|
|
5087
|
-
<p class="ax-text-sm __post-text-muted">
|
|
5088
|
-
{{
|
|
5089
|
-
'@assessment-management:questionnaires.components.questionnaire-viewer.flow.no-outcomes'
|
|
5090
|
-
| translate
|
|
5091
|
-
| async
|
|
5092
|
-
}}
|
|
5093
|
-
</p>
|
|
5094
|
-
}
|
|
5095
|
-
</div>
|
|
8313
|
+
<axm-questionnaire-outcome-results [placeholderValues]="placeholderValues()" />
|
|
5096
8314
|
} @else {
|
|
5097
8315
|
<div
|
|
5098
8316
|
class="axm-post-questionnaire-content __summary ax-flex ax-flex-col ax-items-center ax-justify-center ax-p-8 ax-min-h-[200px] ax-text-on-surface"
|
|
@@ -5104,6 +8322,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5104
8322
|
CommonModule,
|
|
5105
8323
|
AXTranslationModule,
|
|
5106
8324
|
AXPWidgetCoreModule,
|
|
8325
|
+
AXMQuestionnaireOutcomeResultsComponent,
|
|
5107
8326
|
AXMQuestionnaireViewerQuestionComponent,
|
|
5108
8327
|
AXMQuestionnaireViewerSectionHeaderComponent,
|
|
5109
8328
|
], encapsulation: ViewEncapsulation.None, host: { class: 'axm-post-questionnaire-content' }, styles: [".axm-post-questionnaire-content .__post-text-muted{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"] }]
|
|
@@ -5133,6 +8352,7 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5133
8352
|
this.isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
5134
8353
|
this.loadError = signal(null, ...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
5135
8354
|
this.currentSessionId = signal(null, ...(ngDevMode ? [{ debugName: "currentSessionId" }] : /* istanbul ignore next */ []));
|
|
8355
|
+
this.existingSession = signal(null, ...(ngDevMode ? [{ debugName: "existingSession" }] : /* istanbul ignore next */ []));
|
|
5136
8356
|
this.flowStep = signal('questions', ...(ngDevMode ? [{ debugName: "flowStep" }] : /* istanbul ignore next */ []));
|
|
5137
8357
|
this.reviewSnapshot = signal([], ...(ngDevMode ? [{ debugName: "reviewSnapshot" }] : /* istanbul ignore next */ []));
|
|
5138
8358
|
this.reviewContext = signal(null, ...(ngDevMode ? [{ debugName: "reviewContext" }] : /* istanbul ignore next */ []));
|
|
@@ -5219,9 +8439,12 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5219
8439
|
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
5220
8440
|
.data()
|
|
5221
8441
|
.byKey(existingSessionId);
|
|
5222
|
-
if (session
|
|
5223
|
-
|
|
8442
|
+
if (session) {
|
|
8443
|
+
if (session.answers) {
|
|
8444
|
+
answers = session.answers;
|
|
8445
|
+
}
|
|
5224
8446
|
this.currentSessionId.set(existingSessionId);
|
|
8447
|
+
this.existingSession.set(session);
|
|
5225
8448
|
}
|
|
5226
8449
|
}
|
|
5227
8450
|
this.questionnaire.set(questionnaire);
|
|
@@ -5253,7 +8476,7 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5253
8476
|
this.handleDone();
|
|
5254
8477
|
return;
|
|
5255
8478
|
}
|
|
5256
|
-
if (cfg?.post.
|
|
8479
|
+
if (cfg?.post.showOutcomeResults === true) {
|
|
5257
8480
|
this.flowStep.set('results');
|
|
5258
8481
|
return;
|
|
5259
8482
|
}
|
|
@@ -5269,7 +8492,6 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5269
8492
|
const q = this.questionnaire();
|
|
5270
8493
|
if (!caseIdVal || !structureVal || !q)
|
|
5271
8494
|
return null;
|
|
5272
|
-
const { answeredQuestionsCount, progressPercentage } = this.questionnaireViewerService.calculateProgressFromStructure(structureVal, answers);
|
|
5273
8495
|
const responderId = this.authSession.user?.id;
|
|
5274
8496
|
if (!responderId) {
|
|
5275
8497
|
this.toastService.show({
|
|
@@ -5279,39 +8501,41 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5279
8501
|
});
|
|
5280
8502
|
return null;
|
|
5281
8503
|
}
|
|
5282
|
-
const
|
|
5283
|
-
const
|
|
5284
|
-
|
|
5285
|
-
|
|
8504
|
+
const vm = this.viewerViewModel();
|
|
8505
|
+
const result = await persistAssessmentSession({
|
|
8506
|
+
entityService: this.entityService,
|
|
8507
|
+
questionnaireViewerService: this.questionnaireViewerService,
|
|
5286
8508
|
caseId: caseIdVal,
|
|
8509
|
+
sessionId: this.currentSessionId(),
|
|
8510
|
+
existingSession: this.existingSession(),
|
|
5287
8511
|
responderId,
|
|
5288
|
-
role,
|
|
8512
|
+
role: 'responder',
|
|
8513
|
+
structure: structureVal,
|
|
8514
|
+
questionnaireId: q.id,
|
|
5289
8515
|
answers,
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
8516
|
+
finalize: true,
|
|
8517
|
+
progressMetrics: vm
|
|
8518
|
+
? {
|
|
8519
|
+
answeredQuestionsCount: vm.answeredQuestionsCount(),
|
|
8520
|
+
progressPercentage: vm.progressPercentage(),
|
|
8521
|
+
}
|
|
8522
|
+
: undefined,
|
|
8523
|
+
timeSpentSeconds: vm?.timerElapsed(),
|
|
8524
|
+
});
|
|
8525
|
+
this.currentSessionId.set(result.sessionId);
|
|
8526
|
+
const session = await this.entityService
|
|
5295
8527
|
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
5296
|
-
.data()
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
this.
|
|
5300
|
-
color: 'success',
|
|
5301
|
-
title: await this.translateService.translateAsync('@general:messages.form.saved.success.title'),
|
|
5302
|
-
content: await this.translateService.translateAsync('@general:messages.form.saved.success.description'),
|
|
5303
|
-
});
|
|
5304
|
-
}
|
|
5305
|
-
else {
|
|
5306
|
-
const newSessionData = { ...sessionData, startedAt: now };
|
|
5307
|
-
await sessionDataAccessor.create(newSessionData);
|
|
5308
|
-
this.toastService.show({
|
|
5309
|
-
color: 'success',
|
|
5310
|
-
title: await this.translateService.translateAsync('@assessment-management:sessions.states.submitted'),
|
|
5311
|
-
content: '',
|
|
5312
|
-
});
|
|
8528
|
+
.data()
|
|
8529
|
+
.byKey(result.sessionId);
|
|
8530
|
+
if (session) {
|
|
8531
|
+
this.existingSession.set(session);
|
|
5313
8532
|
}
|
|
5314
|
-
|
|
8533
|
+
this.toastService.show({
|
|
8534
|
+
color: 'success',
|
|
8535
|
+
title: await this.translateService.translateAsync('@assessment-management:sessions.states.submitted'),
|
|
8536
|
+
content: '',
|
|
8537
|
+
});
|
|
8538
|
+
const elapsed = vm?.timerElapsed() ?? 0;
|
|
5315
8539
|
return this.questionnaireViewerService.buildSummaryPlaceholderValues(structureVal, answers, {
|
|
5316
8540
|
questionnaireId: q.id,
|
|
5317
8541
|
elapsedSeconds: elapsed,
|
|
@@ -5405,9 +8629,9 @@ class AXMQuestionnaireViewerPageComponent extends AXPPageLayoutBaseComponent {
|
|
|
5405
8629
|
this.router.navigateByUrl(this.getCasesListPath());
|
|
5406
8630
|
}
|
|
5407
8631
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5408
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerPageComponent, isStandalone: true, selector: "axm-questionnaire-viewer-page", host: { classAttribute: "axm-questionnaire-viewer-page" }, providers: [{ provide: AXPPageLayoutBase, useExisting: AXMQuestionnaireViewerPageComponent }], viewQueries: [{ propertyName: "viewer", first: true, predicate: ["viewer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Page shell layout -->\n<axp-page-layout>\n <!-- Main content area -->\n <axp-page-content class=\"ax-flex ax-flex-col ax-flex-1 ax-min-h-0\"\n [class.ax-overflow-hidden]=\"flowStep() === 'questions'\" [class.ax-overflow-y-auto]=\"flowStep() !== 'questions'\">\n <!-- Loading state -->\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-min-h-[200px]\">\n <span>{{ '@assessment-management:questionnaires.components.questionnaire-viewer.loading.title' | translate | async\n }}</span>\n </div>\n }\n <!-- Error state -->\n @else if (loadError()) {\n <div class=\"ax-p-4 ax-text-error-600\">\n {{ loadError() }}\n </div>\n }\n <!-- Content state -->\n @else if (structure()) {\n <!-- Pre-questionnaire introduction content -->\n @if (flowStep() === 'pre') {\n <axm-pre-questionnaire-content [content]=\"prePostConfig()?.pre?.content\"></axm-pre-questionnaire-content>\n }\n <!-- Post-submit results content -->\n @else if (flowStep() === 'results') {\n <axm-post-questionnaire-content mode=\"results\"\n [placeholderValues]=\"submitResult()\"></axm-post-questionnaire-content>\n }\n <!-- Post-submit summary content -->\n @else if (flowStep() === 'summary') {\n <axm-post-questionnaire-content mode=\"summary\" [summaryContent]=\"prePostConfig()?.post?.summaryContent\"\n [placeholderValues]=\"submitResult()\"></axm-post-questionnaire-content>\n }\n <!-- Questionnaire and review flow -->\n @else {\n <!-- Review mode content -->\n @if (flowStep() === 'review') {\n <axm-post-questionnaire-content mode=\"review\" [questionsWithAnswers]=\"reviewSnapshot()\"\n [reviewContext]=\"reviewContext()\"></axm-post-questionnaire-content>\n }\n\n <!-- Questionnaire workspace (hidden while in review mode) -->\n <div class=\"__questions ax-flex ax-flex-col ax-flex-1 ax-min-h-0 ax-overflow-hidden\"\n [class.ax-invisible]=\"flowStep() === 'review'\" [style.position]=\"flowStep() === 'review' ? 'fixed' : null\"\n [style.left]=\"flowStep() === 'review' ? '-9999px' : null\" [class.ax-size-0]=\"flowStep() === 'review'\"\n [class.ax-overflow-hidden]=\"flowStep() === 'review'\">\n\n <!-- Questionnaire rendering container -->\n <div class=\"__content ax-flex ax-flex-col ax-flex-1 ax-min-h-0 ax-overflow-y-auto ax-overflow-x-hidden\">\n <axm-questionnaire-viewer #viewer [structure]=\"structure()!\" [config]=\"viewerConfig()\"\n [initialAnswers]=\"effectiveInitialAnswers()\"\n (answersChanged)=\"handleAnswersChanged($event)\"></axm-questionnaire-viewer>\n </div>\n </div>\n }\n }\n </axp-page-content>\n\n <!-- Footer actions (only when content is ready) -->\n @if (structure() && !isLoading() && !loadError()) {\n <axp-page-footer class=\"--animated\">\n <!-- Footer prefix: progress indicator -->\n <axp-layout-prefix>\n @if (flowStep() === 'questions') {\n <div class=\"__footer-progress ax-text-sm ax-font-mono ax-tabular-nums\" dir=\"ltr\">\n @if (showProgressBar()) {\n {{ answeredQuestionsCount() }} / {{ totalQuestionsCount() }}\n }\n </div>\n }\n <!-- @if (showTimer()) {\n <axp-stopwatch [mode]=\"timerTimeLimit() ? 'count-down' : 'count-up'\" [timeLimit]=\"timerTimeLimit()\"\n [format]=\"timerTimeLimit() && timerTimeLimit()! >= 3600 ? 'hh:mm:ss' : 'mm:ss'\" [autoStart]=\"true\"\n [showControls]=\"false\" [value]=\"timerElapsed()\"\n (valueChange)=\"viewerViewModel()!.updateTimerElapsed($event)\"></axp-stopwatch>\n } -->\n </axp-layout-prefix>\n\n <!-- Footer suffix: flow action buttons -->\n <axp-layout-suffix>\n @if (flowStep() === 'pre') {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.start' | translate | async\"\n (onClick)=\"flowStep.set('questions')\"></ax-button>\n }\n <!-- Question step actions -->\n @else if (flowStep() === 'questions') {\n <!-- Question navigation buttons -->\n @if (showNavigationButtons()) {\n <ax-button look=\"solid\" [disabled]=\"!canNavigatePrevious()\"\n [text]=\"'@general:actions.previous.title' | translate | async\" (onClick)=\"handlePreviousClick()\"></ax-button>\n @if (!isLastStep()) {\n <ax-button look=\"solid\" color=\"primary\" [disabled]=\"!canNavigateNext()\"\n [text]=\"'@general:actions.next.title' | translate | async\" (onClick)=\"handleNextClick()\"></ax-button>\n }\n }\n\n <!-- Final-step actions -->\n @if (isLastStep() && showReviewButton()) {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.review' | translate | async\"\n [disabled]=\"!areAllRequiredQuestionsAnswered()\" (onClick)=\"handleReviewClick()\"></ax-button>\n }\n @if (isLastStep() && !showReviewButton()) {\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.submit.title' | translate | async\"\n [disabled]=\"isReadonly() || isSubmitting() || !areAllRequiredQuestionsAnswered()\"\n (onClick)=\"handleSubmitClick()\"></ax-button>\n }\n }\n <!-- Review step actions -->\n @else if (flowStep() === 'review') {\n <ax-button look=\"outline\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.edit' | translate | async\"\n (onClick)=\"flowStep.set('questions')\"></ax-button>\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.submit.title' | translate | async\"\n [disabled]=\"isSubmitting()\" (onClick)=\"handleReviewSubmit()\"></ax-button>\n }\n <!-- Results step actions -->\n @else if (flowStep() === 'results') {\n @if (prePostConfig()?.post?.summaryEnabled) {\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.next.title' | translate | async\"\n (onClick)=\"flowStep.set('summary')\"></ax-button>\n } @else {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.done' | translate | async\"\n (onClick)=\"handleDone()\"></ax-button>\n }\n }\n <!-- Summary step action -->\n @else if (flowStep() === 'summary') {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.done' | translate | async\"\n (onClick)=\"handleDone()\"></ax-button>\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axm-questionnaire-viewer-page .__questions{min-height:0px;overflow:hidden}axm-questionnaire-viewer-page .__header{z-index:20;display:flex;flex-shrink:0;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));position:sticky;top:0;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-page .__content axm-questionnaire-viewer{display:flex;height:auto;max-height:none;min-height:0px;width:100%;max-width:100%;flex:none;flex-direction:column}axm-questionnaire-viewer-page .__content axm-questionnaire-viewer .__questionnaire-container{min-height:0px;flex:none;overflow:visible}axm-questionnaire-viewer-page .__toolbar-meta{color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-page .__footer-progress{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1
|
|
8632
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXMQuestionnaireViewerPageComponent, isStandalone: true, selector: "axm-questionnaire-viewer-page", host: { classAttribute: "axm-questionnaire-viewer-page" }, providers: [{ provide: AXPPageLayoutBase, useExisting: AXMQuestionnaireViewerPageComponent }], viewQueries: [{ propertyName: "viewer", first: true, predicate: ["viewer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<!-- Page shell layout -->\n<axp-page-layout>\n <!-- Main content area -->\n <axp-page-content class=\"ax-flex ax-flex-col ax-flex-1 ax-min-h-0\"\n [class.ax-overflow-hidden]=\"flowStep() === 'questions'\" [class.ax-overflow-y-auto]=\"flowStep() !== 'questions'\">\n <!-- Loading state -->\n @if (isLoading()) {\n <div class=\"ax-flex ax-items-center ax-justify-center ax-min-h-[200px]\">\n <span>{{ '@assessment-management:questionnaires.components.questionnaire-viewer.loading.title' | translate | async\n }}</span>\n </div>\n }\n <!-- Error state -->\n @else if (loadError()) {\n <div class=\"ax-p-4 ax-text-error-600\">\n {{ loadError() }}\n </div>\n }\n <!-- Content state -->\n @else if (structure()) {\n <!-- Pre-questionnaire introduction content -->\n @if (flowStep() === 'pre') {\n <axm-pre-questionnaire-content [content]=\"prePostConfig()?.pre?.content\"></axm-pre-questionnaire-content>\n }\n <!-- Post-submit results content -->\n @else if (flowStep() === 'results') {\n <axm-post-questionnaire-content mode=\"results\"\n [placeholderValues]=\"submitResult()\"></axm-post-questionnaire-content>\n }\n <!-- Post-submit summary content -->\n @else if (flowStep() === 'summary') {\n <axm-post-questionnaire-content mode=\"summary\" [summaryContent]=\"prePostConfig()?.post?.summaryContent\"\n [placeholderValues]=\"submitResult()\"></axm-post-questionnaire-content>\n }\n <!-- Questionnaire and review flow -->\n @else {\n <!-- Review mode content -->\n @if (flowStep() === 'review') {\n <axm-post-questionnaire-content mode=\"review\" [questionsWithAnswers]=\"reviewSnapshot()\"\n [reviewContext]=\"reviewContext()\"></axm-post-questionnaire-content>\n }\n\n <!-- Questionnaire workspace (hidden while in review mode) -->\n <div class=\"__questions ax-flex ax-flex-col ax-flex-1 ax-min-h-0 ax-overflow-hidden\"\n [class.ax-invisible]=\"flowStep() === 'review'\" [style.position]=\"flowStep() === 'review' ? 'fixed' : null\"\n [style.left]=\"flowStep() === 'review' ? '-9999px' : null\" [class.ax-size-0]=\"flowStep() === 'review'\"\n [class.ax-overflow-hidden]=\"flowStep() === 'review'\">\n\n <!-- Questionnaire rendering container -->\n <div class=\"__content ax-flex ax-flex-col ax-flex-1 ax-min-h-0 ax-overflow-y-auto ax-overflow-x-hidden\">\n <axm-questionnaire-viewer #viewer [structure]=\"structure()!\" [config]=\"viewerConfig()\"\n [initialAnswers]=\"effectiveInitialAnswers()\"\n (answersChanged)=\"handleAnswersChanged($event)\"></axm-questionnaire-viewer>\n </div>\n </div>\n }\n }\n </axp-page-content>\n\n <!-- Footer actions (only when content is ready) -->\n @if (structure() && !isLoading() && !loadError()) {\n <axp-page-footer class=\"--animated\">\n <!-- Footer prefix: progress indicator -->\n <axp-layout-prefix>\n @if (flowStep() === 'questions') {\n <div class=\"__footer-progress ax-text-sm ax-font-mono ax-tabular-nums\" dir=\"ltr\">\n @if (showProgressBar()) {\n {{ answeredQuestionsCount() }} / {{ totalQuestionsCount() }}\n }\n </div>\n }\n <!-- @if (showTimer()) {\n <axp-stopwatch [mode]=\"timerTimeLimit() ? 'count-down' : 'count-up'\" [timeLimit]=\"timerTimeLimit()\"\n [format]=\"timerTimeLimit() && timerTimeLimit()! >= 3600 ? 'hh:mm:ss' : 'mm:ss'\" [autoStart]=\"true\"\n [showControls]=\"false\" [value]=\"timerElapsed()\"\n (valueChange)=\"viewerViewModel()!.updateTimerElapsed($event)\"></axp-stopwatch>\n } -->\n </axp-layout-prefix>\n\n <!-- Footer suffix: flow action buttons -->\n <axp-layout-suffix>\n @if (flowStep() === 'pre') {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.start' | translate | async\"\n (onClick)=\"flowStep.set('questions')\"></ax-button>\n }\n <!-- Question step actions -->\n @else if (flowStep() === 'questions') {\n <!-- Question navigation buttons -->\n @if (showNavigationButtons()) {\n <ax-button look=\"solid\" [disabled]=\"!canNavigatePrevious()\"\n [text]=\"'@general:actions.previous.title' | translate | async\" (onClick)=\"handlePreviousClick()\"></ax-button>\n @if (!isLastStep()) {\n <ax-button look=\"solid\" color=\"primary\" [disabled]=\"!canNavigateNext()\"\n [text]=\"'@general:actions.next.title' | translate | async\" (onClick)=\"handleNextClick()\"></ax-button>\n }\n }\n\n <!-- Final-step actions -->\n @if (isLastStep() && showReviewButton()) {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.review' | translate | async\"\n [disabled]=\"!areAllRequiredQuestionsAnswered()\" (onClick)=\"handleReviewClick()\"></ax-button>\n }\n @if (isLastStep() && !showReviewButton()) {\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.submit.title' | translate | async\"\n [disabled]=\"isReadonly() || isSubmitting() || !areAllRequiredQuestionsAnswered()\"\n (onClick)=\"handleSubmitClick()\"></ax-button>\n }\n }\n <!-- Review step actions -->\n @else if (flowStep() === 'review') {\n <ax-button look=\"outline\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.edit' | translate | async\"\n (onClick)=\"flowStep.set('questions')\"></ax-button>\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.submit.title' | translate | async\"\n [disabled]=\"isSubmitting()\" (onClick)=\"handleReviewSubmit()\"></ax-button>\n }\n <!-- Results step actions -->\n @else if (flowStep() === 'results') {\n @if (prePostConfig()?.post?.summaryEnabled) {\n <ax-button look=\"solid\" color=\"primary\" [text]=\"'@general:actions.next.title' | translate | async\"\n (onClick)=\"flowStep.set('summary')\"></ax-button>\n } @else {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.done' | translate | async\"\n (onClick)=\"handleDone()\"></ax-button>\n }\n }\n <!-- Summary step action -->\n @else if (flowStep() === 'summary') {\n <ax-button look=\"solid\" color=\"primary\"\n [text]=\"'@assessment-management:questionnaires.components.questionnaire-viewer.flow.done' | translate | async\"\n (onClick)=\"handleDone()\"></ax-button>\n }\n </axp-layout-suffix>\n </axp-page-footer>\n }\n</axp-page-layout>", styles: ["axm-questionnaire-viewer-page .__questions{min-height:0px;overflow:hidden}axm-questionnaire-viewer-page .__header{z-index:20;display:flex;flex-shrink:0;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));position:sticky;top:0;color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-page .__content axm-questionnaire-viewer{display:flex;height:auto;max-height:none;min-height:0px;width:100%;max-width:100%;flex:none;flex-direction:column}axm-questionnaire-viewer-page .__content axm-questionnaire-viewer .__questionnaire-container{min-height:0px;flex:none;overflow:visible}axm-questionnaire-viewer-page .__toolbar-meta{color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-page .__footer-progress{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: AXPPageLayoutComponent, selector: "axp-page-layout" }, { kind: "component", type: AXPThemeLayoutBlockComponent, selector: " axp-page-content, axp-page-footer-container, axp-page-footer, axp-page-header, axp-page-header-container, axp-page-toolbar, axp-layout-content, axp-layout-page-content, axp-layout-sections, axp-layout-body, axp-layout-page-body, axp-layout-prefix, axp-layout-suffix, axp-layout-title-bar, axp-layout-title, axp-layout-title-actions, axp-layout-nav-button, axp-layout-description, axp-layout-breadcrumbs, axp-layout-list-action, " }, { kind: "component", type:
|
|
5409
8633
|
//AXPStopwatchComponent,
|
|
5410
|
-
AXMQuestionnaireViewerComponent, selector: "axm-questionnaire-viewer", inputs: ["questionnaireId", "structure", "config", "initialAnswers"], outputs: ["answersChanged", "questionAnswered"] }, { kind: "component", type: AXMPreQuestionnaireContentComponent, selector: "axm-pre-questionnaire-content", inputs: ["content"] }, { kind: "component", type: AXMPostQuestionnaireContentComponent, selector: "axm-post-questionnaire-content", inputs: ["mode", "questionsWithAnswers", "reviewContext", "summaryContent", "placeholderValues", "locale", "showQuestionNumbers"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4
|
|
8634
|
+
AXMQuestionnaireViewerComponent, selector: "axm-questionnaire-viewer", inputs: ["questionnaireId", "structure", "config", "initialAnswers"], outputs: ["answersChanged", "questionAnswered"] }, { kind: "component", type: AXMPreQuestionnaireContentComponent, selector: "axm-pre-questionnaire-content", inputs: ["content"] }, { kind: "component", type: AXMPostQuestionnaireContentComponent, selector: "axm-post-questionnaire-content", inputs: ["mode", "questionsWithAnswers", "reviewContext", "summaryContent", "placeholderValues", "locale", "showQuestionNumbers"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
5411
8635
|
}
|
|
5412
8636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerPageComponent, decorators: [{
|
|
5413
8637
|
type: Component,
|
|
@@ -5450,6 +8674,8 @@ class AXMQuestionnaireViewerStandalonePageComponent {
|
|
|
5450
8674
|
this.isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
5451
8675
|
this.loadError = signal(null, ...(ngDevMode ? [{ debugName: "loadError" }] : /* istanbul ignore next */ []));
|
|
5452
8676
|
this.isSubmitting = signal(false, ...(ngDevMode ? [{ debugName: "isSubmitting" }] : /* istanbul ignore next */ []));
|
|
8677
|
+
this.sessionId = signal(null, ...(ngDevMode ? [{ debugName: "sessionId" }] : /* istanbul ignore next */ []));
|
|
8678
|
+
this.existingSession = signal(null, ...(ngDevMode ? [{ debugName: "existingSession" }] : /* istanbul ignore next */ []));
|
|
5453
8679
|
this.flowStep = signal('questions', ...(ngDevMode ? [{ debugName: "flowStep" }] : /* istanbul ignore next */ []));
|
|
5454
8680
|
this.reviewSnapshot = signal([], ...(ngDevMode ? [{ debugName: "reviewSnapshot" }] : /* istanbul ignore next */ []));
|
|
5455
8681
|
this.reviewContext = signal(null, ...(ngDevMode ? [{ debugName: "reviewContext" }] : /* istanbul ignore next */ []));
|
|
@@ -5517,6 +8743,8 @@ class AXMQuestionnaireViewerStandalonePageComponent {
|
|
|
5517
8743
|
this.isLoading.set(false);
|
|
5518
8744
|
return;
|
|
5519
8745
|
}
|
|
8746
|
+
this.sessionId.set(sessionId);
|
|
8747
|
+
this.existingSession.set(session);
|
|
5520
8748
|
const caseId = session.caseId;
|
|
5521
8749
|
const assessmentCase = await this.entityService
|
|
5522
8750
|
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentCase.name)
|
|
@@ -5558,28 +8786,41 @@ class AXMQuestionnaireViewerStandalonePageComponent {
|
|
|
5558
8786
|
//#endregion
|
|
5559
8787
|
//#region ---- Submit Handler ----
|
|
5560
8788
|
async saveSessionAndGetSummary(answers) {
|
|
5561
|
-
const
|
|
8789
|
+
const sessionIdVal = this.sessionId();
|
|
5562
8790
|
const structureVal = this.structure();
|
|
5563
8791
|
const q = this.questionnaire();
|
|
5564
|
-
|
|
8792
|
+
const session = this.existingSession();
|
|
8793
|
+
if (!sessionIdVal || !structureVal || !q || !session)
|
|
5565
8794
|
return null;
|
|
5566
|
-
const
|
|
5567
|
-
const
|
|
8795
|
+
const vm = this.viewerViewModel();
|
|
8796
|
+
const result = await persistAssessmentSession({
|
|
8797
|
+
entityService: this.entityService,
|
|
8798
|
+
questionnaireViewerService: this.questionnaireViewerService,
|
|
8799
|
+
caseId: session.caseId,
|
|
8800
|
+
sessionId: sessionIdVal,
|
|
8801
|
+
existingSession: session,
|
|
8802
|
+
responderId: session.responderId,
|
|
8803
|
+
role: session.role,
|
|
8804
|
+
structure: structureVal,
|
|
8805
|
+
questionnaireId: q.id,
|
|
8806
|
+
answers,
|
|
8807
|
+
finalize: true,
|
|
8808
|
+
progressMetrics: vm
|
|
8809
|
+
? {
|
|
8810
|
+
answeredQuestionsCount: vm.answeredQuestionsCount(),
|
|
8811
|
+
progressPercentage: vm.progressPercentage(),
|
|
8812
|
+
}
|
|
8813
|
+
: undefined,
|
|
8814
|
+
timeSpentSeconds: vm?.timerElapsed(),
|
|
8815
|
+
});
|
|
8816
|
+
const updated = await this.entityService
|
|
5568
8817
|
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
5569
8818
|
.data()
|
|
5570
|
-
.byKey(sessionId);
|
|
5571
|
-
if (
|
|
5572
|
-
|
|
5573
|
-
.withEntity(RootConfig.module.name, RootConfig.entities.assessmentSession.name)
|
|
5574
|
-
.data()
|
|
5575
|
-
.update(sessionId, {
|
|
5576
|
-
answers,
|
|
5577
|
-
progressPercentage,
|
|
5578
|
-
answeredQuestionsCount,
|
|
5579
|
-
lastSavedAt: new Date(),
|
|
5580
|
-
});
|
|
8819
|
+
.byKey(result.sessionId);
|
|
8820
|
+
if (updated) {
|
|
8821
|
+
this.existingSession.set(updated);
|
|
5581
8822
|
}
|
|
5582
|
-
const elapsed =
|
|
8823
|
+
const elapsed = vm?.timerElapsed() ?? 0;
|
|
5583
8824
|
return this.questionnaireViewerService.buildSummaryPlaceholderValues(structureVal, answers, {
|
|
5584
8825
|
questionnaireId: q.id,
|
|
5585
8826
|
elapsedSeconds: elapsed,
|
|
@@ -5594,7 +8835,7 @@ class AXMQuestionnaireViewerStandalonePageComponent {
|
|
|
5594
8835
|
this.handleDone();
|
|
5595
8836
|
return;
|
|
5596
8837
|
}
|
|
5597
|
-
if (cfg?.post.
|
|
8838
|
+
if (cfg?.post.showOutcomeResults === true) {
|
|
5598
8839
|
this.flowStep.set('results');
|
|
5599
8840
|
return;
|
|
5600
8841
|
}
|
|
@@ -5783,7 +9024,7 @@ class AXMQuestionnaireViewerStandalonePageComponent {
|
|
|
5783
9024
|
</ax-footer>
|
|
5784
9025
|
}
|
|
5785
9026
|
</div>
|
|
5786
|
-
`, isInline: true, styles: ["axm-questionnaire-viewer-standalone-page{display:flex;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column;overflow:hidden}axm-questionnaire-viewer-standalone-page .__body{display:flex;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column;overflow:hidden}axm-questionnaire-viewer-standalone-page .__content-area{min-height:0px;overflow:hidden}axm-questionnaire-viewer-standalone-page .__questions{min-height:0px;overflow:hidden}axm-questionnaire-viewer-standalone-page .__header{z-index:20;display:flex;flex-shrink:0;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));color:rgb(var(--ax-sys-color-on-surface-variant));position:sticky;top:0}axm-questionnaire-viewer-standalone-page .__header .__header-top{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.75rem 1rem}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta{display:flex;align-items:center;gap:1rem;font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item{display:flex;align-items:center;gap:.375rem}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item i{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-600),var(--tw-text-opacity, 1))}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item span{font-weight:500}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-timer{display:flex;flex-shrink:0;align-items:center}axm-questionnaire-viewer-standalone-page .__content-wrapper{display:flex;min-height:0px;flex:1 1 0%;overflow:hidden}axm-questionnaire-viewer-standalone-page .__content axm-questionnaire-viewer{display:flex;height:auto;max-height:none;min-height:0px;width:100%;max-width:100%;flex:none;flex-direction:column}axm-questionnaire-viewer-standalone-page .__content axm-questionnaire-viewer .__questionnaire-container{min-height:0px;flex:none;overflow:visible}axm-questionnaire-viewer-standalone-page .__toolbar-meta{color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-standalone-page .__footer-progress{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1
|
|
9027
|
+
`, isInline: true, styles: ["axm-questionnaire-viewer-standalone-page{display:flex;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column;overflow:hidden}axm-questionnaire-viewer-standalone-page .__body{display:flex;min-height:0px;width:100%;flex:1 1 0%;flex-direction:column;overflow:hidden}axm-questionnaire-viewer-standalone-page .__content-area{min-height:0px;overflow:hidden}axm-questionnaire-viewer-standalone-page .__questions{min-height:0px;overflow:hidden}axm-questionnaire-viewer-standalone-page .__header{z-index:20;display:flex;flex-shrink:0;flex-direction:column;background-color:rgb(var(--ax-sys-color-lightest-surface));color:rgb(var(--ax-sys-color-on-lightest-surface));border-color:rgb(var(--ax-sys-color-border-lightest-surface));border-bottom-width:1px;--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-border-surface),var(--tw-border-opacity, 1));color:rgb(var(--ax-sys-color-on-surface-variant));position:sticky;top:0}axm-questionnaire-viewer-standalone-page .__header .__header-top{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.75rem 1rem}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta{display:flex;align-items:center;gap:1rem;font-size:.75rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity, 1))}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item{display:flex;align-items:center;gap:.375rem}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item i{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgba(var(--ax-sys-color-primary-600),var(--tw-text-opacity, 1))}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-meta .__meta-item span{font-weight:500}axm-questionnaire-viewer-standalone-page .__header .__header-top .__header-timer{display:flex;flex-shrink:0;align-items:center}axm-questionnaire-viewer-standalone-page .__content-wrapper{display:flex;min-height:0px;flex:1 1 0%;overflow:hidden}axm-questionnaire-viewer-standalone-page .__content axm-questionnaire-viewer{display:flex;height:auto;max-height:none;min-height:0px;width:100%;max-width:100%;flex:none;flex-direction:column}axm-questionnaire-viewer-standalone-page .__content axm-questionnaire-viewer .__questionnaire-container{min-height:0px;flex:none;overflow:visible}axm-questionnaire-viewer-standalone-page .__toolbar-meta{color:rgb(var(--ax-sys-color-on-surface-variant))}axm-questionnaire-viewer-standalone-page .__footer-progress{color:rgb(var(--ax-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: AXPStopwatchComponent, selector: "axp-stopwatch", inputs: ["mode", "timeLimit", "format", "autoStart", "showControls", "value"], outputs: ["valueChange", "timeUp"] }, { kind: "component", type: AXMQuestionnaireViewerComponent, selector: "axm-questionnaire-viewer", inputs: ["questionnaireId", "structure", "config", "initialAnswers"], outputs: ["answersChanged", "questionAnswered"] }, { kind: "component", type: AXMPreQuestionnaireContentComponent, selector: "axm-pre-questionnaire-content", inputs: ["content"] }, { kind: "component", type: AXMPostQuestionnaireContentComponent, selector: "axm-post-questionnaire-content", inputs: ["mode", "questionsWithAnswers", "reviewContext", "summaryContent", "placeholderValues", "locale", "showQuestionNumbers"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
5787
9028
|
}
|
|
5788
9029
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXMQuestionnaireViewerStandalonePageComponent, decorators: [{
|
|
5789
9030
|
type: Component,
|
|
@@ -5920,5 +9161,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
5920
9161
|
* Generated bundle index. Do not edit.
|
|
5921
9162
|
*/
|
|
5922
9163
|
|
|
5923
|
-
export { AXMQuestionnaireViewerService as A,
|
|
5924
|
-
//# sourceMappingURL=acorex-modules-assessment-management-acorex-modules-assessment-management-
|
|
9164
|
+
export { AXMQuestionnaireViewerService as A, DEFAULT_QUESTION_HINT_CONFIG as B, diffQuestionCommentOverride as C, DEFAULT_POST_QUESTIONNAIRE_CONFIG as D, diffQuestionHintOverride as E, findDuplicateOutcomeNames as F, flattenQuestionnaireOutcomeItems as G, getQuestionAnswerCommentStoragePath as H, isQuestionnaireOutcomeDisplayColorHex as I, matchesQuestionnaireOutcomeDisplayRule as J, mergeQuestionCommentConfig as K, mergeQuestionHintForViewer as L, normalizeQuestionCommentConfig as M, normalizeQuestionHintConfig as N, normalizeQuestionHintFromEntityRow as O, normalizeQuestionHintMode as P, QUESTIONNAIRE_QUESTIONS_PAGE_COMPONENT_KEY as Q, RootConfig as R, normalizeQuestionnaireOutcomeDisplayRules as S, normalizeQuestionnaireOutcomesValue as T, normalizeValidationStrategy$1 as U, normalizeViewMode as V, parseQuestionHintPartialFromRecord as W, parseQuestionnaireOutcomeDisplayColor as X, readHintFieldsFromRecord as Y, QUESTIONNAIRE_OUTCOMES_PAGE_COMPONENT_KEY as a, AXMQuestionnaireViewerComponent as b, AXMPreQuestionnaireContentComponent as c, AXMPostQuestionnaireContentComponent as d, toDisplaySettings as e, AXMAssessmentManagementEntityProvider as f, AXMAssessmentManagementFeatureDefinitionProvider as g, AXMAssessmentManagementFeatureKeys as h, AXMAssessmentManagementMenuProvider as i, AXMAssessmentManagementModule as j, AXMAssessmentManagementPermissionDefinitionProvider as k, AXMAssessmentManagementPermissionKeys as l, mapToOutcomeResultsViewModel as m, normalizeCompletionMode as n, AXMAssessmentManagementSearchCommandProvider as o, persistAssessmentSession as p, AXMQuestionnaireViewerPageComponent as q, resolveWidgetNodeFromMetaDataDefinitionInterface as r, stripQuestionBankInterfaceMetadata as s, toPrePostConfig as t, AXMQuestionnaireViewerStandalonePageComponent as u, AXPAssessmentManagementMenuKeys as v, DEFAULT_PRE_QUESTIONNAIRE_CONFIG as w, DEFAULT_QUESTIONNAIRE_ENTITY_DISPLAY as x, DEFAULT_QUESTIONNAIRE_OUTCOMES as y, DEFAULT_QUESTION_COMMENT_CONFIG as z };
|
|
9165
|
+
//# sourceMappingURL=acorex-modules-assessment-management-acorex-modules-assessment-management-DlhSQ0cB.mjs.map
|