@things-factory/ops-master 10.1.34 → 10.1.35

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 (119) hide show
  1. package/dist-client/master-change-approval.d.ts +7 -0
  2. package/dist-client/master-change-approval.js +16 -0
  3. package/dist-client/master-change-approval.js.map +1 -1
  4. package/dist-client/pages/master/material-definition.d.ts +4 -11
  5. package/dist-client/pages/master/material-definition.js +5 -53
  6. package/dist-client/pages/master/material-definition.js.map +1 -1
  7. package/dist-client/pages/master/material-revision-fields.d.ts +2 -0
  8. package/dist-client/pages/master/material-revision-fields.js +43 -0
  9. package/dist-client/pages/master/material-revision-fields.js.map +1 -0
  10. package/dist-client/pages/master/recipe-definition.d.ts +4 -135
  11. package/dist-client/pages/master/recipe-definition.js +7 -397
  12. package/dist-client/pages/master/recipe-definition.js.map +1 -1
  13. package/dist-client/pages/master/revision-comparison.d.ts +48 -0
  14. package/dist-client/pages/master/revision-comparison.js +553 -0
  15. package/dist-client/pages/master/revision-comparison.js.map +1 -0
  16. package/dist-client/pages/master/revision-view.d.ts +19 -0
  17. package/dist-client/pages/master/revision-view.js +133 -0
  18. package/dist-client/pages/master/revision-view.js.map +1 -0
  19. package/dist-client/pages/master/revision-workspace.d.ts +50 -0
  20. package/dist-client/pages/master/revision-workspace.js +752 -0
  21. package/dist-client/pages/master/revision-workspace.js.map +1 -0
  22. package/dist-client/pages/master/test-specification.d.ts +4 -29
  23. package/dist-client/pages/master/test-specification.js +5 -225
  24. package/dist-client/pages/master/test-specification.js.map +1 -1
  25. package/dist-client/tsconfig.tsbuildinfo +1 -1
  26. package/dist-server/service/index.d.ts +12 -2
  27. package/dist-server/service/index.js +10 -0
  28. package/dist-server/service/index.js.map +1 -1
  29. package/dist-server/service/master-axis.js +1 -1
  30. package/dist-server/service/master-axis.js.map +1 -1
  31. package/dist-server/service/master-change-policy.js +7 -2
  32. package/dist-server/service/master-change-policy.js.map +1 -1
  33. package/dist-server/service/master-conformance-resolver.js +11 -1
  34. package/dist-server/service/master-conformance-resolver.js.map +1 -1
  35. package/dist-server/service/master-crud.js +3 -0
  36. package/dist-server/service/master-crud.js.map +1 -1
  37. package/dist-server/service/master-list.js +6 -0
  38. package/dist-server/service/master-list.js.map +1 -1
  39. package/dist-server/service/material/index.d.ts +3 -2
  40. package/dist-server/service/material/index.js +4 -2
  41. package/dist-server/service/material/index.js.map +1 -1
  42. package/dist-server/service/material/material-axis-status.d.ts +8 -0
  43. package/dist-server/service/material/material-axis-status.js +19 -0
  44. package/dist-server/service/material/material-axis-status.js.map +1 -0
  45. package/dist-server/service/material/material-definition.d.ts +3 -0
  46. package/dist-server/service/material/material-definition.js +13 -0
  47. package/dist-server/service/material/material-definition.js.map +1 -1
  48. package/dist-server/service/material/material-effective-list.d.ts +39 -0
  49. package/dist-server/service/material/material-effective-list.js +54 -0
  50. package/dist-server/service/material/material-effective-list.js.map +1 -0
  51. package/dist-server/service/material/material-master-resolver.js +4 -10
  52. package/dist-server/service/material/material-master-resolver.js.map +1 -1
  53. package/dist-server/service/material/material-query.js +9 -2
  54. package/dist-server/service/material/material-query.js.map +1 -1
  55. package/dist-server/service/material/material-revision-content.d.ts +10 -0
  56. package/dist-server/service/material/material-revision-content.js +92 -0
  57. package/dist-server/service/material/material-revision-content.js.map +1 -0
  58. package/dist-server/service/material/material-revision-resolver.d.ts +54 -0
  59. package/dist-server/service/material/material-revision-resolver.js +76 -0
  60. package/dist-server/service/material/material-revision-resolver.js.map +1 -0
  61. package/dist-server/service/material/material-revision-service.d.ts +144 -0
  62. package/dist-server/service/material/material-revision-service.js +534 -0
  63. package/dist-server/service/material/material-revision-service.js.map +1 -0
  64. package/dist-server/service/material/material-revision.d.ts +84 -0
  65. package/dist-server/service/material/material-revision.js +339 -0
  66. package/dist-server/service/material/material-revision.js.map +1 -0
  67. package/dist-server/service/operation/operation-definition.js +1 -0
  68. package/dist-server/service/operation/operation-definition.js.map +1 -1
  69. package/dist-server/service/operation/operation-master-resolver.js +2 -5
  70. package/dist-server/service/operation/operation-master-resolver.js.map +1 -1
  71. package/dist-server/service/recipe/index.d.ts +3 -2
  72. package/dist-server/service/recipe/index.js +4 -2
  73. package/dist-server/service/recipe/index.js.map +1 -1
  74. package/dist-server/service/recipe/recipe-definition.d.ts +4 -0
  75. package/dist-server/service/recipe/recipe-definition.js +14 -1
  76. package/dist-server/service/recipe/recipe-definition.js.map +1 -1
  77. package/dist-server/service/recipe/recipe-effective-list.d.ts +49 -0
  78. package/dist-server/service/recipe/recipe-effective-list.js +96 -0
  79. package/dist-server/service/recipe/recipe-effective-list.js.map +1 -0
  80. package/dist-server/service/recipe/recipe-query.js +9 -2
  81. package/dist-server/service/recipe/recipe-query.js.map +1 -1
  82. package/dist-server/service/recipe/recipe-revision-content.d.ts +32 -0
  83. package/dist-server/service/recipe/recipe-revision-content.js +65 -0
  84. package/dist-server/service/recipe/recipe-revision-content.js.map +1 -0
  85. package/dist-server/service/recipe/recipe-revision-line.d.ts +30 -0
  86. package/dist-server/service/recipe/recipe-revision-line.js +95 -0
  87. package/dist-server/service/recipe/recipe-revision-line.js.map +1 -0
  88. package/dist-server/service/recipe/recipe-revision-resolver.d.ts +59 -0
  89. package/dist-server/service/recipe/recipe-revision-resolver.js +76 -0
  90. package/dist-server/service/recipe/recipe-revision-resolver.js.map +1 -0
  91. package/dist-server/service/recipe/recipe-revision-service.d.ts +147 -0
  92. package/dist-server/service/recipe/recipe-revision-service.js +591 -0
  93. package/dist-server/service/recipe/recipe-revision-service.js.map +1 -0
  94. package/dist-server/service/recipe/recipe-revision.d.ts +100 -0
  95. package/dist-server/service/recipe/recipe-revision.js +373 -0
  96. package/dist-server/service/recipe/recipe-revision.js.map +1 -0
  97. package/dist-server/service/recipe/route-definition.js +1 -0
  98. package/dist-server/service/recipe/route-definition.js.map +1 -1
  99. package/dist-server/service/resource/class-members.js +9 -0
  100. package/dist-server/service/resource/class-members.js.map +1 -1
  101. package/dist-server/service/status/master-status.js +2 -1
  102. package/dist-server/service/status/master-status.js.map +1 -1
  103. package/dist-server/service/test-spec/test-spec-effective-list.d.ts +2 -0
  104. package/dist-server/service/test-spec/test-spec-effective-list.js +3 -1
  105. package/dist-server/service/test-spec/test-spec-effective-list.js.map +1 -1
  106. package/dist-server/service/test-spec/test-spec-revision-resolver.d.ts +1 -0
  107. package/dist-server/service/test-spec/test-spec-revision-service.d.ts +21 -0
  108. package/dist-server/service/test-spec/test-spec-revision-service.js +19 -0
  109. package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -1
  110. package/dist-server/service/test-spec/test-spec-revision.d.ts +2 -0
  111. package/dist-server/service/test-spec/test-spec-revision.js +6 -1
  112. package/dist-server/service/test-spec/test-spec-revision.js.map +1 -1
  113. package/dist-server/service/test-spec/test-specification.d.ts +2 -0
  114. package/dist-server/service/test-spec/test-specification.js +4 -0
  115. package/dist-server/service/test-spec/test-specification.js.map +1 -1
  116. package/dist-server/tsconfig.tsbuildinfo +1 -1
  117. package/package.json +4 -3
  118. package/translations/en.json +148 -0
  119. package/translations/ko.json +148 -0
