@acorex-platform/module-workplacesafety-management-client 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/fesm2022/acorex-platform-module-workplacesafety-management-client-acorex-platform-module-workplacesafety-management-client-isnVDChu.mjs +549 -0
  2. package/fesm2022/acorex-platform-module-workplacesafety-management-client-acorex-platform-module-workplacesafety-management-client-isnVDChu.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-workplacesafety-management-client-contracts.mjs +739 -806
  4. package/fesm2022/acorex-platform-module-workplacesafety-management-client-contracts.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram-widget-view.component-CZFCMX6R.mjs +93 -0
  6. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram-widget-view.component-CZFCMX6R.mjs.map +1 -0
  7. package/fesm2022/{acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram-widget-view.component-C-qrrqOV.mjs → acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.component-D7hofHR0.mjs} +8 -93
  8. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.component-D7hofHR0.mjs.map +1 -0
  9. package/fesm2022/{acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.service-BBhH7KP1.mjs → acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.service-tMrUDnCb.mjs} +48 -1
  10. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.service-tMrUDnCb.mjs.map +1 -0
  11. package/fesm2022/{acorex-platform-module-workplacesafety-management-client-index-kF37zgd4.mjs → acorex-platform-module-workplacesafety-management-client-index-yxxC7i6A.mjs} +391 -92
  12. package/fesm2022/acorex-platform-module-workplacesafety-management-client-index-yxxC7i6A.mjs.map +1 -0
  13. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer-widget-column.component-D2Mmow12.mjs +42 -0
  14. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer-widget-column.component-D2Mmow12.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer-widget-edit.component-CQtVhCgw.mjs +101 -0
  16. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer-widget-edit.component-CQtVhCgw.mjs.map +1 -0
  17. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer.service-YS8FHiRu.mjs +221 -0
  18. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer.service-YS8FHiRu.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer.util-2Kl3_3sg.mjs +61 -0
  20. package/fesm2022/acorex-platform-module-workplacesafety-management-client-ppe-item-viewer.util-2Kl3_3sg.mjs.map +1 -0
  21. package/fesm2022/{acorex-platform-module-workplacesafety-management-client-preview-control-hierarchy-diagram.command-C2X3VpEt.mjs → acorex-platform-module-workplacesafety-management-client-preview-control-hierarchy-diagram.command-Dd9xdo_y.mjs} +3 -7
  22. package/fesm2022/acorex-platform-module-workplacesafety-management-client-preview-control-hierarchy-diagram.command-Dd9xdo_y.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-module-workplacesafety-management-client-safety-plan-preview-modal.component-C7IojUT9.mjs +557 -0
  24. package/fesm2022/acorex-platform-module-workplacesafety-management-client-safety-plan-preview-modal.component-C7IojUT9.mjs.map +1 -0
  25. package/fesm2022/{acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BJsg3pHZ.mjs → acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BlPzzCc2.mjs} +13 -25
  26. package/fesm2022/acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BlPzzCc2.mjs.map +1 -0
  27. package/fesm2022/acorex-platform-module-workplacesafety-management-client.mjs +1 -460
  28. package/fesm2022/acorex-platform-module-workplacesafety-management-client.mjs.map +1 -1
  29. package/package.json +2 -2
  30. package/types/acorex-platform-module-workplacesafety-management-client-contracts.d.ts +89 -140
  31. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram-widget-view.component-C-qrrqOV.mjs.map +0 -1
  32. package/fesm2022/acorex-platform-module-workplacesafety-management-client-control-hierarchy-diagram.service-BBhH7KP1.mjs.map +0 -1
  33. package/fesm2022/acorex-platform-module-workplacesafety-management-client-hazard-risk-ppe-rule-status.provider-DtqzcWh0.mjs +0 -42
  34. package/fesm2022/acorex-platform-module-workplacesafety-management-client-hazard-risk-ppe-rule-status.provider-DtqzcWh0.mjs.map +0 -1
  35. package/fesm2022/acorex-platform-module-workplacesafety-management-client-index-kF37zgd4.mjs.map +0 -1
  36. package/fesm2022/acorex-platform-module-workplacesafety-management-client-preview-control-hierarchy-diagram.command-C2X3VpEt.mjs.map +0 -1
  37. package/fesm2022/acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BJsg3pHZ.mjs.map +0 -1
@@ -1,12 +1,13 @@
1
- import { AXPWidgetsCatalog, AXPSystemStatusType } from '@acorex-platform/framework-shared/core';
2
- import { AXPDataGenerator, AXPHookService } from '@acorex-platform/framework-client/core';
1
+ import { AXPWidgetsList, AXPWidgetsCatalog, AXPSystemStatusType } from '@acorex-platform/framework-shared/core';
2
+ import { resolveEntityRowDisplayText } from '@acorex-platform/framework-client/common';
3
+ import { AXPDataGenerator, AXPDeviceService, AXPHookService } from '@acorex-platform/framework-client/core';
3
4
  import { AXPEntityDataSelectorService, AXPEntityDefinitionRegistryService, AXPEntityService } from '@acorex-platform/framework-client/layout/entity';
4
5
  import { AXPCommandService, AXPRuntimeRemoteHookKeys } from '@acorex-platform/framework-client/runtime';
5
6
  import { AXPLayoutBuilderService, resolveLayoutBuilderDialogResult } from '@acorex-platform/framework-client/layout/builder';
6
7
  import { AXPPageLayoutBaseComponent, AXPPageLayoutBase } from '@acorex-platform/framework-client/layout/views';