@@ -0,0 +1,553 @@
1
+ var MasterRevisionReview_1;
2
+ import { __decorate, __metadata } from "tslib";
3
+ import { materialRevisionFields } from './material-revision-fields.js';
4
+ import { LitElement, html, css } from 'lit';
5
+ import { customElement, property, state } from 'lit/decorators.js';
6
+ import { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360 } from '@operato/layout';
7
+ import { i18next, localize } from '@operato/i18n';
8
+ import { ScrollbarStyles } from '@operato/styles';
9
+ import { revisionDifferences, revisionDetailAddress, revisionSideAt } from './revision-view.js';
10
+ export const revisionText = (key, params = {}) => String(i18next.t('revision-ui.' + key, params));
11
+ export const revisionDate = (value) => value
12
+ ? new Intl.DateTimeFormat(i18next.language || 'en', { dateStyle: 'medium', timeStyle: 'short' }).format(new Date(value))
13
+ : '—';
14
+ export const revisionStyles = css `
15
+ .material-property { border: 1px solid var(--ui-line, #ddd); margin: 12px 0; padding: 12px; min-width: 0; }
16
+ .material-property legend { font-weight: 600; padding: 0 6px; }
17
+ .material-property-values { display: grid; grid-template-columns: minmax(70px, 1fr) minmax(0, 3fr); gap: 8px; }
18
+ .material-property-values dt { color: var(--md-sys-color-on-surface-variant); }
19
+ .material-property-values dd { margin: 0; overflow-wrap: anywhere; }
20
+ :host {
21
+ color: var(--md-sys-color-on-surface);
22
+ font: inherit;
23
+ }
24
+ table {
25
+ width: 100%;
26
+ border-collapse: collapse;
27
+ font-size: var(--ui-t-small, 13px);
28
+ }
29
+ th,
30
+ td {
31
+ padding: 10px 12px;
32
+ border-bottom: 1px solid var(--ui-line);
33
+ text-align: left;
34
+ vertical-align: top;
35
+ overflow-wrap: anywhere;
36
+ }
37
+ th {
38
+ color: var(--md-sys-color-on-surface-variant);
39
+ font-weight: 600;
40
+ }
41
+ .scroll {
42
+ overflow: auto;
43
+ }
44
+ .muted {
45
+ color: var(--md-sys-color-on-surface-variant);
46
+ }
47
+ .pill {
48
+ display: inline-block;
49
+ padding: 3px 8px;
50
+ border-radius: 4px;
51
+ background: var(--md-sys-color-secondary-container);
52
+ color: var(--md-sys-color-on-secondary-container);
53
+ }
54
+ .before {
55
+ color: var(--md-sys-color-on-surface-variant);
56
+ }
57
+ .after {
58
+ font-weight: 600;
59
+ }
60
+ h3 {
61
+ font-size: var(--ui-t-title, 16px);
62
+ margin: 16px 0 10px;
63
+ }
64
+ button {
65
+ font: inherit;
66
+ min-height: var(--form-action-height, 32px);
67
+ padding: 4px 12px;
68
+ border: 1px solid var(--ui-line);
69
+ border-radius: 4px;
70
+ color: inherit;
71
+ background: var(--md-sys-color-surface);
72
+ cursor: pointer;
73
+ }
74
+ button.primary {
75
+ background: var(--md-sys-color-primary);
76
+ color: var(--md-sys-color-on-primary);
77
+ border-color: transparent;
78
+ }
79
+ button:disabled {
80
+ opacity: 0.5;
81
+ cursor: default;
82
+ }
83
+ button:focus-visible,
84
+ a:focus-visible,
85
+ input:focus-visible,
86
+ textarea:focus-visible,
87
+ select:focus-visible,
88
+ summary:focus-visible {
89
+ outline: 2px solid var(--md-sys-color-primary);
90
+ outline-offset: 3px;
91
+ }
92
+ details {
93
+ margin: 12px 0;
94
+ }
95
+ summary {
96
+ cursor: pointer;
97
+ padding: 8px 0;
98
+ }
99
+ `;
100
+ let MasterRevisionComparison = class MasterRevisionComparison extends localize(i18next)(LitElement) {
101
+ constructor() {
102
+ super(...arguments);
103
+ this.axis = 'testSpecification';
104
+ }
105
+ static { this.styles = [ScrollbarStyles, revisionStyles]; }
106
+ display(field, value) {
107
+ if (value === undefined || value === null)
108
+ return '—';
109
+ if (this.axis === 'workShift') {
110
+ if (field === 'fromDate' || field === 'toDate')
111
+ return revisionText('day-offset-' + value);
112
+ if (field === 'daysOfWeek')
113
+ return String(value).split(',').map(day => revisionText('weekday-' + day)).join(', ');
114
+ }
115
+ return value;
116
+ }
117
+ render() {
118
+ const changes = revisionDifferences(this.axis, this.before, this.after);
119
+ return html `<h3>
120
+ ${revisionText('changes')} <span class="pill">${revisionText('change-count', { count: changes.length })}</span>
121
+ </h3>
122
+ ${!this.before ? html `<p class="muted">${revisionText('new-baseline')}</p>` : ''}
123
+ ${changes.length
124
+ ? html `<div class="scroll">
125
+ <table>
126
+ <thead>
127
+ <tr>
128
+ <th>${revisionText('change-kind')}</th>
129
+ <th>${revisionText('item')}</th>
130
+ <th>${revisionText('before')}</th>
131
+ <th>${revisionText('after')}</th>
132
+ </tr>
133
+ </thead>
134
+ <tbody>
135
+ ${changes.map(row => html `<tr>
136
+ <td><span class="pill">${revisionText(row.kind)}</span></td>
137
+ <td>
138
+ ${revisionText(row.section)}${row.label ? ' · ' + row.label : ''}<br />${revisionText(row.field)}
139
+ </td>
140
+ <td class="before">${this.display(row.field, row.before)}</td>
141
+ <td class="after">${this.display(row.field, row.after)}</td>
142
+ </tr>`)}
143
+ </tbody>
144
+ </table>
145
+ </div>`
146
+ : html `<p>${revisionText('no-content-change')}</p>`}`;
147
+ }
148
+ };
149
+ __decorate([
150
+ property(),
151
+ __metadata("design:type", String)
152
+ ], MasterRevisionComparison.prototype, "axis", void 0);
153
+ __decorate([
154
+ property({ attribute: false }),
155
+ __metadata("design:type", Object)
156
+ ], MasterRevisionComparison.prototype, "before", void 0);
157
+ __decorate([
158
+ property({ attribute: false }),
159
+ __metadata("design:type", Object)
160
+ ], MasterRevisionComparison.prototype, "after", void 0);
161
+ MasterRevisionComparison = __decorate([
162
+ customElement('ops-master-revision-comparison')
163
+ ], MasterRevisionComparison);
164
+ export { MasterRevisionComparison };
165
+ /** Uses the existing Worklist custom-element slot. No Worklist dependency in the master module. */
166
+ let MasterRevisionReview = class MasterRevisionReview extends localize(i18next)(LitElement) {
167
+ constructor() {
168
+ super(...arguments);
169
+ this.detailError = '';
170
+ }
171
+ static { MasterRevisionReview_1 = this; }
172
+ static { this.styles = [
173
+ ScrollbarStyles,
174
+ revisionStyles,
175
+ css `
176
+ :host {
177
+ display: block;
178
+ padding: 20px;
179
+ box-sizing: border-box;
180
+ }
181
+ .facts {
182
+ display: flex;
183
+ flex-wrap: wrap;
184
+ gap: 24px;
185
+ margin: 20px 0;
186
+ }
187
+ .facts p {
188
+ margin: 4px 0;
189
+ }
190
+ .impact {
191
+ padding: 12px;
192
+ background: var(--md-sys-color-surface-container);
193
+ }
194
+ h2 {
195
+ margin: 0;
196
+ font-size: var(--ui-t-title, 20px);
197
+ }
198
+ .entity-links {
199
+ display: flex;
200
+ flex-wrap: wrap;
201
+ gap: 16px 32px;
202
+ }
203
+ .entity-links a {
204
+ display: inline-block;
205
+ padding: 8px 0;
206
+ color: var(--md-sys-color-primary);
207
+ text-underline-offset: 3px;
208
+ }
209
+ `
210
+ ]; }
211
+ // Worklist recreates custom views on shell updates. The common dock has a stable owner.
212
+ static { this.dockOwner = {}; }
213
+ static { this.enabled = false; }
214
+ static { this.detailPath = ''; }
215
+ static { this.detailRevision = ''; }
216
+ static { this.onAddress = () => requestAnimationFrame(() => MasterRevisionReview_1.activeReview?.syncDetail()); }
217
+ connectedCallback() {
218
+ super.connectedCallback();
219
+ MasterRevisionReview_1.activeReview = this;
220
+ // One provider listener, not one view listener: routing may disconnect a view during dispatch.
221
+ window.addEventListener('popstate', MasterRevisionReview_1.onAddress, true);
222
+ }
223
+ disconnectedCallback() {
224
+ if (MasterRevisionReview_1.activeReview === this)
225
+ MasterRevisionReview_1.activeReview = undefined;
226
+ requestAnimationFrame(() => {
227
+ if (!MasterRevisionReview_1.activeReview) {
228
+ hideEntity360(MasterRevisionReview_1.dockOwner, false);
229
+ MasterRevisionReview_1.enabled = false;
230
+ }
231
+ });
232
+ super.disconnectedCallback();
233
+ }
234
+ updated(changes) {
235
+ super.updated(changes);
236
+ if (changes.has('input') && MasterRevisionReview_1.enabled) {
237
+ if (location.pathname !== MasterRevisionReview_1.detailPath ||
238
+ this.input?.after?.detail?.revisionId !== MasterRevisionReview_1.detailRevision) {
239
+ hideEntity360(MasterRevisionReview_1.dockOwner, false);
240
+ MasterRevisionReview_1.enabled = false;
241
+ }
242
+ else
243
+ this.syncDetail();
244
+ }
245
+ }
246
+ syncDetail() {
247
+ if (MasterRevisionReview_1.activeReview !== this || !MasterRevisionReview_1.enabled)
248
+ return;
249
+ if (location.pathname !== MasterRevisionReview_1.detailPath) {
250
+ MasterRevisionReview_1.enabled = false;
251
+ hideEntity360(MasterRevisionReview_1.dockOwner, false);
252
+ return;
253
+ }
254
+ try {
255
+ const side = revisionSideAt(this.input, location.href);
256
+ if (side)
257
+ this.showDetail(side);
258
+ else
259
+ hideEntity360(MasterRevisionReview_1.dockOwner);
260
+ }
261
+ catch {
262
+ hideEntity360(MasterRevisionReview_1.dockOwner);
263
+ this.detailError = revisionText('detail-unavailable');
264
+ }
265
+ }
266
+ closeDetail() {
267
+ const url = new URL(location.href);
268
+ url.searchParams.delete('f');
269
+ url.searchParams.delete('revision');
270
+ const { entity360Previous: _previous, ...state } = history.state ?? {};
271
+ history.replaceState(state, '', url);
272
+ hideEntity360(MasterRevisionReview_1.dockOwner);
273
+ }
274
+ showDetail(side, opener) {
275
+ const row = this.input[side];
276
+ showEntity360(MasterRevisionReview_1.dockOwner, {
277
+ key: revisionDetailAddress(this.input, side, location.href),
278
+ title: this.input.headline,
279
+ context: `${revisionText(side)} · ${revisionText('revision-value', { n: row.revisionNumber })}`,
280
+ labels: { close: revisionText('dock-close'), expand: revisionText('dock-expand'), collapse: revisionText('dock-collapse'),
281
+ resize: revisionText('dock-resize'), back: revisionText('dock-back') },
282
+ onClose: () => (MasterRevisionReview_1.activeReview ?? this).closeDetail(),
283
+ onBack: canGoBackEntity360() ? () => history.back() : undefined,
284
+ content: html `<ops-master-revision-360 .input=${this.input} .side=${side}
285
+ .activityApproval=${this.activityApproval}></ops-master-revision-360>`
286
+ }, () => {
287
+ const target = opener?.isConnected ? opener : MasterRevisionReview_1.activeReview?.renderRoot.querySelector(`[data-detail="${side}"]`);
288
+ target?.focus({ preventScroll: true });
289
+ });
290
+ }
291
+ openDetail(side, opener) {
292
+ try {
293
+ const address = revisionDetailAddress(this.input, side, location.href);
294
+ this.detailError = '';
295
+ if (!MasterRevisionReview_1.enabled && new URL(location.href).searchParams.has('f')) {
296
+ const base = new URL(location.href);
297
+ base.searchParams.delete('f');
298
+ base.searchParams.delete('revision');
299
+ const { entity360Previous: _previous, ...state } = history.state ?? {};
300
+ history.replaceState(state, '', base);
301
+ }
302
+ MasterRevisionReview_1.enabled = true;
303
+ MasterRevisionReview_1.detailPath = location.pathname;
304
+ MasterRevisionReview_1.detailRevision = this.input.after.detail.revisionId;
305
+ navigateEntity360(address);
306
+ this.showDetail(side, opener);
307
+ }
308
+ catch {
309
+ this.detailError = revisionText('detail-unavailable');
310
+ }
311
+ }
312
+ entityLink(side) {
313
+ const row = this.input[side];
314
+ if (!row)
315
+ return html `<span>${revisionText('no-before')}</span>`;
316
+ // A URL alone never opens a modal. Inspection is always an explicit user action.
317
+ if (!row.detail)
318
+ return html `<span>${revisionText('detail-unavailable')}</span>`;
319
+ return html `<div>
320
+ <span class="muted">${revisionText(side)}</span><br />
321
+ <a href=${revisionDetailAddress(this.input, side, location.href)} data-detail=${side}
322
+ @click=${(event) => {
323
+ if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)
324
+ return;
325
+ event.preventDefault();
326
+ this.openDetail(side, event.currentTarget);
327
+ }}>${this.input.headline} · ${revisionText('revision-value', { n: row.revisionNumber })}</a>
328
+ </div>`;
329
+ }
330
+ render() {
331
+ const input = this.input;
332
+ if (!input)
333
+ return html ``;
334
+ const axis = input.revision?.arrangementId ? 'workShift' : input.revision?.recipeId ? 'recipeDefinition' : input.revision?.materialId ? 'materialDefinition' : 'testSpecification';
335
+ return html `<h2>${input.headline}</h2>
336
+ <div class="entity-links">${this.entityLink('before')}${this.entityLink('after')}</div>
337
+ ${this.detailError ? html `<p role="alert">${this.detailError}</p>` : ''}
338
+ <div class="facts">
339
+ <div>
340
+ <span class="muted">${revisionText('revision')}</span>
341
+ <p>
342
+ ${input.before ? revisionText('revision-value', { n: input.before.revisionNumber }) : revisionText('new')} →
343
+ ${revisionText('revision-value', { n: input.after.revisionNumber })}
344
+ </p>
345
+ </div>
346
+ <div>
347
+ <span class="muted">${revisionText('effectiveFrom')}</span>
348
+ <p>${revisionDate(input.effectiveFrom)} · ${Intl.DateTimeFormat().resolvedOptions().timeZone}</p>
349
+ </div>
350
+ <div>
351
+ <span class="muted">${revisionText('reason')}</span>
352
+ <p>${input.reason}</p>
353
+ </div>
354
+ </div>
355
+ <p class="impact">${revisionText(axis === 'workShift' ? 'shift-impact' : axis === 'recipeDefinition' ? 'recipe-impact' : axis === 'materialDefinition' ? 'material-impact' : 'spec-impact')}</p>
356
+ <ops-master-revision-comparison
357
+ .axis=${axis}
358
+ .before=${input.before}
359
+ .after=${input.after}
360
+ ></ops-master-revision-comparison>
361
+ <details>
362
+ <summary>${revisionText('full-content')}</summary>
363
+ ${revisionContents(input.after, axis)}
364
+ </details>
365
+ <p class="muted">${revisionText('signed-correction')}</p>`;
366
+ }
367
+ };
368
+ __decorate([
369
+ property({ attribute: false }),
370
+ __metadata("design:type", Object)
371
+ ], MasterRevisionReview.prototype, "input", void 0);
372
+ __decorate([
373
+ property({ attribute: false }),
374
+ __metadata("design:type", Object)
375
+ ], MasterRevisionReview.prototype, "activityApproval", void 0);
376
+ __decorate([
377
+ state(),
378
+ __metadata("design:type", Object)
379
+ ], MasterRevisionReview.prototype, "detailError", void 0);
380
+ MasterRevisionReview = MasterRevisionReview_1 = __decorate([
381
+ customElement('ops-master-revision-review')
382
+ ], MasterRevisionReview);
383
+ export { MasterRevisionReview };
384
+ export function revisionContents(value, axis) {
385
+ if (axis === 'workShift')
386
+ return html `<p>${revisionText('timezone')}: ${value.timezone}</p>
387
+ <div class="scroll"><table><thead><tr>${['name', 'fromDate', 'fromTime', 'toDate', 'toTime', 'daysOfWeek'].map(f => html `<th>${revisionText(f)}</th>`)}</tr></thead>
388
+ <tbody>${(value.shifts ?? []).map(row => html `<tr><td>${row.name}${row.description ? html `<br /><span class="muted">${row.description}</span>` : ''}</td><td>${revisionText('day-offset-' + row.fromDate)}</td><td>${row.fromTime}</td><td>${revisionText('day-offset-' + row.toDate)}</td><td>${row.toTime}</td><td>${row.daysOfWeek ? row.daysOfWeek.split(',').map(day => revisionText('weekday-' + day)).join(', ') : revisionText('every-day')}</td></tr>`)}</tbody></table></div>`;
389
+ if (axis === 'materialDefinition')
390
+ return materialRevisionFields(value);
391
+ return (axis === 'recipeDefinition' ? ['inputs', 'outputs'] : ['criteria']).map(section => {
392
+ const fields = section === 'criteria'
393
+ ? ['id', 'description', 'evaluatedPropertyId', 'minimum', 'maximum', 'uom', 'expression']
394
+ : section === 'inputs'
395
+ ? ['material', 'qty', 'operation']
396
+ : ['material', 'qty'];
397
+ return html `<h3>${revisionText(section)}</h3>
398
+ <div class="scroll">
399
+ <table class=${section === 'criteria' ? 'criteria' : ''}>
400
+ <thead>
401
+ <tr>
402
+ ${fields.map(field => html `<th>${revisionText(field)}</th>`)}
403
+ </tr>
404
+ </thead>
405
+ <tbody>
406
+ ${(value[section] ?? []).map((row) => html `<tr>
407
+ ${fields.map(field => html `<td>${(section === 'criteria' && ['minimum', 'maximum', 'uom'].includes(field) ? row.limit?.[field] : row[field]) ?? '—'}</td>`)}
408
+ </tr>`)}
409
+ </tbody>
410
+ </table>
411
+ </div>`;
412
+ });
413
+ }
414
+ /** Read-only revision contents. Layout, scrolling and closing belong to the common dock. */
415
+ let MasterRevision360 = class MasterRevision360 extends localize(i18next)(LitElement) {
416
+ constructor() {
417
+ super(...arguments);
418
+ this.side = 'after';
419
+ }
420
+ static { this.styles = [
421
+ ...MasterRevisionReview.styles,
422
+ css `
423
+ :host {
424
+ display: block;
425
+ min-height: 0;
426
+ }
427
+ section {
428
+ margin: 16px 0;
429
+ border-top: 1px solid var(--ui-line);
430
+ padding-top: 8px;
431
+ }
432
+ table.criteria { min-width: 640px; }
433
+ th, td { overflow-wrap: normal; word-break: normal; }
434
+ dl {
435
+ display: grid;
436
+ grid-template-columns: minmax(110px, 1fr) minmax(0, 3fr);
437
+ gap: 8px 16px;
438
+ }
439
+ dt {
440
+ color: var(--md-sys-color-on-surface-variant);
441
+ }
442
+ dd {
443
+ margin: 0;
444
+ overflow-wrap: anywhere;
445
+ }
446
+ `
447
+ ]; }
448
+ render() {
449
+ const row = this.input?.[this.side];
450
+ if (!row?.detail)
451
+ return html `<p role="alert">${revisionText('detail-unavailable')}</p>`;
452
+ const recipe = !!this.input.revision.recipeId;
453
+ const axis = this.input.revision.arrangementId ? 'workShift' : recipe ? 'recipeDefinition' : this.input.revision.materialId ? 'materialDefinition' : 'testSpecification';
454
+ const state = String(this.activityApproval?.activityThread?.activityInstance?.state ?? '').toLowerCase();
455
+ const judgment = String(this.activityApproval?.judgment ?? '').toLowerCase();
456
+ const status = this.side === 'before'
457
+ ? 'approval-baseline'
458
+ : judgment === 'rejected'
459
+ ? 'rejected'
460
+ : state === 'ended'
461
+ ? 'approved'
462
+ : state === 'aborted'
463
+ ? 'aborted'
464
+ : 'pending';
465
+ return html `<article>
466
+ <p>
467
+ <span class="pill">${revisionText(this.side)}</span> ·
468
+ ${revisionText('revision-value', { n: row.revisionNumber })} · ${revisionText(status)}
469
+ </p>
470
+ <p class="impact">${revisionText('fixed-review-context')}</p>
471
+ <section>
472
+ <h3>${revisionText('summary')}</h3>
473
+ <dl>
474
+ <dt>${revisionText('description')}</dt>
475
+ <dd>${row.description || '—'}</dd>
476
+ ${recipe
477
+ ? html `<dt>${revisionText('materialDefinitionName')}</dt>
478
+ <dd>${row.materialDefinitionName}</dd>
479
+ <dt>${revisionText('route')}</dt>
480
+ <dd>${row.route || '—'}</dd>`
481
+ : axis === 'materialDefinition' || axis === 'workShift' ? '' : html `<dt>${revisionText('version')}</dt>
482
+ <dd>${row.version}</dd>`}
483
+ </dl>
484
+ ${revisionContents(row, axis)}
485
+ </section>
486
+ <section>
487
+ <h3>${revisionText('state')}</h3>
488
+ <dl>
489
+ <dt>${revisionText(this.side === 'before' ? 'baseline-period' : 'proposed-start')}</dt>
490
+ <dd>
491
+ ${revisionDate(row.detail.validFrom ?? row.detail.effectiveFrom)}${this.side === 'before' ? html ` → ${row.detail.validTo ? revisionDate(row.detail.validTo) : revisionText('until-change')}` : ''}
492
+ </dd>
493
+ <dt>${revisionText('time-zone')}</dt>
494
+ <dd>${Intl.DateTimeFormat().resolvedOptions().timeZone}</dd>
495
+ </dl>
496
+ <p>${revisionText(this.side === 'before' ? 'baseline-period-hint' : 'proposed-start-hint')}</p>
497
+ </section>
498
+ <section>
499
+ <h3>${revisionText('related-entities')}</h3>
500
+ ${recipe
501
+ ? html `<p>
502
+ ${revisionText('inputs')}: ${[...new Set((row.inputs ?? []).map((r) => r.material))].join(', ')}
503
+ </p>
504
+ <p>
505
+ ${revisionText('outputs')}:
506
+ ${[...new Set((row.outputs ?? []).map((r) => r.material))].join(', ')}
507
+ </p>
508
+ <p>
509
+ ${revisionText('operation')}:
510
+ ${[...new Set((row.inputs ?? []).map((r) => r.operation).filter(Boolean))].join(', ') || '—'}
511
+ </p>`
512
+ : ''}
513
+ <p class="muted">${revisionText('relation-scope')}</p>
514
+ </section>
515
+ <section>
516
+ <h3>${revisionText('history')}</h3>
517
+ <dl>
518
+ <dt>${revisionText('created')}</dt>
519
+ <dd>${revisionDate(row.detail.createdAt)}</dd>
520
+ <dt>${revisionText('frozen')}</dt>
521
+ <dd>${revisionDate(row.detail.frozenAt)}</dd>
522
+ <dt>${revisionText('reason')}</dt>
523
+ <dd>${row.detail.reason}</dd>
524
+ </dl>
525
+ <p class="muted">${revisionText('history-scope')}</p>
526
+ </section>
527
+ <details>
528
+ <summary>${revisionText('technical-details')}</summary>
529
+ <dl>
530
+ <dt>Revision ID</dt>
531
+ <dd>${row.detail.revisionId}</dd>
532
+ </dl>
533
+ </details>
534
+ </article>`;
535
+ }
536
+ };
537
+ __decorate([
538
+ property(),
539
+ __metadata("design:type", String)
540
+ ], MasterRevision360.prototype, "side", void 0);
541
+ __decorate([
542
+ property({ attribute: false }),
543
+ __metadata("design:type", Object)
544
+ ], MasterRevision360.prototype, "input", void 0);
545
+ __decorate([
546
+ property({ attribute: false }),
547
+ __metadata("design:type", Object)
548
+ ], MasterRevision360.prototype, "activityApproval", void 0);
549
+ MasterRevision360 = __decorate([
550
+ customElement('ops-master-revision-360')
551
+ ], MasterRevision360);
552
+ export { MasterRevision360 };
553
+ //# sourceMappingURL=revision-comparison.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revision-comparison.js","sourceRoot":"","sources":["../../../client/pages/master/revision-comparison.ts"],"names":[],"mappings":"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","sourcesContent":["import { materialRevisionFields } from './material-revision-fields.js'\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360 } from '@operato/layout'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport {\n revisionDifferences,\n RevisionAxis,\n RevisionSide,\n revisionDetailAddress,\n revisionSideAt\n} from './revision-view.js'\n\nexport const revisionText = (key: string, params: any = {}): string => String(i18next.t('revision-ui.' + key, params))\nexport const revisionDate = (value?: string) =>\n value\n ? new Intl.DateTimeFormat(i18next.language || 'en', { dateStyle: 'medium', timeStyle: 'short' }).format(\n new Date(value)\n )\n : '—'\nexport const revisionStyles = css`\n .material-property { border: 1px solid var(--ui-line, #ddd); margin: 12px 0; padding: 12px; min-width: 0; }\n .material-property legend { font-weight: 600; padding: 0 6px; }\n .material-property-values { display: grid; grid-template-columns: minmax(70px, 1fr) minmax(0, 3fr); gap: 8px; }\n .material-property-values dt { color: var(--md-sys-color-on-surface-variant); }\n .material-property-values dd { margin: 0; overflow-wrap: anywhere; }\n :host {\n color: var(--md-sys-color-on-surface);\n font: inherit;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--ui-t-small, 13px);\n }\n th,\n td {\n padding: 10px 12px;\n border-bottom: 1px solid var(--ui-line);\n text-align: left;\n vertical-align: top;\n overflow-wrap: anywhere;\n }\n th {\n color: var(--md-sys-color-on-surface-variant);\n font-weight: 600;\n }\n .scroll {\n overflow: auto;\n }\n .muted {\n color: var(--md-sys-color-on-surface-variant);\n }\n .pill {\n display: inline-block;\n padding: 3px 8px;\n border-radius: 4px;\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n .before {\n color: var(--md-sys-color-on-surface-variant);\n }\n .after {\n font-weight: 600;\n }\n h3 {\n font-size: var(--ui-t-title, 16px);\n margin: 16px 0 10px;\n }\n button {\n font: inherit;\n min-height: var(--form-action-height, 32px);\n padding: 4px 12px;\n border: 1px solid var(--ui-line);\n border-radius: 4px;\n color: inherit;\n background: var(--md-sys-color-surface);\n cursor: pointer;\n }\n button.primary {\n background: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n border-color: transparent;\n }\n button:disabled {\n opacity: 0.5;\n cursor: default;\n }\n button:focus-visible,\n a:focus-visible,\n input:focus-visible,\n textarea:focus-visible,\n select:focus-visible,\n summary:focus-visible {\n outline: 2px solid var(--md-sys-color-primary);\n outline-offset: 3px;\n }\n details {\n margin: 12px 0;\n }\n summary {\n cursor: pointer;\n padding: 8px 0;\n }\n`\n@customElement('ops-master-revision-comparison')\nexport class MasterRevisionComparison extends localize(i18next)(LitElement) {\n static styles = [ScrollbarStyles, revisionStyles]\n @property() axis: RevisionAxis = 'testSpecification'\n @property({ attribute: false }) before: any\n @property({ attribute: false }) after: any\n private display(field: string, value: unknown) {\n if (value === undefined || value === null) return '—'\n if (this.axis === 'workShift') {\n if (field === 'fromDate' || field === 'toDate') return revisionText('day-offset-' + value)\n if (field === 'daysOfWeek') return String(value).split(',').map(day => revisionText('weekday-' + day)).join(', ')\n }\n return value\n }\n render() {\n const changes = revisionDifferences(this.axis, this.before, this.after)\n return html`<h3>\n ${revisionText('changes')} <span class=\"pill\">${revisionText('change-count', { count: changes.length })}</span>\n </h3>\n ${!this.before ? html`<p class=\"muted\">${revisionText('new-baseline')}</p>` : ''}\n ${\n changes.length\n ? html`<div class=\"scroll\">\n <table>\n <thead>\n <tr>\n <th>${revisionText('change-kind')}</th>\n <th>${revisionText('item')}</th>\n <th>${revisionText('before')}</th>\n <th>${revisionText('after')}</th>\n </tr>\n </thead>\n <tbody>\n ${changes.map(\n row =>\n html`<tr>\n <td><span class=\"pill\">${revisionText(row.kind)}</span></td>\n <td>\n ${revisionText(row.section)}${row.label ? ' · ' + row.label : ''}<br />${revisionText(row.field)}\n </td>\n <td class=\"before\">${this.display(row.field, row.before)}</td>\n <td class=\"after\">${this.display(row.field, row.after)}</td>\n </tr>`\n )}\n </tbody>\n </table>\n </div>`\n : html`<p>${revisionText('no-content-change')}</p>`\n }`\n }\n}\n\n/** Uses the existing Worklist custom-element slot. No Worklist dependency in the master module. */\n@customElement('ops-master-revision-review')\nexport class MasterRevisionReview extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n revisionStyles,\n css`\n :host {\n display: block;\n padding: 20px;\n box-sizing: border-box;\n }\n .facts {\n display: flex;\n flex-wrap: wrap;\n gap: 24px;\n margin: 20px 0;\n }\n .facts p {\n margin: 4px 0;\n }\n .impact {\n padding: 12px;\n background: var(--md-sys-color-surface-container);\n }\n h2 {\n margin: 0;\n font-size: var(--ui-t-title, 20px);\n }\n .entity-links {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n .entity-links a {\n display: inline-block;\n padding: 8px 0;\n color: var(--md-sys-color-primary);\n text-underline-offset: 3px;\n }\n `\n ]\n @property({ attribute: false }) input: any\n @property({ attribute: false }) activityApproval: any\n @state() private detailError = ''\n // Worklist recreates custom views on shell updates. The common dock has a stable owner.\n private static dockOwner = {}\n private static activeReview?: MasterRevisionReview\n private static enabled = false\n private static detailPath = ''\n private static detailRevision = ''\n private static onAddress = () => requestAnimationFrame(() => MasterRevisionReview.activeReview?.syncDetail())\n connectedCallback() {\n super.connectedCallback()\n MasterRevisionReview.activeReview = this\n // One provider listener, not one view listener: routing may disconnect a view during dispatch.\n window.addEventListener('popstate', MasterRevisionReview.onAddress, true)\n }\n disconnectedCallback() {\n if (MasterRevisionReview.activeReview === this) MasterRevisionReview.activeReview = undefined\n requestAnimationFrame(() => {\n if (!MasterRevisionReview.activeReview) {\n hideEntity360(MasterRevisionReview.dockOwner, false)\n MasterRevisionReview.enabled = false\n }\n })\n super.disconnectedCallback()\n }\n updated(changes: any) {\n super.updated(changes)\n if (changes.has('input') && MasterRevisionReview.enabled) {\n if (location.pathname !== MasterRevisionReview.detailPath ||\n this.input?.after?.detail?.revisionId !== MasterRevisionReview.detailRevision) {\n hideEntity360(MasterRevisionReview.dockOwner, false)\n MasterRevisionReview.enabled = false\n } else this.syncDetail()\n }\n }\n private syncDetail() {\n if (MasterRevisionReview.activeReview !== this || !MasterRevisionReview.enabled) return\n if (location.pathname !== MasterRevisionReview.detailPath) {\n MasterRevisionReview.enabled = false\n hideEntity360(MasterRevisionReview.dockOwner, false)\n return\n }\n try {\n const side = revisionSideAt(this.input, location.href)\n if (side) this.showDetail(side)\n else hideEntity360(MasterRevisionReview.dockOwner)\n } catch {\n hideEntity360(MasterRevisionReview.dockOwner)\n this.detailError = revisionText('detail-unavailable')\n }\n }\n private closeDetail() {\n const url = new URL(location.href)\n url.searchParams.delete('f')\n url.searchParams.delete('revision')\n const { entity360Previous: _previous, ...state } = history.state ?? {}\n history.replaceState(state, '', url)\n hideEntity360(MasterRevisionReview.dockOwner)\n }\n private showDetail(side: RevisionSide, opener?: HTMLElement) {\n const row = this.input[side]\n showEntity360(MasterRevisionReview.dockOwner, {\n key: revisionDetailAddress(this.input, side, location.href),\n title: this.input.headline,\n context: `${revisionText(side)} · ${revisionText('revision-value', { n: row.revisionNumber })}`,\n labels: { close: revisionText('dock-close'), expand: revisionText('dock-expand'), collapse: revisionText('dock-collapse'),\n resize: revisionText('dock-resize'), back: revisionText('dock-back') },\n onClose: () => (MasterRevisionReview.activeReview ?? this).closeDetail(),\n onBack: canGoBackEntity360() ? () => history.back() : undefined,\n content: html`<ops-master-revision-360 .input=${this.input} .side=${side}\n .activityApproval=${this.activityApproval}></ops-master-revision-360>`\n }, () => {\n const target = opener?.isConnected ? opener : MasterRevisionReview.activeReview?.renderRoot.querySelector<HTMLElement>(`[data-detail=\"${side}\"]`)\n target?.focus({ preventScroll: true })\n })\n }\n private openDetail(side: RevisionSide, opener?: HTMLElement) {\n try {\n const address = revisionDetailAddress(this.input, side, location.href)\n this.detailError = ''\n if (!MasterRevisionReview.enabled && new URL(location.href).searchParams.has('f')) {\n const base = new URL(location.href)\n base.searchParams.delete('f')\n base.searchParams.delete('revision')\n const { entity360Previous: _previous, ...state } = history.state ?? {}\n history.replaceState(state, '', base)\n }\n MasterRevisionReview.enabled = true\n MasterRevisionReview.detailPath = location.pathname\n MasterRevisionReview.detailRevision = this.input.after.detail.revisionId\n navigateEntity360(address)\n this.showDetail(side, opener)\n } catch {\n this.detailError = revisionText('detail-unavailable')\n }\n }\n private entityLink(side: RevisionSide) {\n const row = this.input[side]\n if (!row) return html`<span>${revisionText('no-before')}</span>`\n // A URL alone never opens a modal. Inspection is always an explicit user action.\n if (!row.detail) return html`<span>${revisionText('detail-unavailable')}</span>`\n return html`<div>\n <span class=\"muted\">${revisionText(side)}</span><br />\n <a href=${revisionDetailAddress(this.input, side, location.href)} data-detail=${side}\n @click=${(event: MouseEvent) => {\n if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return\n event.preventDefault()\n this.openDetail(side, event.currentTarget as HTMLElement)\n }}>${this.input.headline} · ${revisionText('revision-value', { n: row.revisionNumber })}</a>\n </div>`\n }\n render() {\n const input = this.input\n if (!input) return html``\n const axis: RevisionAxis = input.revision?.arrangementId ? 'workShift' : input.revision?.recipeId ? 'recipeDefinition' : input.revision?.materialId ? 'materialDefinition' : 'testSpecification'\n return html`<h2>${input.headline}</h2>\n <div class=\"entity-links\">${this.entityLink('before')}${this.entityLink('after')}</div>\n ${this.detailError ? html`<p role=\"alert\">${this.detailError}</p>` : ''}\n <div class=\"facts\">\n <div>\n <span class=\"muted\">${revisionText('revision')}</span>\n <p>\n ${input.before ? revisionText('revision-value', { n: input.before.revisionNumber }) : revisionText('new')} →\n ${revisionText('revision-value', { n: input.after.revisionNumber })}\n </p>\n </div>\n <div>\n <span class=\"muted\">${revisionText('effectiveFrom')}</span>\n <p>${revisionDate(input.effectiveFrom)} · ${Intl.DateTimeFormat().resolvedOptions().timeZone}</p>\n </div>\n <div>\n <span class=\"muted\">${revisionText('reason')}</span>\n <p>${input.reason}</p>\n </div>\n </div>\n <p class=\"impact\">${revisionText(axis === 'workShift' ? 'shift-impact' : axis === 'recipeDefinition' ? 'recipe-impact' : axis === 'materialDefinition' ? 'material-impact' : 'spec-impact')}</p>\n <ops-master-revision-comparison\n .axis=${axis}\n .before=${input.before}\n .after=${input.after}\n ></ops-master-revision-comparison>\n <details>\n <summary>${revisionText('full-content')}</summary>\n ${revisionContents(input.after, axis)}\n </details>\n <p class=\"muted\">${revisionText('signed-correction')}</p>`\n }\n}\n\nexport function revisionContents(value: any, axis: RevisionAxis) {\n if (axis === 'workShift') return html`<p>${revisionText('timezone')}: ${value.timezone}</p>\n <div class=\"scroll\"><table><thead><tr>${['name','fromDate','fromTime','toDate','toTime','daysOfWeek'].map(f => html`<th>${revisionText(f)}</th>`)}</tr></thead>\n <tbody>${(value.shifts ?? []).map(row => html`<tr><td>${row.name}${row.description ? html`<br /><span class=\"muted\">${row.description}</span>` : ''}</td><td>${revisionText('day-offset-' + row.fromDate)}</td><td>${row.fromTime}</td><td>${revisionText('day-offset-' + row.toDate)}</td><td>${row.toTime}</td><td>${row.daysOfWeek ? row.daysOfWeek.split(',').map(day => revisionText('weekday-' + day)).join(', ') : revisionText('every-day')}</td></tr>`)}</tbody></table></div>`\n\n if (axis === 'materialDefinition') return materialRevisionFields(value)\n return (axis === 'recipeDefinition' ? ['inputs', 'outputs'] : ['criteria']).map(section => {\n const fields =\n section === 'criteria'\n ? ['id', 'description', 'evaluatedPropertyId', 'minimum', 'maximum', 'uom', 'expression']\n : section === 'inputs'\n ? ['material', 'qty', 'operation']\n : ['material', 'qty']\n return html`<h3>${revisionText(section)}</h3>\n <div class=\"scroll\">\n <table class=${section === 'criteria' ? 'criteria' : ''}>\n <thead>\n <tr>\n ${fields.map(field => html`<th>${revisionText(field)}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${(value[section] ?? []).map(\n (row: any) =>\n html`<tr>\n ${fields.map(field => html`<td>${(section === 'criteria' && ['minimum', 'maximum', 'uom'].includes(field) ? row.limit?.[field] : row[field]) ?? '—'}</td>`)}\n </tr>`\n )}\n </tbody>\n </table>\n </div>`\n })\n}\n\n/** Read-only revision contents. Layout, scrolling and closing belong to the common dock. */\n@customElement('ops-master-revision-360')\nexport class MasterRevision360 extends localize(i18next)(LitElement) {\n static styles = [\n ...MasterRevisionReview.styles,\n css`\n :host {\n display: block;\n min-height: 0;\n }\n section {\n margin: 16px 0;\n border-top: 1px solid var(--ui-line);\n padding-top: 8px;\n }\n table.criteria { min-width: 640px; }\n th, td { overflow-wrap: normal; word-break: normal; }\n dl {\n display: grid;\n grid-template-columns: minmax(110px, 1fr) minmax(0, 3fr);\n gap: 8px 16px;\n }\n dt {\n color: var(--md-sys-color-on-surface-variant);\n }\n dd {\n margin: 0;\n overflow-wrap: anywhere;\n }\n `\n ]\n @property() side: RevisionSide = 'after'\n @property({ attribute: false }) input: any\n @property({ attribute: false }) activityApproval: any\n render() {\n const row = this.input?.[this.side]\n if (!row?.detail) return html`<p role=\"alert\">${revisionText('detail-unavailable')}</p>`\n const recipe = !!this.input.revision.recipeId\n const axis: RevisionAxis = this.input.revision.arrangementId ? 'workShift' : recipe ? 'recipeDefinition' : this.input.revision.materialId ? 'materialDefinition' : 'testSpecification'\n const state = String(this.activityApproval?.activityThread?.activityInstance?.state ?? '').toLowerCase()\n const judgment = String(this.activityApproval?.judgment ?? '').toLowerCase()\n const status =\n this.side === 'before'\n ? 'approval-baseline'\n : judgment === 'rejected'\n ? 'rejected'\n : state === 'ended'\n ? 'approved'\n : state === 'aborted'\n ? 'aborted'\n : 'pending'\n return html`<article>\n <p>\n <span class=\"pill\">${revisionText(this.side)}</span> ·\n ${revisionText('revision-value', { n: row.revisionNumber })} · ${revisionText(status)}\n </p>\n <p class=\"impact\">${revisionText('fixed-review-context')}</p>\n <section>\n <h3>${revisionText('summary')}</h3>\n <dl>\n <dt>${revisionText('description')}</dt>\n <dd>${row.description || '—'}</dd>\n ${\n recipe\n ? html`<dt>${revisionText('materialDefinitionName')}</dt>\n <dd>${row.materialDefinitionName}</dd>\n <dt>${revisionText('route')}</dt>\n <dd>${row.route || '—'}</dd>`\n : axis === 'materialDefinition' || axis === 'workShift' ? '' : html`<dt>${revisionText('version')}</dt>\n <dd>${row.version}</dd>`\n }\n </dl>\n ${revisionContents(row, axis)}\n </section>\n <section>\n <h3>${revisionText('state')}</h3>\n <dl>\n <dt>${revisionText(this.side === 'before' ? 'baseline-period' : 'proposed-start')}</dt>\n <dd>\n ${revisionDate(row.detail.validFrom ?? row.detail.effectiveFrom)}${this.side === 'before' ? html` → ${row.detail.validTo ? revisionDate(row.detail.validTo) : revisionText('until-change')}` : ''}\n </dd>\n <dt>${revisionText('time-zone')}</dt>\n <dd>${Intl.DateTimeFormat().resolvedOptions().timeZone}</dd>\n </dl>\n <p>${revisionText(this.side === 'before' ? 'baseline-period-hint' : 'proposed-start-hint')}</p>\n </section>\n <section>\n <h3>${revisionText('related-entities')}</h3>\n ${\n recipe\n ? html`<p>\n ${revisionText('inputs')}: ${[...new Set((row.inputs ?? []).map((r: any) => r.material))].join(', ')}\n </p>\n <p>\n ${revisionText('outputs')}:\n ${[...new Set((row.outputs ?? []).map((r: any) => r.material))].join(', ')}\n </p>\n <p>\n ${revisionText('operation')}:\n ${[...new Set((row.inputs ?? []).map((r: any) => r.operation).filter(Boolean))].join(', ') || '—'}\n </p>`\n : ''\n }\n <p class=\"muted\">${revisionText('relation-scope')}</p>\n </section>\n <section>\n <h3>${revisionText('history')}</h3>\n <dl>\n <dt>${revisionText('created')}</dt>\n <dd>${revisionDate(row.detail.createdAt)}</dd>\n <dt>${revisionText('frozen')}</dt>\n <dd>${revisionDate(row.detail.frozenAt)}</dd>\n <dt>${revisionText('reason')}</dt>\n <dd>${row.detail.reason}</dd>\n </dl>\n <p class=\"muted\">${revisionText('history-scope')}</p>\n </section>\n <details>\n <summary>${revisionText('technical-details')}</summary>\n <dl>\n <dt>Revision ID</dt>\n <dd>${row.detail.revisionId}</dd>\n </dl>\n </details>\n </article>`\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ /** View calculations only. IDs are comparison keys, never display labels. */
2
+ /** Flatten only for comparison labels. The stored structure and sibling order remain intact. */
3
+ export declare function materialDifferenceValues(value: any): Map<string, unknown>;
4
+ export type RevisionAxis = 'recipeDefinition' | 'testSpecification' | 'materialDefinition' | 'workShift';
5
+ export type RevisionSide = 'before' | 'after';
6
+ /** A detail address is scoped to the already-authorized approval, not a general revision lookup. */
7
+ export declare function revisionDetailAddress(input: any, side: RevisionSide, href: string): string;
8
+ export declare function revisionSideAt(input: any, href: string): RevisionSide | undefined;
9
+ export interface Difference {
10
+ section: string;
11
+ label: string;
12
+ field: string;
13
+ before: unknown;
14
+ after: unknown;
15
+ kind: 'added' | 'removed' | 'changed';
16
+ }
17
+ export declare function revisionDifferences(axis: RevisionAxis, before: any, after: any): Difference[];
18
+ export declare function localDateTime(iso: string): string;
19
+ export declare function isoFromLocal(value: string): string;