7
- import { clearDependentItemsOnParentChange, enrichSectionTypeSnapshot, isStepTableSectionType, safetyPlanSectionTypeAlreadyExists, SAFETY_PLAN_SECTION_DUPLICATE_SECTION_TYPE_MESSAGE_KEY, collectBuiltInRepeatableSectionTypeIds, RootConfig, WORKPLACE_SAFETY_SECTION_TYPE_LOOKUP_WIDGET_OPTIONS, normalizeStepTableColumns, resolveSafetyPlanSectionItemFilterAsync, resolveSafetyPlanSectionItemEntityKey, resolveSafetyPlanSectionItemColumns, mapSafetyPlanSectionSelectedItems, dedupeSafetyPlanSectionItemSelection, sortStepTableColumns, stepTableColumnKey, resolveStepTableColumnLookupEntity, isStepTableColumnMultiLookup, stepTableColumnTitle, normalizeStepTableRows, resolveEntityRefId, AXMWorkplaceSafetyManagementCommandKeys, dedupeSafetyPlanSectionStructure, buildSectionStructureFromTypeSections, toBuilderValueFromStructure, SAFETY_PLAN_SECTIONS_PAGE_COMPONENT_KEY } from '@acorex-platform/module-workplacesafety-management-client/contracts';
8
+ import { resolveSectionTypeKey, asSafetyPlanDisplayText, resolveEntityRefId, clearDependentItemsOnParentChange, enrichSectionTypeSnapshot, isStepTableSectionType, WORKPLACE_SAFETY_SECTION_TYPE_LOOKUP_WIDGET_OPTIONS, RootConfig, normalizeStepTableColumns, resolveSafetyPlanSectionItemFilterAsync, resolveSafetyPlanSectionItemEntityKey, resolveSafetyPlanSectionItemColumns, mapSafetyPlanSectionSelectedItems, dedupeSafetyPlanSectionItemSelection, sortStepTableColumns, stepTableColumnKey, resolveStepTableColumnLookupEntity, isStepTableColumnMultiLookup, stepTableColumnTitle, normalizeStepTableRows, AXMWorkplaceSafetyManagementCommandKeys, dedupeSafetyPlanSectionStructure, resolveSectionItemEntityName, collectBuiltInRepeatableSectionTypeIds, buildSectionStructureFromTypeSections, toBuilderValueFromStructure, SAFETY_PLAN_SECTIONS_PAGE_COMPONENT_KEY } from '@acorex-platform/module-workplacesafety-management-client/contracts';
8
9
  import * as i0 from '@angular/core';
9
- import { input, output, viewChild, inject, signal, computed, effect, ChangeDetectionStrategy, Component, untracked, Injectable } from '@angular/core';
10
+ import { inject, Injectable, input, output, viewChild, signal, computed, effect, ChangeDetectionStrategy, Component, untracked } from '@angular/core';
10
11
  import { isEqual, cloneDeep } from 'lodash';
11
12
  import { AXDialogService } from '@acorex/components/dialog';
12
13
  import * as i1 from '@acorex/components/button';
@@ -14,13 +15,215 @@ import { AXButtonModule } from '@acorex/components/button';
14
15
  import * as i2 from '@acorex/components/decorators';
15
16
  import { AXDecoratorModule } from '@acorex/components/decorators';
16
17
  import { AXToastService } from '@acorex/components/toast';
17
- import * as i3$1 from '@acorex/core/translation';
18
+ import * as i1$1 from '@acorex/core/translation';
18
19
  import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
19
- import { AXPStandardSectionItemsBuilderComponent } from '@acorex-platform/framework-client/layout/components';
20
+ import { AXPWidgetPropertyViewerService, AXPStandardSectionItemsBuilderComponent } from '@acorex-platform/framework-client/layout/components';
20
21
  import * as i3 from '@angular/common';
21
22
  import { CommonModule, AsyncPipe } from '@angular/common';
22
- import { n as normalizeSafetyPlanSectionBuilderValue, s as summarizeStepTableRow, S as SAFETY_PLAN_SECTIONS_SAVE_COMMAND, a as safetyPlanSectionsToBuilderValue, h as hydrateStepTableSectionsWithWorkSteps } from './acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BJsg3pHZ.mjs';
23
- export { A as AXMSaveSafetyPlanSectionsCommand } from './acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BJsg3pHZ.mjs';
23
+ import { n as normalizeSafetyPlanSectionBuilderValue, s as summarizeStepTableRow, S as SAFETY_PLAN_SECTIONS_SAVE_COMMAND, a as safetyPlanSectionsToBuilderValue, h as hydrateStepTableSectionsWithWorkSteps } from './acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BlPzzCc2.mjs';
24
+ export { A as AXMSaveSafetyPlanSectionsCommand } from './acorex-platform-module-workplacesafety-management-client-save-safety-plan-sections.command-BlPzzCc2.mjs';
25
+ import { P as PPE_ITEM_VIEWER_WIDGET_NAME } from './acorex-platform-module-workplacesafety-management-client-acorex-platform-module-workplacesafety-management-client-isnVDChu.mjs';
26
+ import { AXP_BEHAVIOR_PROPERTY_GROUP } from '@acorex-platform/framework-client/layout/widgets';
27
+ import { createBooleanProperty } from '@acorex-platform/framework-shared/widget-core';
28
+ import { AXPopupService } from '@acorex/components/popup';
29
+
30
+ //#region ----- Imports -----
31
+ //#endregion
32
+ //#region ----- Constants -----
33
+ const SAFETY_PLAN_PPE_WIDGET_PROPERTY_EXCLUDE = [
34
+ 'name',
35
+ 'path',
36
+ 'ppeItems',
37
+ 'readonly',
38
+ 'disabled',
39
+ 'triggers',
40
+ 'requiredValidation',
41
+ ];
42
+ const SAFETY_PLAN_HIERARCHY_WIDGET_PROPERTY_EXCLUDE = ['name', 'path'];
43
+ const PPE_OPTION_KEYS = ['layout'];
44
+ const HIERARCHY_OPTION_KEYS = ['viewType', 'showTitle', 'showViewTypeSelector'];
45
+ //#endregion
46
+ //#region ----- Resolve -----
47
+ function resolveSafetyPlanSectionConfigurableWidgetType(sectionTypeId, snapshot, sectionTitle, sectionDescription) {
48
+ const resolvedKeys = [
49
+ resolveSectionTypeKey(sectionTypeId, snapshot),
50
+ resolveSectionTypeKeyFromCode(snapshot?.code),
51
+ resolveSectionTypeKeyFromTitle(sectionTitle),
52
+ resolveSectionTypeKeyFromTitle(snapshot?.title),
53
+ resolveSectionTypeKeyFromDescription(sectionDescription),
54
+ resolveSectionTypeKeyFromDescription(snapshot?.description),
55
+ ];
56
+ if (resolvedKeys.includes('Ppe')) {
57
+ return PPE_ITEM_VIEWER_WIDGET_NAME;
58
+ }
59
+ if (resolvedKeys.includes('HierarchyLevel')) {
60
+ return AXPWidgetsList.Editors.ControlHierarchyDiagram;
61
+ }
62
+ return null;
63
+ }
64
+ function resolveSectionTypeKeyFromCode(code) {
65
+ const compact = asSafetyPlanDisplayText(code).replace(/\s+/g, '').toLowerCase();
66
+ if (!compact) {
67
+ return undefined;
68
+ }
69
+ if (compact === 'hierarchylevel' || compact === 'hierarchy') {
70
+ return 'HierarchyLevel';
71
+ }
72
+ if (compact === 'ppe') {
73
+ return 'Ppe';
74
+ }
75
+ return undefined;
76
+ }
77
+ function resolveSectionTypeKeyFromTitle(title) {
78
+ const compact = asSafetyPlanDisplayText(title).replace(/\s+/g, '').toLowerCase();
79
+ if (!compact) {
80
+ return undefined;
81
+ }
82
+ if (compact === 'hierarchylevel' || compact.includes('hierarchy')) {
83
+ return 'HierarchyLevel';
84
+ }
85
+ if (compact === 'ppe' || compact === 'ppeitem' || compact === 'ppeitems') {
86
+ return 'Ppe';
87
+ }
88
+ return undefined;
89
+ }
90
+ function resolveSectionTypeKeyFromDescription(description) {
91
+ const text = asSafetyPlanDisplayText(description).toLowerCase();
92
+ if (!text) {
93
+ return undefined;
94
+ }
95
+ if (text.includes('control hierarchy')) {
96
+ return 'HierarchyLevel';
97
+ }
98
+ if (text.includes('personal protective equipment')) {
99
+ return 'Ppe';
100
+ }
101
+ return undefined;
102
+ }
103
+ function readBuilderSectionTypeId(section) {
104
+ return resolveEntityRefId(section['sectionTypeId']) ?? resolveEntityRefId(section['sectionType']) ?? undefined;
105
+ }
106
+ function resolveConfigurableWidgetTypeForSection(section) {
107
+ return resolveSafetyPlanSectionConfigurableWidgetType(readBuilderSectionTypeId(section), section['sectionType'], section['title'], section['description']);
108
+ }
109
+ function canConfigureSafetyPlanSectionWidget(section) {
110
+ return resolveConfigurableWidgetTypeForSection(section) != null;
111
+ }
112
+ function widgetTitleKeyForConfigurableType(widgetType) {
113
+ if (widgetType === PPE_ITEM_VIEWER_WIDGET_NAME) {
114
+ return '@workplacesafety-management:ppe-items.components.ppe-item-viewer.widget-title';
115
+ }
116
+ return '@workplacesafety-management:control-measure-types.components.control-hierarchy-diagram.widget-title';
117
+ }
118
+ //#endregion
119
+ //#region ----- Options -----
120
+ function readSectionWidgetOptions(section) {
121
+ const raw = section['widgetOptions'];
122
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
123
+ return {};
124
+ }
125
+ return { ...raw };
126
+ }
127
+ function pickSavedWidgetOptions(widgetType, existing, incoming) {
128
+ const merged = { ...existing, ...incoming };
129
+ const keys = widgetType === PPE_ITEM_VIEWER_WIDGET_NAME ? PPE_OPTION_KEYS : HIERARCHY_OPTION_KEYS;
130
+ const next = {};
131
+ for (const key of keys) {
132
+ const value = merged[key];
133
+ if (value !== undefined && value !== null) {
134
+ next[key] = value;
135
+ }
136
+ }
137
+ return next;
138
+ }
139
+ function buildSafetyPlanSectionWidgetNode(widgetType, options) {
140
+ return {
141
+ type: widgetType,
142
+ options: { ...options },
143
+ };
144
+ }
145
+ function hierarchyWidgetCustomProperties() {
146
+ return [
147
+ {
148
+ property: createBooleanProperty({
149
+ name: 'showTitle',
150
+ title: '@workplacesafety-management:control-measure-types.components.control-hierarchy-diagram.fields.show-title.title',
151
+ path: 'options.showTitle',
152
+ group: AXP_BEHAVIOR_PROPERTY_GROUP,
153
+ defaultValue: false,
154
+ }),
155
+ },
156
+ {
157
+ property: createBooleanProperty({
158
+ name: 'showViewTypeSelector',
159
+ title: '@workplacesafety-management:control-measure-types.components.control-hierarchy-diagram.fields.show-view-type-selector.title',
160
+ path: 'options.showViewTypeSelector',
161
+ group: AXP_BEHAVIOR_PROPERTY_GROUP,
162
+ defaultValue: true,
163
+ }),
164
+ },
165
+ ];
166
+ }
167
+ //#endregion
168
+
169
+ //#region ----- Imports -----
170
+ //#endregion
171
+ //#region ----- Service -----
172
+ class AXMSafetyPlanSectionWidgetOptionsService {
173
+ constructor() {
174
+ //#region ----- Services & Dependencies -----
175
+ this.widgetPropertyViewer = inject(AXPWidgetPropertyViewerService);
176
+ this.translationService = inject(AXTranslationService);
177
+ }
178
+ //#endregion
179
+ //#region ----- Public API -----
180
+ canConfigure(section) {
181
+ return canConfigureSafetyPlanSectionWidget(section);
182
+ }
183
+ async prompt(section, _value) {
184
+ const widgetType = resolveConfigurableWidgetTypeForSection(section);
185
+ if (!widgetType) {
186
+ return null;
187
+ }
188
+ const existing = readSectionWidgetOptions(section);
189
+ const title = (await this.translationService.translateAsync(widgetTitleKeyForConfigurableType(widgetType))) ||
190
+ (await this.translationService.translateAsync('@general:actions.edit.title')) ||
191
+ 'Edit';
192
+ const result = await this.widgetPropertyViewer
193
+ .create()
194
+ .dialog((dialog) => {
195
+ dialog
196
+ .setTitle(title)
197
+ .setMode('simple')
198
+ .setWidget(buildSafetyPlanSectionWidgetNode(widgetType, existing))
199
+ .setExclude([...this.excludeFor(widgetType)]);
200
+ if (widgetType !== PPE_ITEM_VIEWER_WIDGET_NAME) {
201
+ dialog.setCustom({ properties: hierarchyWidgetCustomProperties() });
202
+ }
203
+ })
204
+ .show();
205
+ if (!result?.values) {
206
+ return null;
207
+ }
208
+ const incoming = result.values.options ?? {};
209
+ return {
210
+ widgetOptions: pickSavedWidgetOptions(widgetType, existing, incoming),
211
+ };
212
+ }
213
+ //#endregion
214
+ //#region ----- Helpers -----
215
+ excludeFor(widgetType) {
216
+ return widgetType === PPE_ITEM_VIEWER_WIDGET_NAME
217
+ ? SAFETY_PLAN_PPE_WIDGET_PROPERTY_EXCLUDE
218
+ : SAFETY_PLAN_HIERARCHY_WIDGET_PROPERTY_EXCLUDE;
219
+ }
220
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionWidgetOptionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
221
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionWidgetOptionsService, providedIn: 'root' }); }
222
+ }
223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionWidgetOptionsService, decorators: [{
224
+ type: Injectable,
225
+ args: [{ providedIn: 'root' }]
226
+ }] });
24
227
 
25
228
  //#endregion
26
229
  //#region ----- Component -----
@@ -44,19 +247,17 @@ class AXMSafetyPlanSectionBuilderComponent {
44
247
  this.entityDataSelector = inject(AXPEntityDataSelectorService);
45
248
  this.entityRegistry = inject(AXPEntityDefinitionRegistryService);
46
249
  this.entityService = inject(AXPEntityService);
250
+ this.widgetOptionsService = inject(AXMSafetyPlanSectionWidgetOptionsService);
47
251
  //#endregion
48
252
  //#region ----- State Signals -----
49
253
  this.builderValue = signal({ sections: [] }, /* @ts-ignore */
50
254
  ...(ngDevMode ? [{ debugName: "builderValue" }] : /* istanbul ignore next */ []));
51
255
  /** Applied on the next builder commit so section header title survives item add/edit. */
52
256
  this.pendingSectionTitles = new Map();
53
- this.disabledSectionPrompt = false;
54
257
  this.standardConfig = computed(() => ({
55
258
  mapItemToView: (item) => this.mapItemToView(item),
56
259
  promptAddSection: this.allowAddSection() ? (value) => this.promptAddSection(value) : async () => null,
57
- promptEditSection: this.allowEditSection()
58
- ? (section, value) => this.promptEditSection(section, value)
59
- : this.disabledSectionPrompt,
260
+ promptEditSection: (section, value) => this.promptSectionHeaderEdit(section, value),
60
261
  promptAddItems: this.allowAddItems() ? (sectionId, value) => this.promptAddItems(sectionId, value) : undefined,
61
262
  promptEditItem: (item, sectionId, value) => this.promptEditItem(item, sectionId, value),
62
263
  showSectionTechnicalName: false,
@@ -139,11 +340,6 @@ class AXMSafetyPlanSectionBuilderComponent {
139
340
  });
140
341
  if (!dialogValue)
141
342
  return null;
142
- if (await this.blockIfSectionTypeExists(value, dialogValue.sectionTypeId, {
143
- sectionType: dialogValue.sectionType,
144
- })) {
145
- return null;
146
- }
147
343
  const sectionId = AXPDataGenerator.uuid();
148
344
  return {
149
345
  id: sectionId,
@@ -157,6 +353,15 @@ class AXMSafetyPlanSectionBuilderComponent {
157
353
  items: [],
158
354
  };
159
355
  }
356
+ async promptSectionHeaderEdit(section, value) {
357
+ if (this.widgetOptionsService.canConfigure(section)) {
358
+ return this.widgetOptionsService.prompt(section, value);
359
+ }
360
+ if (!this.allowEditSection()) {
361
+ return null;
362
+ }
363
+ return this.promptEditSection(section, value);
364
+ }
160
365
  async promptEditSection(section, value) {
161
366
  const previousSectionTypeId = String(section['sectionTypeId'] ?? '');
162
367
  const sectionTypeSnapshot = section['sectionType'];
@@ -170,12 +375,6 @@ class AXMSafetyPlanSectionBuilderComponent {
170
375
  });
171
376
  if (!dialogValue)
172
377
  return null;
173
- if (await this.blockIfSectionTypeExists(value, dialogValue.sectionTypeId, {
174
- excludeSectionId: String(section.id ?? ''),
175
- sectionType: dialogValue.sectionType,
176
- })) {
177
- return null;
178
- }
179
378
  const sectionTypeChanged = previousSectionTypeId !== dialogValue.sectionTypeId;
180
379
  const isStepTable = isStepTableSectionType(dialogValue.sectionTypeId, dialogValue.sectionType);
181
380
  const keepWorkStep = isStepTable && !sectionTypeChanged
@@ -199,48 +398,6 @@ class AXMSafetyPlanSectionBuilderComponent {
199
398
  ...(sectionTypeChanged ? { items: [] } : {}),
200
399
  };
201
400
  }
202
- async blockIfSectionTypeExists(value, sectionTypeId, options) {
203
- const repeatableSectionTypeIds = await this.loadRepeatableSectionTypeIds();
204
- const sections = value.sections.map((section) => ({
205
- id: String(section.id ?? ''),
206
- sectionTypeId: section['sectionTypeId'],
207
- sectionType: section['sectionType'],
208
- }));
209
- if (!safetyPlanSectionTypeAlreadyExists(sections, sectionTypeId, {
210
- ...options,
211
- repeatableSectionTypeIds,
212
- sectionType: options?.sectionType,
213
- })) {
214
- return false;
215
- }
216
- this.toastService.show({
217
- color: 'danger',
218
- title: await this.translationService.translateAsync('@general:messages.generic.error.title'),
219
- content: await this.translationService.translateAsync(SAFETY_PLAN_SECTION_DUPLICATE_SECTION_TYPE_MESSAGE_KEY),
220
- });
221
- return true;
222
- }
223
- async loadRepeatableSectionTypeIds() {
224
- const builtIn = collectBuiltInRepeatableSectionTypeIds();
225
- try {
226
- const entityKey = `${RootConfig.module.name}.${RootConfig.entities.sectionType.name}`;
227
- const result = await this.entityService.withEntity(entityKey).data().query({
228
- skip: 0,
229
- take: 1000,
230
- });
231
- const fromQuery = (result.items ?? [])
232
- .filter((row) => row.isRepeatable === true)
233
- .map((row) => {
234
- const id = row.id;
235
- return typeof id === 'string' ? id.trim() : '';
236
- })
237
- .filter(Boolean);
238
- return [...new Set([...fromQuery, ...builtIn])];
239
- }
240
- catch {
241
- return builtIn;
242
- }
243
- }
244
401
  async promptSectionForm(mode, seed) {
245
402
  const titleKey = mode === 'create'
246
403
  ? '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.add-section.title'
@@ -655,8 +812,8 @@ class AXMSafetyPlanSectionBuilderComponent {
655
812
  const snapshot = Array.isArray(item['items'])
656
813
  ? item['items'][0]
657
814
  : undefined;
658
- const title = String(item['title'] ?? snapshot?.title ?? '').trim();
659
- const code = String(item['name'] ?? snapshot?.code ?? '').trim();
815
+ const title = asSafetyPlanDisplayText(item['title']) || asSafetyPlanDisplayText(snapshot?.title);
816
+ const code = asSafetyPlanDisplayText(item['name']) || asSafetyPlanDisplayText(snapshot?.code);
660
817
  return {
661
818
  icon: 'fa-light fa-list-check',
662
819
  title,
@@ -682,6 +839,7 @@ class AXMSafetyPlanSectionBuilderComponent {
682
839
  workStepTypeId: section.workStepTypeId,
683
840
  workStepType: section.workStepType,
684
841
  columns: normalizeStepTableColumns(section.columns),
842
+ widgetOptions: section.widgetOptions,
685
843
  items: this.expandSectionItemsToBuilderRows(section.id, section.items, section),
686
844
  })),
687
845
  };
@@ -704,6 +862,9 @@ class AXMSafetyPlanSectionBuilderComponent {
704
862
  workStepTypeId: typeof section['workStepTypeId'] === 'string' ? section['workStepTypeId'] : undefined,
705
863
  workStepType: section['workStepType'],
706
864
  columns: normalizeStepTableColumns(section['columns']),
865
+ widgetOptions: section['widgetOptions'] && typeof section['widgetOptions'] === 'object' && !Array.isArray(section['widgetOptions'])
866
+ ? { ...section['widgetOptions'] }
867
+ : undefined,
707
868
  items: this.collapseBuilderRowsToStorageItems(section.id, section.items, section),
708
869
  })),
709
870
  });
@@ -767,10 +928,12 @@ class AXMSafetyPlanSectionBuilderComponent {
767
928
  : undefined;
768
929
  snapshots.push({
769
930
  id: entityId,
770
- title: (typeof snapshot?.title === 'string' && snapshot.title) ||
771
- (typeof item['title'] === 'string' ? item['title'] : undefined),
772
- code: (typeof snapshot?.code === 'string' && snapshot.code) ||
773
- (typeof item['name'] === 'string' ? item['name'] : undefined),
931
+ title: asSafetyPlanDisplayText(snapshot?.title) ||
932
+ asSafetyPlanDisplayText(item['title']) ||
933
+ undefined,
934
+ code: asSafetyPlanDisplayText(snapshot?.code) ||
935
+ asSafetyPlanDisplayText(item['name']) ||
936
+ undefined,
774
937
  });
775
938
  }
776
939
  if (!itemIds.length) {
@@ -799,8 +962,8 @@ class AXMSafetyPlanSectionBuilderComponent {
799
962
  const snapshot = snapshots.find((entry) => entry?.id === id) ?? snapshots[index];
800
963
  linked.push({
801
964
  id,
802
- title: snapshot?.title,
803
- code: snapshot?.code,
965
+ title: asSafetyPlanDisplayText(snapshot?.title) || undefined,
966
+ code: asSafetyPlanDisplayText(snapshot?.code) || undefined,
804
967
  });
805
968
  }
806
969
  }
@@ -841,8 +1004,8 @@ class AXMSafetyPlanSectionBuilderComponent {
841
1004
  return null;
842
1005
  }
843
1006
  toBuilderItemFromEntity(sectionId, entry, order) {
844
- const title = String(entry.title ?? '').trim();
845
- const code = String(entry.code ?? '').trim();
1007
+ const title = asSafetyPlanDisplayText(entry.title);
1008
+ const code = asSafetyPlanDisplayText(entry.code);
846
1009
  return {
847
1010
  id: `${sectionId}__entity_${entry.id}`,
848
1011
  order,
@@ -1095,17 +1258,47 @@ class AXMSafetyPlanSectionBuilderComponent {
1095
1258
  }
1096
1259
  }
1097
1260
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1098
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMSafetyPlanSectionBuilderComponent, isStandalone: true, selector: "axm-safety-plan-section-builder", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, safetyPlanId: { classPropertyName: "safetyPlanId", publicName: "safetyPlanId", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", 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-safety-plan-section-builder\">\n @if (!readonly() && !hideHeaderActions() && allowAddSection()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n <ax-button\n class=\"ax-sm\"\n [text]=\"\n '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.add-section.title'\n | translate\n | async\n \"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n class=\"block min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\"\n />\n</div>\n", styles: [".axm-safety-plan-section-builder .__header{margin-bottom:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:space-between}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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: i3$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1261
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXMSafetyPlanSectionBuilderComponent, isStandalone: true, selector: "axm-safety-plan-section-builder", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, safetyPlanId: { classPropertyName: "safetyPlanId", publicName: "safetyPlanId", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", 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-safety-plan-section-builder\">\n @if (!readonly() && !hideHeaderActions() && allowAddSection()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n <ax-button\n class=\"ax-sm\"\n [text]=\"\n '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.add-section.title'\n | translate\n | async\n \"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n class=\"block min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\"\n />\n</div>\n", styles: [".axm-safety-plan-section-builder .__header{margin-bottom:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:space-between}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\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: i1$1.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1099
1262
  }
1100
1263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionBuilderComponent, decorators: [{
1101
1264
  type: Component,
1102
1265
  args: [{ selector: 'axm-safety-plan-section-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, AXButtonModule, AXDecoratorModule, AXTranslationModule, AXPStandardSectionItemsBuilderComponent], template: "<div class=\"axm-safety-plan-section-builder\">\n @if (!readonly() && !hideHeaderActions() && allowAddSection()) {\n <div class=\"__header\">\n <div class=\"__header-left\"></div>\n <div class=\"__header-right\">\n <ax-button\n class=\"ax-sm\"\n [text]=\"\n '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.add-section.title'\n | translate\n | async\n \"\n [color]=\"'primary'\"\n (onClick)=\"addSection()\"\n >\n <ax-prefix>\n <ax-icon icon=\"fa-light fa-layer-group\"></ax-icon>\n </ax-prefix>\n </ax-button>\n </div>\n </div>\n }\n\n <axp-standard-section-items-builder\n class=\"block min-h-[200px]\"\n [value]=\"builderValue()\"\n [config]=\"standardConfig()\"\n [readonly]=\"readonly()\"\n (valueChange)=\"onBuilderValueChange($event)\"\n />\n</div>\n", styles: [".axm-safety-plan-section-builder .__header{margin-bottom:calc(var(--spacing, .25rem) * 3);display:flex;align-items:center;justify-content:space-between}\n/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n"] }]
1103
1266
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], safetyPlanId: [{ type: i0.Input, args: [{ isSignal: true, alias: "safetyPlanId", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], standardRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AXPStandardSectionItemsBuilderComponent), { isSignal: true }] }] } });
1104
1267
 
1268
+ //#region ----- Imports -----
1269
+ //#endregion
1270
+ //#region ----- Service -----
1271
+ class AXMSafetyPlanPreviewService {
1272
+ constructor() {
1273
+ //#region ----- Services & Dependencies -----
1274
+ this.popupService = inject(AXPopupService);
1275
+ this.deviceService = inject(AXPDeviceService);
1276
+ }
1277
+ //#endregion
1278
+ //#region ----- Public API -----
1279
+ async open(options) {
1280
+ const { AXMSafetyPlanPreviewModalComponent } = await import('./acorex-platform-module-workplacesafety-management-client-safety-plan-preview-modal.component-C7IojUT9.mjs');
1281
+ await this.popupService.open(AXMSafetyPlanPreviewModalComponent, {
1282
+ title: options.title,
1283
+ size: this.deviceService.isSmall() ? 'full' : 'lg',
1284
+ data: {
1285
+ structure: options.structure,
1286
+ },
1287
+ });
1288
+ }
1289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanPreviewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1290
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanPreviewService, providedIn: 'root' }); }
1291
+ }
1292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanPreviewService, decorators: [{
1293
+ type: Injectable,
1294
+ args: [{ providedIn: 'root' }]
1295
+ }] });
1296
+
1105
1297
  //#region ---- Imports ----
1106
1298
  //#endregion
1107
1299
  //#region ---- Constants ----
1108
1300
  const SAFETY_PLAN_SECTIONS_ADD_SECTION_COMMAND = 'SafetyPlan:Sections:AddSection';
1301
+ const SAFETY_PLAN_SECTIONS_PREVIEW_COMMAND = 'SafetyPlan:Sections:Preview';
1109
1302
  const SAFETY_PLAN_SECTIONS_DISCARD_COMMAND = 'SafetyPlan:Sections:Discard';
1110
1303
  const SAFETY_PLAN_SECTIONS_CHANGE_PLAN_TYPE_COMMAND = 'SafetyPlan:Sections:ChangePlanType';
1111
1304
  const SAFETY_PLAN_SECTION_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.safetyPlanSection.name}`;
@@ -1132,6 +1325,7 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1132
1325
  this.layoutBuilder = inject(AXPLayoutBuilderService);
1133
1326
  this.hooks = inject(AXPHookService);
1134
1327
  this.hostPageLayout = inject(AXPPageLayoutBase, { optional: true, skipSelf: true });
1328
+ this.previewService = inject(AXMSafetyPlanPreviewService);
1135
1329
  this.baselineValue = signal(null, /* @ts-ignore */
1136
1330
  ...(ngDevMode ? [{ debugName: "baselineValue" }] : /* istanbul ignore next */ []));
1137
1331
  this.committedValue = signal(null, /* @ts-ignore */
@@ -1322,28 +1516,41 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1322
1516
  return this.isDirty();
1323
1517
  }
1324
1518
  async getPrimaryMenuItems() {
1325
- if (!this.isDraftPlan() || this.isLoadingStructure()) {
1326
- return [];
1327
- }
1328
- const actions = [
1329
- {
1519
+ const actions = [];
1520
+ const canPreview = !this.isLoadingStructure() &&
1521
+ (!!this.hasPlanType() || !!this.safetyPlanId() || (this.committedValue()?.sections.length ?? 0) > 0);
1522
+ if (this.isDraftPlan() && !this.isLoadingStructure()) {
1523
+ actions.push({
1330
1524
  title: '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.add-section.title',
1331
1525
  icon: 'fa-light fa-layer-group',
1332
1526
  zone: 'header',
1333
1527
  priority: 'primary',
1334
1528
  color: 'primary',
1335
1529
  command: { name: SAFETY_PLAN_SECTIONS_ADD_SECTION_COMMAND, options: {} },
1336
- },
1337
- {
1338
- title: '@workplacesafety-management:safety-plans.actions.change-plan-type.title',
1339
- icon: 'fa-light fa-arrow-right-arrow-left',
1530
+ });
1531
+ }
1532
+ if (canPreview) {
1533
+ actions.push({
1534
+ title: '@workplacesafety-management:safety-plan-sections.entities.safety-plan-section.actions.preview.title',
1535
+ icon: 'fa-light fa-eye',
1340
1536
  zone: 'header',
1341
1537
  priority: 'secondary',
1342
1538
  color: 'default',
1343
- visible: this.isDraftPlan() && (!!this.planTypeId() || !!this.safetyPlanId()),
1344
- command: { name: SAFETY_PLAN_SECTIONS_CHANGE_PLAN_TYPE_COMMAND, options: {} },
1345
- },
1346
- ];
1539
+ command: { name: SAFETY_PLAN_SECTIONS_PREVIEW_COMMAND, options: {} },
1540
+ });
1541
+ }
1542
+ if (!this.isDraftPlan() || this.isLoadingStructure()) {
1543
+ return actions;
1544
+ }
1545
+ actions.push({
1546
+ title: '@workplacesafety-management:safety-plans.actions.change-plan-type.title',
1547
+ icon: 'fa-light fa-arrow-right-arrow-left',
1548
+ zone: 'header',
1549
+ priority: 'secondary',
1550
+ color: 'default',
1551
+ visible: this.isDraftPlan() && (!!this.planTypeId() || !!this.safetyPlanId()),
1552
+ command: { name: SAFETY_PLAN_SECTIONS_CHANGE_PLAN_TYPE_COMMAND, options: {} },
1553
+ });
1347
1554
  if (this.safetyPlanId()) {
1348
1555
  actions.push({
1349
1556
  title: '@general:actions.discard.title',
@@ -1370,6 +1577,10 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1370
1577
  await this.builderRef()?.addSection();
1371
1578
  return;
1372
1579
  }
1580
+ if (command.name === SAFETY_PLAN_SECTIONS_PREVIEW_COMMAND) {
1581
+ await this.handlePreview();
1582
+ return;
1583
+ }
1373
1584
  if (command.name === SAFETY_PLAN_SECTIONS_CHANGE_PLAN_TYPE_COMMAND) {
1374
1585
  await this.handleChangePlanType();
1375
1586
  return;
@@ -1382,6 +1593,16 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1382
1593
  return;
1383
1594
  await this.handleSave({ silent: false });
1384
1595
  }
1596
+ async handlePreview() {
1597
+ const previewLabel = (await this.translateService.translateAsync('@general:actions.preview.title')) || 'Preview';
1598
+ const locale = this.translateService.getActiveLang?.() ?? 'en-US';
1599
+ const planTitle = resolveEntityRowDisplayText(this.rootContext()?.['title'], locale);
1600
+ const title = planTitle ? `${previewLabel}: ${planTitle}` : previewLabel;
1601
+ await this.previewService.open({
1602
+ title,
1603
+ structure: cloneDeep(this.committedValue() ?? { sections: [] }),
1604
+ });
1605
+ }
1385
1606
  async handleChangePlanType() {
1386
1607
  if (!this.isDraftPlan()) {
1387
1608
  this.toastService.show({
@@ -1653,7 +1874,85 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1653
1874
  const columnsByWorkStepTypeId = await this.loadWorkStepTypeColumns(deduped.sections
1654
1875
  .map((section) => section.workStepTypeId)
1655
1876
  .filter((id) => typeof id === 'string' && id.length > 0));
1656
- return hydrateStepTableSectionsWithWorkSteps(deduped, (workStepsResult.items ?? []), columnsByWorkStepTypeId);
1877
+ return this.hydrateCatalogItemSnapshots(hydrateStepTableSectionsWithWorkSteps(deduped, (workStepsResult.items ?? []), columnsByWorkStepTypeId));
1878
+ }
1879
+ /**
1880
+ * Repeater lookups are not joined on query. Fill missing catalog item titles from
1881
+ * Hazard / HazardRisk / PPE / Control records so seeded item cards are not blank.
1882
+ */
1883
+ async hydrateCatalogItemSnapshots(value) {
1884
+ const locale = this.translateService.getActiveLang?.() ?? 'en-US';
1885
+ const missingByEntity = new Map();
1886
+ for (const section of value.sections) {
1887
+ if (isStepTableSectionType(section.sectionTypeId, section.sectionType)) {
1888
+ continue;
1889
+ }
1890
+ const entityName = resolveSectionItemEntityName(section.sectionTypeId, section.sectionType);
1891
+ if (!entityName) {
1892
+ continue;
1893
+ }
1894
+ for (const slot of section.items) {
1895
+ for (const id of slot.itemIds ?? []) {
1896
+ const snapshot = slot.items?.find((entry) => entry.id === id);
1897
+ if (asSafetyPlanDisplayText(snapshot?.title) || asSafetyPlanDisplayText(snapshot?.code)) {
1898
+ continue;
1899
+ }
1900
+ const ids = missingByEntity.get(entityName) ?? new Set();
1901
+ ids.add(id);
1902
+ missingByEntity.set(entityName, ids);
1903
+ }
1904
+ }
1905
+ }
1906
+ if (missingByEntity.size === 0) {
1907
+ return value;
1908
+ }
1909
+ const loadedById = new Map();
1910
+ await Promise.all([...missingByEntity.entries()].map(async ([entityName, ids]) => {
1911
+ const idList = [...ids];
1912
+ try {
1913
+ const result = await this.entityService.withEntity(entityName).data().query({
1914
+ skip: 0,
1915
+ take: Math.max(idList.length, 1),
1916
+ filter: idList.length === 1
1917
+ ? { field: 'id', operator: { type: 'equal' }, value: idList[0] }
1918
+ : { field: 'id', operator: { type: 'in' }, value: idList },
1919
+ });
1920
+ for (const row of result.items ?? []) {
1921
+ const record = row;
1922
+ const id = resolveEntityRefId(record['id']);
1923
+ if (!id) {
1924
+ continue;
1925
+ }
1926
+ loadedById.set(id, {
1927
+ title: resolveEntityRowDisplayText(record['title'], locale) || undefined,
1928
+ code: asSafetyPlanDisplayText(record['code']) || undefined,
1929
+ });
1930
+ }
1931
+ }
1932
+ catch {
1933
+ /* skip entities the session cannot read */
1934
+ }
1935
+ }));
1936
+ if (loadedById.size === 0) {
1937
+ return value;
1938
+ }
1939
+ return {
1940
+ sections: value.sections.map((section) => ({
1941
+ ...section,
1942
+ items: section.items.map((slot) => ({
1943
+ ...slot,
1944
+ items: (slot.itemIds ?? []).map((id, index) => {
1945
+ const existing = slot.items?.find((entry) => entry.id === id) ?? slot.items?.[index];
1946
+ const loaded = loadedById.get(id);
1947
+ return {
1948
+ id,
1949
+ title: asSafetyPlanDisplayText(existing?.title) || loaded?.title,
1950
+ code: asSafetyPlanDisplayText(existing?.code) || loaded?.code,
1951
+ };
1952
+ }),
1953
+ })),
1954
+ })),
1955
+ };
1657
1956
  }
1658
1957
  async loadWorkStepTypeColumns(workStepTypeIds) {
1659
1958
  const uniqueIds = [...new Set(workStepTypeIds)];
@@ -1825,7 +2124,7 @@ class AXMSafetyPlanSectionsPageComponent extends AXPPageLayoutBaseComponent {
1825
2124
  }}
1826
2125
  </p>
1827
2126
  }
1828
- `, isInline: true, dependencies: [{ kind: "component", type: AXMSafetyPlanSectionBuilderComponent, selector: "axm-safety-plan-section-builder", inputs: ["value", "safetyPlanId", "options"], outputs: ["valueChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i3$1.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2127
+ `, isInline: true, dependencies: [{ kind: "component", type: AXMSafetyPlanSectionBuilderComponent, selector: "axm-safety-plan-section-builder", inputs: ["value", "safetyPlanId", "options"], outputs: ["valueChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1$1.AXTranslatorPipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1829
2128
  }
1830
2129
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMSafetyPlanSectionsPageComponent, decorators: [{
1831
2130
  type: Component,
@@ -1897,4 +2196,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
1897
2196
  }] });
1898
2197
 
1899
2198
  export { AXMSafetyPlanSectionBuilderComponent, AXMSafetyPlanSectionsPageComponent, AXMSafetyPlanSectionsPageComponentProvider, SAFETY_PLAN_SECTIONS_SAVE_COMMAND };
1900
- //# sourceMappingURL=acorex-platform-module-workplacesafety-management-client-index-kF37zgd4.mjs.map
2199
+ //# sourceMappingURL=acorex-platform-module-workplacesafety-management-client-index-yxxC7i6A.mjs.map