@things-factory/ops-master 10.0.18 → 10.1.0

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 (269) hide show
  1. package/dist-client/bootstrap.d.ts +18 -0
  2. package/dist-client/bootstrap.js +36 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/index.d.ts +15 -1
  5. package/dist-client/index.js +18 -1
  6. package/dist-client/index.js.map +1 -1
  7. package/dist-client/pages/master/equipment-class.d.ts +12 -0
  8. package/dist-client/pages/master/equipment-class.js +42 -0
  9. package/dist-client/pages/master/equipment-class.js.map +1 -0
  10. package/dist-client/pages/master/equipment.d.ts +12 -0
  11. package/dist-client/pages/master/equipment.js +57 -0
  12. package/dist-client/pages/master/equipment.js.map +1 -0
  13. package/dist-client/pages/master/grist-iso-duration.d.ts +20 -0
  14. package/dist-client/pages/master/grist-iso-duration.js +70 -0
  15. package/dist-client/pages/master/grist-iso-duration.js.map +1 -0
  16. package/dist-client/pages/master/grist-reference.d.ts +91 -0
  17. package/dist-client/pages/master/grist-reference.js +419 -0
  18. package/dist-client/pages/master/grist-reference.js.map +1 -0
  19. package/dist-client/pages/master/import-rows.d.ts +35 -0
  20. package/dist-client/pages/master/import-rows.js +66 -0
  21. package/dist-client/pages/master/import-rows.js.map +1 -0
  22. package/dist-client/pages/master/iso-duration.d.ts +34 -0
  23. package/dist-client/pages/master/iso-duration.js +76 -0
  24. package/dist-client/pages/master/iso-duration.js.map +1 -0
  25. package/dist-client/pages/master/master-options.d.ts +33 -0
  26. package/dist-client/pages/master/master-options.js +47 -0
  27. package/dist-client/pages/master/master-options.js.map +1 -0
  28. package/dist-client/pages/master/master-page-base.d.ts +357 -0
  29. package/dist-client/pages/master/master-page-base.js +626 -0
  30. package/dist-client/pages/master/master-page-base.js.map +1 -0
  31. package/dist-client/pages/master/material-class.d.ts +12 -0
  32. package/dist-client/pages/master/material-class.js +42 -0
  33. package/dist-client/pages/master/material-class.js.map +1 -0
  34. package/dist-client/pages/master/material-definition.d.ts +12 -0
  35. package/dist-client/pages/master/material-definition.js +62 -0
  36. package/dist-client/pages/master/material-definition.js.map +1 -0
  37. package/dist-client/pages/master/operation-definition.d.ts +12 -0
  38. package/dist-client/pages/master/operation-definition.js +49 -0
  39. package/dist-client/pages/master/operation-definition.js.map +1 -0
  40. package/dist-client/pages/master/operational-location.d.ts +84 -0
  41. package/dist-client/pages/master/operational-location.js +426 -0
  42. package/dist-client/pages/master/operational-location.js.map +1 -0
  43. package/dist-client/pages/master/person.d.ts +12 -0
  44. package/dist-client/pages/master/person.js +41 -0
  45. package/dist-client/pages/master/person.js.map +1 -0
  46. package/dist-client/pages/master/personnel-class.d.ts +12 -0
  47. package/dist-client/pages/master/personnel-class.js +43 -0
  48. package/dist-client/pages/master/personnel-class.js.map +1 -0
  49. package/dist-client/pages/master/physical-asset-class.d.ts +12 -0
  50. package/dist-client/pages/master/physical-asset-class.js +40 -0
  51. package/dist-client/pages/master/physical-asset-class.js.map +1 -0
  52. package/dist-client/pages/master/physical-asset.d.ts +12 -0
  53. package/dist-client/pages/master/physical-asset.js +41 -0
  54. package/dist-client/pages/master/physical-asset.js.map +1 -0
  55. package/dist-client/pages/master/recipe-definition.d.ts +136 -0
  56. package/dist-client/pages/master/recipe-definition.js +404 -0
  57. package/dist-client/pages/master/recipe-definition.js.map +1 -0
  58. package/dist-client/pages/master/reference-targets.d.ts +42 -0
  59. package/dist-client/pages/master/reference-targets.js +82 -0
  60. package/dist-client/pages/master/reference-targets.js.map +1 -0
  61. package/dist-client/pages/master/route-definition.d.ts +19 -0
  62. package/dist-client/pages/master/route-definition.js +40 -0
  63. package/dist-client/pages/master/route-definition.js.map +1 -0
  64. package/dist-client/pages/master/stop-reason.d.ts +12 -0
  65. package/dist-client/pages/master/stop-reason.js +48 -0
  66. package/dist-client/pages/master/stop-reason.js.map +1 -0
  67. package/dist-client/pages/master/test-specification.d.ts +93 -0
  68. package/dist-client/pages/master/test-specification.js +449 -0
  69. package/dist-client/pages/master/test-specification.js.map +1 -0
  70. package/dist-client/pages/master-axes.d.ts +20 -29
  71. package/dist-client/pages/master-axes.js +32 -169
  72. package/dist-client/pages/master-axes.js.map +1 -1
  73. package/dist-client/route.d.ts +1 -1
  74. package/dist-client/route.js +76 -3
  75. package/dist-client/route.js.map +1 -1
  76. package/dist-client/tsconfig.tsbuildinfo +1 -1
  77. package/dist-server/service/asset/asset-lifecycle.d.ts +30 -7
  78. package/dist-server/service/asset/asset-lifecycle.js +33 -6
  79. package/dist-server/service/asset/asset-lifecycle.js.map +1 -1
  80. package/dist-server/service/asset/asset-master-resolver.d.ts +9 -0
  81. package/dist-server/service/asset/asset-master-resolver.js +41 -0
  82. package/dist-server/service/asset/asset-master-resolver.js.map +1 -1
  83. package/dist-server/service/asset/asset-master.js +1 -1
  84. package/dist-server/service/asset/asset-master.js.map +1 -1
  85. package/dist-server/service/asset/asset-query.d.ts +9 -1
  86. package/dist-server/service/asset/asset-query.js +28 -6
  87. package/dist-server/service/asset/asset-query.js.map +1 -1
  88. package/dist-server/service/asset/physical-asset-class.js +1 -1
  89. package/dist-server/service/asset/physical-asset-class.js.map +1 -1
  90. package/dist-server/service/asset/physical-asset.d.ts +17 -4
  91. package/dist-server/service/asset/physical-asset.js +6 -6
  92. package/dist-server/service/asset/physical-asset.js.map +1 -1
  93. package/dist-server/service/equipment/equipment-class.js +1 -1
  94. package/dist-server/service/equipment/equipment-class.js.map +1 -1
  95. package/dist-server/service/equipment/equipment-master-resolver.d.ts +9 -0
  96. package/dist-server/service/equipment/equipment-master-resolver.js +58 -0
  97. package/dist-server/service/equipment/equipment-master-resolver.js.map +1 -1
  98. package/dist-server/service/equipment/equipment-master.d.ts +3 -2
  99. package/dist-server/service/equipment/equipment-master.js +21 -4
  100. package/dist-server/service/equipment/equipment-master.js.map +1 -1
  101. package/dist-server/service/equipment/equipment-query.d.ts +9 -1
  102. package/dist-server/service/equipment/equipment-query.js +28 -6
  103. package/dist-server/service/equipment/equipment-query.js.map +1 -1
  104. package/dist-server/service/equipment/equipment.d.ts +27 -1
  105. package/dist-server/service/equipment/equipment.js +8 -3
  106. package/dist-server/service/equipment/equipment.js.map +1 -1
  107. package/dist-server/service/equipment/state-period-rules.d.ts +19 -0
  108. package/dist-server/service/equipment/state-period-rules.js +35 -1
  109. package/dist-server/service/equipment/state-period-rules.js.map +1 -1
  110. package/dist-server/service/index.d.ts +12 -2
  111. package/dist-server/service/index.js +21 -1
  112. package/dist-server/service/index.js.map +1 -1
  113. package/dist-server/service/location/location-master-resolver.d.ts +29 -0
  114. package/dist-server/service/location/location-master-resolver.js +228 -1
  115. package/dist-server/service/location/location-master-resolver.js.map +1 -1
  116. package/dist-server/service/location/location-query.d.ts +9 -1
  117. package/dist-server/service/location/location-query.js +24 -9
  118. package/dist-server/service/location/location-query.js.map +1 -1
  119. package/dist-server/service/location/operational-location.d.ts +37 -0
  120. package/dist-server/service/location/operational-location.js +22 -2
  121. package/dist-server/service/location/operational-location.js.map +1 -1
  122. package/dist-server/service/master-axis.d.ts +1 -1
  123. package/dist-server/service/master-axis.js +16 -1
  124. package/dist-server/service/master-axis.js.map +1 -1
  125. package/dist-server/service/master-conformance-resolver.d.ts +34 -0
  126. package/dist-server/service/master-conformance-resolver.js +143 -0
  127. package/dist-server/service/master-conformance-resolver.js.map +1 -0
  128. package/dist-server/service/master-conformance.d.ts +80 -0
  129. package/dist-server/service/master-conformance.js +266 -0
  130. package/dist-server/service/master-conformance.js.map +1 -0
  131. package/dist-server/service/master-page-query.d.ts +33 -0
  132. package/dist-server/service/master-page-query.js +55 -0
  133. package/dist-server/service/master-page-query.js.map +1 -0
  134. package/dist-server/service/master-page.d.ts +85 -0
  135. package/dist-server/service/master-page.js +104 -0
  136. package/dist-server/service/master-page.js.map +1 -0
  137. package/dist-server/service/material/material-class.js +1 -1
  138. package/dist-server/service/material/material-class.js.map +1 -1
  139. package/dist-server/service/material/material-definition.js +2 -2
  140. package/dist-server/service/material/material-definition.js.map +1 -1
  141. package/dist-server/service/material/material-master-resolver.d.ts +62 -0
  142. package/dist-server/service/material/material-master-resolver.js +213 -0
  143. package/dist-server/service/material/material-master-resolver.js.map +1 -1
  144. package/dist-server/service/material/material-query.d.ts +9 -1
  145. package/dist-server/service/material/material-query.js +28 -6
  146. package/dist-server/service/material/material-query.js.map +1 -1
  147. package/dist-server/service/material/recipe-index.d.ts +23 -0
  148. package/dist-server/service/material/recipe-index.js +44 -0
  149. package/dist-server/service/material/recipe-index.js.map +1 -0
  150. package/dist-server/service/operation/index.d.ts +2 -1
  151. package/dist-server/service/operation/index.js +2 -1
  152. package/dist-server/service/operation/index.js.map +1 -1
  153. package/dist-server/service/operation/operation-definition.d.ts +1 -1
  154. package/dist-server/service/operation/operation-definition.js +4 -4
  155. package/dist-server/service/operation/operation-definition.js.map +1 -1
  156. package/dist-server/service/operation/operation-master-resolver.d.ts +24 -0
  157. package/dist-server/service/operation/operation-master-resolver.js +107 -0
  158. package/dist-server/service/operation/operation-master-resolver.js.map +1 -1
  159. package/dist-server/service/operation/operation-query.d.ts +10 -2
  160. package/dist-server/service/operation/operation-query.js +25 -10
  161. package/dist-server/service/operation/operation-query.js.map +1 -1
  162. package/dist-server/service/operation/operation-readiness-resolver.d.ts +39 -0
  163. package/dist-server/service/operation/operation-readiness-resolver.js +111 -0
  164. package/dist-server/service/operation/operation-readiness-resolver.js.map +1 -0
  165. package/dist-server/service/operation/operation-readiness.d.ts +34 -0
  166. package/dist-server/service/operation/operation-readiness.js +133 -0
  167. package/dist-server/service/operation/operation-readiness.js.map +1 -0
  168. package/dist-server/service/personnel/person.js +3 -3
  169. package/dist-server/service/personnel/person.js.map +1 -1
  170. package/dist-server/service/personnel/personnel-class-readiness.d.ts +22 -0
  171. package/dist-server/service/personnel/personnel-class-readiness.js +98 -0
  172. package/dist-server/service/personnel/personnel-class-readiness.js.map +1 -0
  173. package/dist-server/service/personnel/personnel-class.d.ts +1 -1
  174. package/dist-server/service/personnel/personnel-class.js +2 -2
  175. package/dist-server/service/personnel/personnel-class.js.map +1 -1
  176. package/dist-server/service/personnel/personnel-master-resolver.d.ts +9 -0
  177. package/dist-server/service/personnel/personnel-master-resolver.js +43 -0
  178. package/dist-server/service/personnel/personnel-master-resolver.js.map +1 -1
  179. package/dist-server/service/personnel/personnel-master.js +1 -1
  180. package/dist-server/service/personnel/personnel-master.js.map +1 -1
  181. package/dist-server/service/personnel/personnel-query.d.ts +9 -1
  182. package/dist-server/service/personnel/personnel-query.js +28 -6
  183. package/dist-server/service/personnel/personnel-query.js.map +1 -1
  184. package/dist-server/service/personnel/qualification.d.ts +7 -0
  185. package/dist-server/service/personnel/qualification.js +25 -0
  186. package/dist-server/service/personnel/qualification.js.map +1 -1
  187. package/dist-server/service/recipe/index.d.ts +9 -0
  188. package/dist-server/service/recipe/index.js +14 -0
  189. package/dist-server/service/recipe/index.js.map +1 -0
  190. package/dist-server/service/recipe/recipe-definition.d.ts +71 -0
  191. package/dist-server/service/recipe/recipe-definition.js +130 -0
  192. package/dist-server/service/recipe/recipe-definition.js.map +1 -0
  193. package/dist-server/service/recipe/recipe-master-resolver.d.ts +28 -0
  194. package/dist-server/service/recipe/recipe-master-resolver.js +124 -0
  195. package/dist-server/service/recipe/recipe-master-resolver.js.map +1 -0
  196. package/dist-server/service/recipe/recipe-master.d.ts +37 -0
  197. package/dist-server/service/recipe/recipe-master.js +47 -0
  198. package/dist-server/service/recipe/recipe-master.js.map +1 -0
  199. package/dist-server/service/recipe/recipe-query.d.ts +21 -0
  200. package/dist-server/service/recipe/recipe-query.js +75 -0
  201. package/dist-server/service/recipe/recipe-query.js.map +1 -0
  202. package/dist-server/service/recipe/route-definition.d.ts +51 -0
  203. package/dist-server/service/recipe/route-definition.js +113 -0
  204. package/dist-server/service/recipe/route-definition.js.map +1 -0
  205. package/dist-server/service/resource/class-lineage.d.ts +46 -0
  206. package/dist-server/service/resource/class-lineage.js +80 -0
  207. package/dist-server/service/resource/class-lineage.js.map +1 -0
  208. package/dist-server/service/resource/class-members.d.ts +36 -0
  209. package/dist-server/service/resource/class-members.js +50 -0
  210. package/dist-server/service/resource/class-members.js.map +1 -0
  211. package/dist-server/service/resource/referrers.d.ts +54 -0
  212. package/dist-server/service/resource/referrers.js +99 -0
  213. package/dist-server/service/resource/referrers.js.map +1 -0
  214. package/dist-server/service/status/master-status.d.ts +0 -7
  215. package/dist-server/service/status/master-status.js +5 -6
  216. package/dist-server/service/status/master-status.js.map +1 -1
  217. package/dist-server/service/test-spec/criteria-check.d.ts +53 -0
  218. package/dist-server/service/test-spec/criteria-check.js +142 -0
  219. package/dist-server/service/test-spec/criteria-check.js.map +1 -0
  220. package/dist-server/service/test-spec/criteria-rows.d.ts +89 -0
  221. package/dist-server/service/test-spec/criteria-rows.js +139 -0
  222. package/dist-server/service/test-spec/criteria-rows.js.map +1 -0
  223. package/dist-server/service/test-spec/test-spec-master-resolver.d.ts +33 -7
  224. package/dist-server/service/test-spec/test-spec-master-resolver.js +137 -2
  225. package/dist-server/service/test-spec/test-spec-master-resolver.js.map +1 -1
  226. package/dist-server/service/test-spec/test-spec-query.d.ts +9 -1
  227. package/dist-server/service/test-spec/test-spec-query.js +23 -9
  228. package/dist-server/service/test-spec/test-spec-query.js.map +1 -1
  229. package/dist-server/service/test-spec/test-specification.js +1 -1
  230. package/dist-server/service/test-spec/test-specification.js.map +1 -1
  231. package/dist-server/tsconfig.tsbuildinfo +1 -1
  232. package/helps/ops-master/equipment-class.ko.md +11 -0
  233. package/helps/ops-master/equipment-class.md +11 -0
  234. package/helps/ops-master/equipment.ko.md +11 -0
  235. package/helps/ops-master/equipment.md +11 -0
  236. package/helps/ops-master/material-class.ko.md +11 -0
  237. package/helps/ops-master/material-class.md +11 -0
  238. package/helps/ops-master/material-definition.ko.md +11 -0
  239. package/helps/ops-master/material-definition.md +11 -0
  240. package/helps/ops-master/operation-definition.ko.md +11 -0
  241. package/helps/ops-master/operation-definition.md +11 -0
  242. package/helps/ops-master/operational-location.ko.md +11 -0
  243. package/helps/ops-master/operational-location.md +11 -0
  244. package/helps/ops-master/person.ko.md +11 -0
  245. package/helps/ops-master/person.md +11 -0
  246. package/helps/ops-master/personnel-class.ko.md +11 -0
  247. package/helps/ops-master/personnel-class.md +11 -0
  248. package/helps/ops-master/physical-asset-class.ko.md +11 -0
  249. package/helps/ops-master/physical-asset-class.md +11 -0
  250. package/helps/ops-master/physical-asset.ko.md +11 -0
  251. package/helps/ops-master/physical-asset.md +11 -0
  252. package/helps/ops-master/recipe-definition.ko.md +11 -0
  253. package/helps/ops-master/recipe-definition.md +11 -0
  254. package/helps/ops-master/route-definition.ko.md +11 -0
  255. package/helps/ops-master/route-definition.md +11 -0
  256. package/helps/ops-master/stop-reason.ko.md +11 -0
  257. package/helps/ops-master/stop-reason.md +11 -0
  258. package/helps/ops-master/test-specification.ko.md +11 -0
  259. package/helps/ops-master/test-specification.md +11 -0
  260. package/package.json +5 -5
  261. package/things-factory.config.js +22 -2
  262. package/translations/en.json +89 -6
  263. package/translations/ja.json +96 -1
  264. package/translations/ko.json +96 -13
  265. package/translations/ms.json +96 -1
  266. package/translations/zh.json +96 -1
  267. package/dist-client/pages/master-list.d.ts +0 -68
  268. package/dist-client/pages/master-list.js +0 -267
  269. package/dist-client/pages/master-list.js.map +0 -1
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 제조법을 **품목에서 되찾을 수 있게** 뒤집는다.
3
+ *
4
+ * 제조법은 「이 품목을 만들려면 무엇이 드나」를 말한다. 품목 화면이 묻는 것은 그 반대다 — 「이
5
+ * 품목을 만드는 제조법은 무엇이고, 이 품목은 어디에 쓰이나」. 그 뒤집기가 여기 있다.
6
+ *
7
+ * 화면과 데이터베이스에서 떼어 두는 것은 **시험 때문**이다. 여기서 가르는 것(같은 제조법이 한
8
+ * 품목을 두 공정에서 쓰는 경우 · 이름이 빈 줄)은 실제 자료에서 일어나는 일이고, 서버를 띄우지 않고
9
+ * 확인할 수 있어야 한다.
10
+ */
11
+ /** 제조법 한 줄에서 이 뒤집기가 보는 것만. */
12
+ export interface RecipeShape {
13
+ name: string;
14
+ materialDefinitionName?: string;
15
+ inputs?: Record<string, unknown>[];
16
+ }
17
+ export interface RecipeIndex {
18
+ /** 만드는 품목 → 제조법 이름들. */
19
+ makes: Map<string, string[]>;
20
+ /** 투입 품목 → 제조법 이름들. */
21
+ uses: Map<string, string[]>;
22
+ }
23
+ export declare function indexRecipes(rows: readonly RecipeShape[]): RecipeIndex;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * 제조법을 **품목에서 되찾을 수 있게** 뒤집는다.
4
+ *
5
+ * 제조법은 「이 품목을 만들려면 무엇이 드나」를 말한다. 품목 화면이 묻는 것은 그 반대다 — 「이
6
+ * 품목을 만드는 제조법은 무엇이고, 이 품목은 어디에 쓰이나」. 그 뒤집기가 여기 있다.
7
+ *
8
+ * 화면과 데이터베이스에서 떼어 두는 것은 **시험 때문**이다. 여기서 가르는 것(같은 제조법이 한
9
+ * 품목을 두 공정에서 쓰는 경우 · 이름이 빈 줄)은 실제 자료에서 일어나는 일이고, 서버를 띄우지 않고
10
+ * 확인할 수 있어야 한다.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.indexRecipes = indexRecipes;
14
+ function indexRecipes(rows) {
15
+ const makes = new Map();
16
+ const uses = new Map();
17
+ const add = (map, key, recipe) => {
18
+ const name = String(key ?? '').trim();
19
+ /* 이름이 빈 줄은 아무것도 가리키지 않는다. 빈 이름으로 묶으면 없는 품목 하나가 생긴다. */
20
+ if (!name || !recipe) {
21
+ return;
22
+ }
23
+ const list = map.get(name);
24
+ if (!list) {
25
+ map.set(name, [recipe]);
26
+ return;
27
+ }
28
+ /*
29
+ * 같은 제조법이 같은 품목을 두 공정에서 쓰면 **한 번만** 적는다. 「어디에 쓰이나」의 답은
30
+ * 제조법이지 투입 줄이 아니다 — 두 번 적으면 「두 군데 쓰인다」로 읽힌다.
31
+ */
32
+ if (!list.includes(recipe)) {
33
+ list.push(recipe);
34
+ }
35
+ };
36
+ for (const row of rows) {
37
+ add(makes, row.materialDefinitionName, row.name);
38
+ for (const part of row.inputs ?? []) {
39
+ add(uses, part?.material, row.name);
40
+ }
41
+ }
42
+ return { makes, uses };
43
+ }
44
+ //# sourceMappingURL=recipe-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipe-index.js","sourceRoot":"","sources":["../../../server/service/material/recipe-index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAgBH,oCAqCC;AArCD,SAAgB,YAAY,CAAC,IAA4B;IACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAA;IACzC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAA;IAExC,MAAM,GAAG,GAAG,CAAC,GAA0B,EAAE,GAAY,EAAE,MAAc,EAAE,EAAE;QACvE,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QAErC,uDAAuD;QACvD,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;YACvB,OAAM;QACR,CAAC;QAED;;;WAGG;QACH,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACnB,CAAC;IACH,CAAC,CAAA;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,sBAAsB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QAEhD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YACpC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACrC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;AACxB,CAAC","sourcesContent":["/**\n * 제조법을 **품목에서 되찾을 수 있게** 뒤집는다.\n *\n * 제조법은 「이 품목을 만들려면 무엇이 드나」를 말한다. 품목 화면이 묻는 것은 그 반대다 — 「이\n * 품목을 만드는 제조법은 무엇이고, 이 품목은 어디에 쓰이나」. 그 뒤집기가 여기 있다.\n *\n * 화면과 데이터베이스에서 떼어 두는 것은 **시험 때문**이다. 여기서 가르는 것(같은 제조법이 한\n * 품목을 두 공정에서 쓰는 경우 · 이름이 빈 줄)은 실제 자료에서 일어나는 일이고, 서버를 띄우지 않고\n * 확인할 수 있어야 한다.\n */\n\n/** 제조법 한 줄에서 이 뒤집기가 보는 것만. */\nexport interface RecipeShape {\n name: string\n materialDefinitionName?: string\n inputs?: Record<string, unknown>[]\n}\n\nexport interface RecipeIndex {\n /** 만드는 품목 → 제조법 이름들. */\n makes: Map<string, string[]>\n /** 투입 품목 → 제조법 이름들. */\n uses: Map<string, string[]>\n}\n\nexport function indexRecipes(rows: readonly RecipeShape[]): RecipeIndex {\n const makes = new Map<string, string[]>()\n const uses = new Map<string, string[]>()\n\n const add = (map: Map<string, string[]>, key: unknown, recipe: string) => {\n const name = String(key ?? '').trim()\n\n /* 이름이 빈 줄은 아무것도 가리키지 않는다. 빈 이름으로 묶으면 없는 품목 하나가 생긴다. */\n if (!name || !recipe) {\n return\n }\n\n const list = map.get(name)\n\n if (!list) {\n map.set(name, [recipe])\n return\n }\n\n /*\n * 같은 제조법이 같은 품목을 두 공정에서 쓰면 **한 번만** 적는다. 「어디에 쓰이나」의 답은\n * 제조법이지 투입 줄이 아니다 — 두 번 적으면 「두 군데 쓰인다」로 읽힌다.\n */\n if (!list.includes(recipe)) {\n list.push(recipe)\n }\n }\n\n for (const row of rows) {\n add(makes, row.materialDefinitionName, row.name)\n\n for (const part of row.inputs ?? []) {\n add(uses, part?.material, row.name)\n }\n }\n\n return { makes, uses }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { OperationDefinition } from './operation-definition';
2
2
  import { OperationQuery } from './operation-query';
3
3
  import { OperationDefinitionResolver } from './operation-master-resolver';
4
+ import { OperationReadinessResolver } from './operation-readiness-resolver';
4
5
  export declare const entities: (typeof OperationDefinition)[];
5
- export declare const resolvers: (typeof OperationDefinitionResolver | typeof OperationQuery)[];
6
+ export declare const resolvers: (typeof OperationDefinitionResolver | typeof OperationQuery | typeof OperationReadinessResolver)[];
@@ -4,6 +4,7 @@ exports.resolvers = exports.entities = void 0;
4
4
  const operation_definition_1 = require("./operation-definition");
5
5
  const operation_query_1 = require("./operation-query");
6
6
  const operation_master_resolver_1 = require("./operation-master-resolver");
7
+ const operation_readiness_resolver_1 = require("./operation-readiness-resolver");
7
8
  exports.entities = [operation_definition_1.OperationDefinition];
8
- exports.resolvers = [operation_query_1.OperationQuery, operation_master_resolver_1.OperationDefinitionResolver];
9
+ exports.resolvers = [operation_query_1.OperationQuery, operation_master_resolver_1.OperationDefinitionResolver, operation_readiness_resolver_1.OperationReadinessResolver];
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/operation/index.ts"],"names":[],"mappings":";;;AAAA,iEAA4D;AAC5D,uDAAkD;AAClD,2EAAyE;AAE5D,QAAA,QAAQ,GAAG,CAAC,0CAAmB,CAAC,CAAA;AAChC,QAAA,SAAS,GAAG,CAAC,gCAAc,EAAE,uDAA2B,CAAC,CAAA","sourcesContent":["import { OperationDefinition } from './operation-definition'\nimport { OperationQuery } from './operation-query'\nimport { OperationDefinitionResolver } from './operation-master-resolver'\n\nexport const entities = [OperationDefinition]\nexport const resolvers = [OperationQuery, OperationDefinitionResolver]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/operation/index.ts"],"names":[],"mappings":";;;AAAA,iEAA4D;AAC5D,uDAAkD;AAClD,2EAAyE;AACzE,iFAA2E;AAE9D,QAAA,QAAQ,GAAG,CAAC,0CAAmB,CAAC,CAAA;AAChC,QAAA,SAAS,GAAG,CAAC,gCAAc,EAAE,uDAA2B,EAAE,yDAA0B,CAAC,CAAA","sourcesContent":["import { OperationDefinition } from './operation-definition'\nimport { OperationQuery } from './operation-query'\nimport { OperationDefinitionResolver } from './operation-master-resolver'\nimport { OperationReadinessResolver } from './operation-readiness-resolver'\n\nexport const entities = [OperationDefinition]\nexport const resolvers = [OperationQuery, OperationDefinitionResolver, OperationReadinessResolver]\n"]}
@@ -14,7 +14,7 @@ export declare class OperationDefinition {
14
14
  readonly id: string;
15
15
  domain?: Domain;
16
16
  domainId?: string;
17
- /** 공정 키 — 라우트의 단계가 이 값을 가리킨다. */
17
+ /** 공정 키 — 라우팅의 단계가 이 값을 가리킨다. */
18
18
  name: string;
19
19
  description?: string;
20
20
  /** 무엇을 하는 공정인가 — `transport` · `process` · `dwell`. */
@@ -70,22 +70,22 @@ tslib_1.__decorate([
70
70
  ], OperationDefinition.prototype, "duration", void 0);
71
71
  tslib_1.__decorate([
72
72
  (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
73
- (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'DurationVariability as JSON text' }),
73
+ (0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'DurationVariability' }),
74
74
  tslib_1.__metadata("design:type", Object)
75
75
  ], OperationDefinition.prototype, "variability", void 0);
76
76
  tslib_1.__decorate([
77
77
  (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
78
- (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'OperationParameter[] as JSON text' }),
78
+ (0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'OperationParameter[]' }),
79
79
  tslib_1.__metadata("design:type", Array)
80
80
  ], OperationDefinition.prototype, "parameters", void 0);
81
81
  tslib_1.__decorate([
82
82
  (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
83
- (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'PersonnelSpecification[] as JSON text' }),
83
+ (0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'PersonnelSpecification[]' }),
84
84
  tslib_1.__metadata("design:type", Array)
85
85
  ], OperationDefinition.prototype, "personnelSpecification", void 0);
86
86
  tslib_1.__decorate([
87
87
  (0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
88
- (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'PhysicalAssetSpecification[] as JSON text' }),
88
+ (0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'PhysicalAssetSpecification[]' }),
89
89
  tslib_1.__metadata("design:type", Array)
90
90
  ], OperationDefinition.prototype, "physicalAssetSpecification", void 0);
91
91
  tslib_1.__decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"operation-definition.js","sourceRoot":"","sources":["../../../server/service/operation/operation-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * 공정 정의 — **ISA-95 `OperationsSegment`**(`OperationsDefinition` 소속).\n *\n * 이 자리가 답하는 것은 「이 공정이 얼마나 걸리고 무엇을 필요로 하는가」다. 예측이 쓰는 소요시간의\n * 근거이고, 정상상태 상한과 병목을 공정별로 낼 수 있게 하는 값이다.\n *\n * ── 필요 자원을 적지 않으면 사람이 없는 공장이 된다 ─────────────────────────\n * 인원 명세가 없으면 사람은 예측에 존재하지 않는다. 설비만 있으면 언제나 가동되는 공장이 되고, 현장에서\n * 가장 자주 모자라는 자원이 만드는 줄이 통째로 사라진다. 등급으로 요구한다 — 「용접 자격자 2명」.\n */\n@Entity({ name: 'ops_operation_definition' })\n@Index('ix_ops_operation_definition_0', (operation: OperationDefinition) => [operation.domain, operation.name], {\n unique: true\n})\n@ObjectType({ description: 'ISA-95 OperationsSegment — what an operation takes and requires' })\nexport class OperationDefinition {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((operation: OperationDefinition) => operation.domain)\n domainId?: string\n\n /** 공정 키 — 라우트의 단계가 이 값을 가리킨다. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /** 무엇을 하는 공정인가 — `transport` · `process` · `dwell`. */\n @Column()\n @Field()\n intent: string\n\n /** 이 공정이 벌어지는 자리 타입. 없으면 커널이 어디서 일하는지 정할 수 없다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n locationType?: string\n\n /** 필요한 설비 종류. `dwell` 은 자원을 잡지 않는다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n resourceType?: string\n\n /** 방출할 CBV bizStep URN. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n bizStep?: string\n\n /** 소요시간 — 표준 `Duration`. ISO 8601 기간 표기다. 없으면 커널이 기본값을 쓴다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n duration?: string\n\n /** 소요시간 변동 — 표준 밖 확장. 없으면 상수다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'DurationVariability as JSON text' })\n variability?: Record<string, unknown>\n\n /** 공정 모수 — 표준 `ParameterSpecification`. 수율 · 셋업 시간 · 온도가 여기 온다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'OperationParameter[] as JSON text' })\n parameters?: Record<string, unknown>[]\n\n /** 필요 인원 — 표준 `PersonnelSpecification`(등급 + 수량). */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'PersonnelSpecification[] as JSON text' })\n personnelSpecification?: Record<string, unknown>[]\n\n /** 필요 물리 자산 — 표준 `PhysicalAssetSpecification`. 빈 팔레트가 없어 출고가 못 나가는 일은 잦다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => String, { nullable: true, description: 'PhysicalAssetSpecification[] as JSON text' })\n physicalAssetSpecification?: Record<string, unknown>[]\n\n /** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /**\n * 언제까지 유효한가 — 표준 `EffectiveEndDate`.\n *\n * **없앨 때 행을 지우지 않고 이 칸을 채운다.** 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((operation: OperationDefinition) => operation.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((operation: OperationDefinition) => operation.updater)\n updaterId?: string\n}\n"]}
1
+ {"version":3,"file":"operation-definition.js","sourceRoot":"","sources":["../../../server/service/operation/operation-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\n\n/**\n * 공정 정의 — **ISA-95 `OperationsSegment`**(`OperationsDefinition` 소속).\n *\n * 이 자리가 답하는 것은 「이 공정이 얼마나 걸리고 무엇을 필요로 하는가」다. 예측이 쓰는 소요시간의\n * 근거이고, 정상상태 상한과 병목을 공정별로 낼 수 있게 하는 값이다.\n *\n * ── 필요 자원을 적지 않으면 사람이 없는 공장이 된다 ─────────────────────────\n * 인원 명세가 없으면 사람은 예측에 존재하지 않는다. 설비만 있으면 언제나 가동되는 공장이 되고, 현장에서\n * 가장 자주 모자라는 자원이 만드는 줄이 통째로 사라진다. 등급으로 요구한다 — 「용접 자격자 2명」.\n */\n@Entity({ name: 'ops_operation_definition' })\n@Index('ix_ops_operation_definition_0', (operation: OperationDefinition) => [operation.domain, operation.name], {\n unique: true\n})\n@ObjectType({ description: 'ISA-95 OperationsSegment — what an operation takes and requires' })\nexport class OperationDefinition {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((operation: OperationDefinition) => operation.domain)\n domainId?: string\n\n /** 공정 키 — 라우팅의 단계가 이 값을 가리킨다. */\n @Column()\n @Field()\n name: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n /** 무엇을 하는 공정인가 — `transport` · `process` · `dwell`. */\n @Column()\n @Field()\n intent: string\n\n /** 이 공정이 벌어지는 자리 타입. 없으면 커널이 어디서 일하는지 정할 수 없다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n locationType?: string\n\n /** 필요한 설비 종류. `dwell` 은 자원을 잡지 않는다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n resourceType?: string\n\n /** 방출할 CBV bizStep URN. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n bizStep?: string\n\n /** 소요시간 — 표준 `Duration`. ISO 8601 기간 표기다. 없으면 커널이 기본값을 쓴다. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n duration?: string\n\n /** 소요시간 변동 — 표준 밖 확장. 없으면 상수다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'DurationVariability' })\n variability?: Record<string, unknown>\n\n /** 공정 모수 — 표준 `ParameterSpecification`. 수율 · 셋업 시간 · 온도가 여기 온다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'OperationParameter[]' })\n parameters?: Record<string, unknown>[]\n\n /** 필요 인원 — 표준 `PersonnelSpecification`(등급 + 수량). */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'PersonnelSpecification[]' })\n personnelSpecification?: Record<string, unknown>[]\n\n /** 필요 물리 자산 — 표준 `PhysicalAssetSpecification`. 빈 팔레트가 없어 출고가 못 나가는 일은 잦다. */\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'PhysicalAssetSpecification[]' })\n physicalAssetSpecification?: Record<string, unknown>[]\n\n /** 언제부터 유효한가 — 표준 `EffectiveStartDate`. */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveStart?: Date\n\n /**\n * 언제까지 유효한가 — 표준 `EffectiveEndDate`.\n *\n * **없앨 때 행을 지우지 않고 이 칸을 채운다.** 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n */\n @Column({ nullable: true })\n @Field({ nullable: true })\n effectiveEnd?: Date\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((operation: OperationDefinition) => operation.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((operation: OperationDefinition) => operation.updater)\n updaterId?: string\n}\n"]}
@@ -17,6 +17,30 @@ export declare class OperationDefinitionList {
17
17
  }
18
18
  export declare class OperationDefinitionResolver {
19
19
  operationDefinitions(params: ListParam, context: ResolverContext): Promise<OperationDefinitionList>;
20
+ /**
21
+ * 이 공정을 단계로 갖는 **라우팅들.**
22
+ *
23
+ * 공정을 고치기 전에 무엇이 딸려 오는지 여기서 본다. 여럿일 수 있다 — 같은 공정을 여러 라우팅이
24
+ * 지난다(절단은 표준에도 빠른 것에도 있다).
25
+ *
26
+ * 아무도 안 쓰면 빈 목록이다. 다만 그것이 「안 쓴다」인지 「다 못 봤다」인지는
27
+ * `referrerScanCapped` 가 말한다.
28
+ */
29
+ usedInRoutes(operation: OperationDefinition, context: ResolverContext): Promise<string[]>;
30
+ /**
31
+ * 이 공정에서 자재를 넣는 **제조법들.**
32
+ *
33
+ * 라우팅은 「어디를 지나나」이고 이것은 「거기서 무엇이 빠지나」다. 공정을 없애면 그 자재가
34
+ * 빠질 자리를 잃는다.
35
+ */
36
+ consumedAt(operation: OperationDefinition, context: ResolverContext): Promise<string[]>;
37
+ /**
38
+ * 라우팅·제조법을 다 보지 못했나.
39
+ *
40
+ * **조용히 자르지 않는다.** 상한에 걸리면 위의 두 칸이 덜 찬 답이고, 그것을 말하지 않으면
41
+ * 「쓰는 데가 없다」와 「못 봤다」가 같아 보인다.
42
+ */
43
+ referrerScanCapped(operation: OperationDefinition, context: ResolverContext): Promise<boolean>;
20
44
  /**
21
45
  * 그리드가 보낸 변경을 한 번에 적용한다.
22
46
  *
@@ -8,6 +8,9 @@ const master_crud_1 = require("../master-crud");
8
8
  const master_axis_1 = require("../master-axis");
9
9
  const master_list_1 = require("../master-list");
10
10
  const operation_definition_1 = require("./operation-definition");
11
+ const recipe_definition_1 = require("../recipe/recipe-definition");
12
+ const route_definition_1 = require("../recipe/route-definition");
13
+ const referrers_1 = require("../resource/referrers");
11
14
  /**
12
15
  * 공정 축을 채우고 고친다.
13
16
  *
@@ -32,12 +35,92 @@ tslib_1.__decorate([
32
35
  exports.OperationDefinitionList = OperationDefinitionList = tslib_1.__decorate([
33
36
  (0, type_graphql_1.ObjectType)({ description: 'A page of operation definitions' })
34
37
  ], OperationDefinitionList);
38
+ /**
39
+ * **이 공정을 누가 쓰나** — 들어오는 관계.
40
+ *
41
+ * ── 왜 필요한가 ────────────────────────────────────────────────────────────
42
+ * 공정 하나를 고치거나 없앨 때 무엇이 딸려 무너지는지 알 수 없었다. 라우팅과 제조법을 하나씩 열어
43
+ * 단계 목록을 눈으로 훑는 수밖에 없었다. 지금 miratek 은 라우팅 다섯에 제조법 다섯이라 그것이
44
+ * 되지만, 제품이 늘면 안 된다.
45
+ *
46
+ * ── 배열 칸이라 훑는다 ─────────────────────────────────────────────────────
47
+ * `RouteDefinition.steps` 와 `RecipeDefinition.inputs[].operation` 은 `simple-json` 이다.
48
+ * 데이터베이스가 그 안을 못 보므로 `IN` 으로 못 좁힌다. 표를 훑어 뒤집는 수밖에 없다.
49
+ *
50
+ * **그래서 상한이 있고, 상한에 걸리면 말한다**(`referrerScanCapped`). 조용히 자르면 「이 공정을
51
+ * 아무도 안 쓴다」와 「너무 많아 다 못 봤다」가 같아 보인다. 앞엣것은 지워도 되는 공정이고
52
+ * 뒤엣것은 지우면 라인이 선다. 품목의 제조법 훑기가 같은 자리에 같은 것을 둔다.
53
+ */
54
+ const OPERATION_SCAN_LIMIT = 2000;
55
+ async function scanOperationUse(domain) {
56
+ const routeRepo = (0, shell_1.getRepository)(route_definition_1.RouteDefinition);
57
+ const recipeRepo = (0, shell_1.getRepository)(recipe_definition_1.RecipeDefinition);
58
+ const [routeTotal, recipeTotal] = await Promise.all([
59
+ routeRepo.count({ where: { domain: { id: domain.id } } }),
60
+ recipeRepo.count({ where: { domain: { id: domain.id } } })
61
+ ]);
62
+ const [routeRows, recipeRows] = await Promise.all([
63
+ /*
64
+ * `id` 를 함께 뽑는다. 빼면 TypeORM 이 「no such column: distinctAlias.…_id」로 터진다 —
65
+ * `take` 를 쓰면 중복 제거를 위해 기본 키로 한 번 더 감싸는데, 그 키를 안 뽑으면 감쌀 것이 없다.
66
+ */
67
+ routeRepo.find({
68
+ where: { domain: { id: domain.id } },
69
+ select: ['id', 'name', 'steps'],
70
+ take: OPERATION_SCAN_LIMIT
71
+ }),
72
+ recipeRepo.find({
73
+ where: { domain: { id: domain.id } },
74
+ select: ['id', 'name', 'inputs'],
75
+ take: OPERATION_SCAN_LIMIT
76
+ })
77
+ ]);
78
+ const routes = (0, referrers_1.indexMultiReferrers)(routeRows, one => one.steps ?? [], one => one.name);
79
+ const recipes = (0, referrers_1.indexMultiReferrers)(recipeRows, one => (one.inputs ?? []).map((part) => part?.operation), one => one.name);
80
+ return { routes, recipes, capped: routeTotal > routeRows.length || recipeTotal > recipeRows.length };
81
+ }
82
+ /** 요청 안에서 한 번만 훑는다. **약속을 담는다** — 줄들이 거의 동시에 묻는다. */
83
+ function operationUseOf(context) {
84
+ const state = context.state;
85
+ state.operationUse = state.operationUse || scanOperationUse(state.domain);
86
+ return state.operationUse;
87
+ }
35
88
  let OperationDefinitionResolver = class OperationDefinitionResolver {
36
89
  async operationDefinitions(params, context) {
37
90
  const { domain } = context.state;
38
91
  const { items, total } = await (0, master_list_1.listMaster)('operationDefinition', params, domain);
39
92
  return { items: items, total };
40
93
  }
94
+ /**
95
+ * 이 공정을 단계로 갖는 **라우팅들.**
96
+ *
97
+ * 공정을 고치기 전에 무엇이 딸려 오는지 여기서 본다. 여럿일 수 있다 — 같은 공정을 여러 라우팅이
98
+ * 지난다(절단은 표준에도 빠른 것에도 있다).
99
+ *
100
+ * 아무도 안 쓰면 빈 목록이다. 다만 그것이 「안 쓴다」인지 「다 못 봤다」인지는
101
+ * `referrerScanCapped` 가 말한다.
102
+ */
103
+ async usedInRoutes(operation, context) {
104
+ return (await operationUseOf(context)).routes.get(operation.name) ?? [];
105
+ }
106
+ /**
107
+ * 이 공정에서 자재를 넣는 **제조법들.**
108
+ *
109
+ * 라우팅은 「어디를 지나나」이고 이것은 「거기서 무엇이 빠지나」다. 공정을 없애면 그 자재가
110
+ * 빠질 자리를 잃는다.
111
+ */
112
+ async consumedAt(operation, context) {
113
+ return (await operationUseOf(context)).recipes.get(operation.name) ?? [];
114
+ }
115
+ /**
116
+ * 라우팅·제조법을 다 보지 못했나.
117
+ *
118
+ * **조용히 자르지 않는다.** 상한에 걸리면 위의 두 칸이 덜 찬 답이고, 그것을 말하지 않으면
119
+ * 「쓰는 데가 없다」와 「못 봤다」가 같아 보인다.
120
+ */
121
+ async referrerScanCapped(operation, context) {
122
+ return (await operationUseOf(context)).capped;
123
+ }
41
124
  /**
42
125
  * 그리드가 보낸 변경을 한 번에 적용한다.
43
126
  *
@@ -64,6 +147,30 @@ tslib_1.__decorate([
64
147
  tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
65
148
  tslib_1.__metadata("design:returntype", Promise)
66
149
  ], OperationDefinitionResolver.prototype, "operationDefinitions", null);
150
+ tslib_1.__decorate([
151
+ (0, type_graphql_1.FieldResolver)(type => [String], { description: 'Routes that include this operation as a step' }),
152
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
153
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
154
+ tslib_1.__metadata("design:type", Function),
155
+ tslib_1.__metadata("design:paramtypes", [operation_definition_1.OperationDefinition, Object]),
156
+ tslib_1.__metadata("design:returntype", Promise)
157
+ ], OperationDefinitionResolver.prototype, "usedInRoutes", null);
158
+ tslib_1.__decorate([
159
+ (0, type_graphql_1.FieldResolver)(type => [String], { description: 'Recipes that consume materials at this operation' }),
160
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
161
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
162
+ tslib_1.__metadata("design:type", Function),
163
+ tslib_1.__metadata("design:paramtypes", [operation_definition_1.OperationDefinition, Object]),
164
+ tslib_1.__metadata("design:returntype", Promise)
165
+ ], OperationDefinitionResolver.prototype, "consumedAt", null);
166
+ tslib_1.__decorate([
167
+ (0, type_graphql_1.FieldResolver)(type => Boolean, { description: 'True when routes or recipes were too many to scan fully' }),
168
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
169
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
170
+ tslib_1.__metadata("design:type", Function),
171
+ tslib_1.__metadata("design:paramtypes", [operation_definition_1.OperationDefinition, Object]),
172
+ tslib_1.__metadata("design:returntype", Promise)
173
+ ], OperationDefinitionResolver.prototype, "referrerScanCapped", null);
67
174
  tslib_1.__decorate([
68
175
  (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
69
176
  (0, type_graphql_1.Directive)('@transaction'),
@@ -1 +1 @@
1
- {"version":3,"file":"operation-master-resolver.js","sourceRoot":"","sources":["../../../server/service/operation/operation-master-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAA2G;AAE3G,iDAA+D;AAE/D,gDAA+D;AAC/D,gDAA6C;AAC7C,gDAA2C;AAC3C,iEAA4D;AAE5D;;;;;;;;;GASG;AAGI,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;CAMnC,CAAA;AANY,0DAAuB;AAElC;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,0CAAmB,CAAC,CAAC;;sDACT;AAG5B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,CAAC;;sDACN;kCALF,uBAAuB;IADnC,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,iCAAiC,EAAE,CAAC;GAClD,uBAAuB,CAMnC;AAGM,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAGhC,AAAN,KAAK,CAAC,oBAAoB,CAA0B,MAAiB,EAAS,OAAwB;QACpG,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAChC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,IAAA,wBAAU,EAAC,qBAAqB,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAEhF,OAAO,EAAE,KAAK,EAAE,KAA8B,EAAE,KAAK,EAAE,CAAA;IACzD,CAAC;IAED;;;;;;OAMG;IAIG,AAAN,KAAK,CAAC,iCAAiC,CACG,OAAsB,EACvD,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1C,MAAM,IAAI,GAAG,IAAA,0BAAY,EAAC,qBAAqB,CAAC,CAAA;QAEhD,MAAM,KAAK,GAAG,MAAM,IAAA,+BAAiB,EAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;YAC5E,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC5C,CAAC,CAAA;QAEF,OAAO,KAA8B,CAAA;IACvC,CAAC;CACF,CAAA;AAjCY,kEAA2B;AAGhC;IAFL,IAAA,wBAAS,EAAC,kFAAkF,CAAC;IAC7F,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC;IACjE,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IAAqB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAjB,iBAAS;;uEAKpE;AAYK;IAHL,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,0CAAmB,CAAC,EAAE,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;IAE9G,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,oBAAY,CAAC,CAAC,CAAA;IACtC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;oFAUP;sCAhCU,2BAA2B;IADvC,IAAA,uBAAQ,EAAC,0CAAmB,CAAC;GACjB,2BAA2B,CAiCvC","sourcesContent":["import { Args, Arg, Ctx, Directive, Int, Mutation, ObjectType, Field, Query, Resolver } from 'type-graphql'\n\nimport { ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { OperationDefinition } from './operation-definition'\n\n/**\n * 공정 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operation definitions' })\nexport class OperationDefinitionList {\n @Field(type => [OperationDefinition])\n items: OperationDefinition[]\n\n @Field(type => Int)\n total: number\n}\n\n@Resolver(OperationDefinition)\nexport class OperationDefinitionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationDefinitionList, { description: 'To fetch operation definitions' })\n async operationDefinitions(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationDefinitionList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationDefinition', params, domain)\n\n return { items: items as OperationDefinition[], total }\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [OperationDefinition], { description: 'To create, change or retire operation definitions' })\n async updateMultipleOperationDefinition(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<OperationDefinition[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationDefinition')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as OperationDefinition[]\n }\n}\n"]}
1
+ {"version":3,"file":"operation-master-resolver.js","sourceRoot":"","sources":["../../../server/service/operation/operation-master-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Args, Arg, Ctx, Directive, FieldResolver, Int, Mutation, ObjectType, Field, Query, Resolver, Root } from 'type-graphql'\n\nimport { Domain, ListParam, ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { MasterPatch, saveMasterPatches } from '../master-crud'\nimport { masterAxisOf } from '../master-axis'\nimport { listMaster } from '../master-list'\nimport { OperationDefinition } from './operation-definition'\nimport { RecipeDefinition } from '../recipe/recipe-definition'\nimport { RouteDefinition } from '../recipe/route-definition'\nimport { indexMultiReferrers } from '../resource/referrers'\n\n/**\n * 공정 축을 채우고 고친다.\n *\n * ── 왜 마스터는 그리드에서 고칠 수 있나 ────────────────────────────────────\n * 업무 기록과 달리 마스터는 **선언**이다. 「이 사람이 용접 자격을 갖는다」는 일어난 일이 아니라 지금의\n * 규정이고, 규정은 바뀐다. 없앨 때 행을 지우지 않고 유효 기간의 끝을 채우는 것이 그래서다 —\n * 지우면 그것을 가리키는 지난 기록이 가리킬 것을 잃는다.\n *\n * 규칙은 `master-crud.ts` 한 곳에 있다. 여기는 축의 이름만 붙인다.\n */\n\n@ObjectType({ description: 'A page of operation definitions' })\nexport class OperationDefinitionList {\n @Field(type => [OperationDefinition])\n items: OperationDefinition[]\n\n @Field(type => Int)\n total: number\n}\n\n/**\n * **이 공정을 누가 쓰나** — 들어오는 관계.\n *\n * ── 왜 필요한가 ────────────────────────────────────────────────────────────\n * 공정 하나를 고치거나 없앨 때 무엇이 딸려 무너지는지 알 수 없었다. 라우팅과 제조법을 하나씩 열어\n * 단계 목록을 눈으로 훑는 수밖에 없었다. 지금 miratek 은 라우팅 다섯에 제조법 다섯이라 그것이\n * 되지만, 제품이 늘면 안 된다.\n *\n * ── 배열 칸이라 훑는다 ─────────────────────────────────────────────────────\n * `RouteDefinition.steps` 와 `RecipeDefinition.inputs[].operation` 은 `simple-json` 이다.\n * 데이터베이스가 그 안을 못 보므로 `IN` 으로 못 좁힌다. 표를 훑어 뒤집는 수밖에 없다.\n *\n * **그래서 상한이 있고, 상한에 걸리면 말한다**(`referrerScanCapped`). 조용히 자르면 「이 공정을\n * 아무도 안 쓴다」와 「너무 많아 다 못 봤다」가 같아 보인다. 앞엣것은 지워도 되는 공정이고\n * 뒤엣것은 지우면 라인이 선다. 품목의 제조법 훑기가 같은 자리에 같은 것을 둔다.\n */\nconst OPERATION_SCAN_LIMIT = 2000\n\ninterface OperationUse {\n /** 이 공정을 단계로 갖는 라우팅들. */\n routes: Map<string, string[]>\n /** 이 공정에서 자재를 넣는 제조법들. */\n recipes: Map<string, string[]>\n /** 상한에 걸려 다 보지 못했나. */\n capped: boolean\n}\n\nasync function scanOperationUse(domain: Domain): Promise<OperationUse> {\n const routeRepo = getRepository(RouteDefinition)\n const recipeRepo = getRepository(RecipeDefinition)\n\n const [routeTotal, recipeTotal] = await Promise.all([\n routeRepo.count({ where: { domain: { id: domain.id } } as any }),\n recipeRepo.count({ where: { domain: { id: domain.id } } as any })\n ])\n\n const [routeRows, recipeRows] = await Promise.all([\n /*\n * `id` 를 함께 뽑는다. 빼면 TypeORM 이 「no such column: distinctAlias.…_id」로 터진다 —\n * `take` 를 쓰면 중복 제거를 위해 기본 키로 한 번 더 감싸는데, 그 키를 안 뽑으면 감쌀 것이 없다.\n */\n routeRepo.find({\n where: { domain: { id: domain.id } } as any,\n select: ['id', 'name', 'steps'] as any,\n take: OPERATION_SCAN_LIMIT\n }),\n recipeRepo.find({\n where: { domain: { id: domain.id } } as any,\n select: ['id', 'name', 'inputs'] as any,\n take: OPERATION_SCAN_LIMIT\n })\n ])\n\n const routes = indexMultiReferrers(\n routeRows as any[],\n one => one.steps ?? [],\n one => one.name\n )\n\n const recipes = indexMultiReferrers(\n recipeRows as any[],\n one => (one.inputs ?? []).map((part: any) => part?.operation),\n one => one.name\n )\n\n return { routes, recipes, capped: routeTotal > routeRows.length || recipeTotal > recipeRows.length }\n}\n\n/** 요청 안에서 한 번만 훑는다. **약속을 담는다** — 줄들이 거의 동시에 묻는다. */\nfunction operationUseOf(context: ResolverContext): Promise<OperationUse> {\n const state = context.state as { domain: Domain; operationUse?: Promise<OperationUse> }\n\n state.operationUse = state.operationUse || scanOperationUse(state.domain)\n\n return state.operationUse\n}\n\n@Resolver(OperationDefinition)\nexport class OperationDefinitionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => OperationDefinitionList, { description: 'To fetch operation definitions' })\n async operationDefinitions(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<OperationDefinitionList> {\n const { domain } = context.state\n const { items, total } = await listMaster('operationDefinition', params, domain)\n\n return { items: items as OperationDefinition[], total }\n }\n\n /**\n * 이 공정을 단계로 갖는 **라우팅들.**\n *\n * 공정을 고치기 전에 무엇이 딸려 오는지 여기서 본다. 여럿일 수 있다 — 같은 공정을 여러 라우팅이\n * 지난다(절단은 표준에도 빠른 것에도 있다).\n *\n * 아무도 안 쓰면 빈 목록이다. 다만 그것이 「안 쓴다」인지 「다 못 봤다」인지는\n * `referrerScanCapped` 가 말한다.\n */\n @FieldResolver(type => [String], { description: 'Routes that include this operation as a step' })\n async usedInRoutes(@Root() operation: OperationDefinition, @Ctx() context: ResolverContext): Promise<string[]> {\n return (await operationUseOf(context)).routes.get(operation.name) ?? []\n }\n\n /**\n * 이 공정에서 자재를 넣는 **제조법들.**\n *\n * 라우팅은 「어디를 지나나」이고 이것은 「거기서 무엇이 빠지나」다. 공정을 없애면 그 자재가\n * 빠질 자리를 잃는다.\n */\n @FieldResolver(type => [String], { description: 'Recipes that consume materials at this operation' })\n async consumedAt(@Root() operation: OperationDefinition, @Ctx() context: ResolverContext): Promise<string[]> {\n return (await operationUseOf(context)).recipes.get(operation.name) ?? []\n }\n\n /**\n * 라우팅·제조법을 다 보지 못했나.\n *\n * **조용히 자르지 않는다.** 상한에 걸리면 위의 두 칸이 덜 찬 답이고, 그것을 말하지 않으면\n * 「쓰는 데가 없다」와 「못 봤다」가 같아 보인다.\n */\n @FieldResolver(type => Boolean, { description: 'True when routes or recipes were too many to scan fully' })\n async referrerScanCapped(@Root() operation: OperationDefinition, @Ctx() context: ResolverContext): Promise<boolean> {\n return (await operationUseOf(context)).capped\n }\n\n /**\n * 그리드가 보낸 변경을 한 번에 적용한다.\n *\n * 패치를 `ScalarObject` 로 받는다 — 축마다 입력 타입을 따로 만들면 칸을 하나 더할 때마다 두 곳을\n * 고쳐야 하고, 한쪽을 빠뜨리면 그 칸이 오류 보고 없이 저장되지 않는다. 돌려주는 것은 타입이 있는\n * 엔티티라 무엇이 저장됐는지 스키마로 확인할 수 있다.\n */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(returns => [OperationDefinition], { description: 'To create, change or retire operation definitions' })\n async updateMultipleOperationDefinition(\n @Arg('patches', type => [ScalarObject]) patches: MasterPatch[],\n @Ctx() context: ResolverContext\n ): Promise<OperationDefinition[]> {\n const { domain, user, tx } = context.state\n const axis = masterAxisOf('operationDefinition')\n\n const saved = await saveMasterPatches(tx, domain, axis.entity, patches, user, {\n hasEffectivePeriod: axis.hasEffectivePeriod\n })\n\n return saved as OperationDefinition[]\n }\n}\n"]}
@@ -1,7 +1,15 @@
1
1
  export declare class OperationMaster {
2
2
  operations: string;
3
+ /**
4
+ * 더 있나 — **이 값을 안 보고 쓰면 조용히 잘린 마스터로 트윈을 세우게 된다.**
5
+ *
6
+ * 거짓이 될 때까지 `next` 를 `after` 로 넘겨 이어 받는다.
7
+ */
8
+ hasMore: boolean;
9
+ /** 이어 받을 자리. 더 없으면 없다. */
10
+ next?: string;
3
11
  }
4
12
  export declare class OperationQuery {
5
- /** 공정 정의 전체 — 라우트의 단계가 이 키를 가리킨다. */
6
- operationMaster(context: ResolverContext): Promise<OperationMaster>;
13
+ /** 공정 정의 전체 — 라우팅의 단계가 이 키를 가리킨다. */
14
+ operationMaster(after: string | undefined, limit: number | undefined, context: ResolverContext): Promise<OperationMaster>;
7
15
  }
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OperationQuery = exports.OperationMaster = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const type_graphql_1 = require("type-graphql");
6
- const shell_1 = require("@things-factory/shell");
6
+ const master_page_query_1 = require("../master-page-query");
7
7
  const operation_definition_1 = require("./operation-definition");
8
8
  const operation_master_1 = require("./operation-master");
9
9
  let OperationMaster = class OperationMaster {
@@ -13,26 +13,41 @@ tslib_1.__decorate([
13
13
  (0, type_graphql_1.Field)(type => String, { description: 'OperationDef[] as JSON text' }),
14
14
  tslib_1.__metadata("design:type", String)
15
15
  ], OperationMaster.prototype, "operations", void 0);
16
+ tslib_1.__decorate([
17
+ (0, type_graphql_1.Field)({ description: 'true when more rows remain — keep pulling with next as after' }),
18
+ tslib_1.__metadata("design:type", Boolean)
19
+ ], OperationMaster.prototype, "hasMore", void 0);
20
+ tslib_1.__decorate([
21
+ (0, type_graphql_1.Field)(type => String, { nullable: true, description: 'cursor for the next page — the last name in this page' }),
22
+ tslib_1.__metadata("design:type", String)
23
+ ], OperationMaster.prototype, "next", void 0);
16
24
  exports.OperationMaster = OperationMaster = tslib_1.__decorate([
17
25
  (0, type_graphql_1.ObjectType)({ description: 'Operation definitions as the twin receives them' })
18
26
  ], OperationMaster);
19
27
  let OperationQuery = class OperationQuery {
20
- /** 공정 정의 전체 — 라우트의 단계가 이 키를 가리킨다. */
21
- async operationMaster(context) {
28
+ /** 공정 정의 전체 — 라우팅의 단계가 이 키를 가리킨다. */
29
+ async operationMaster(after, limit, context) {
22
30
  const { domain } = context.state;
23
- const operations = await (0, shell_1.getRepository)(operation_definition_1.OperationDefinition).find({
24
- where: { domain: { id: domain.id } },
25
- order: { name: 'ASC' }
26
- });
27
- return { operations: JSON.stringify((0, operation_master_1.operationMaster)(operations).operations) };
31
+ const request = { after, limit };
32
+ const page = await (0, master_page_query_1.pullPage)(operation_definition_1.OperationDefinition, domain, request);
33
+ /* 통째로 달라고 했는데 한도를 넘으면 **자르지 않고 거절한다**(§`master-page`). */
34
+ (0, master_page_query_1.refuseIfTooLarge)('공정', request, page);
35
+ const operations = page.rows;
36
+ return {
37
+ operations: JSON.stringify((0, operation_master_1.operationMaster)(operations).operations),
38
+ hasMore: page.hasMore,
39
+ ...(page.next ? { next: page.next } : {})
40
+ };
28
41
  }
29
42
  };
30
43
  exports.OperationQuery = OperationQuery;
31
44
  tslib_1.__decorate([
32
45
  (0, type_graphql_1.Query)(returns => OperationMaster, { description: 'Operation definitions for the twin to pull' }),
33
- tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
46
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('after', { nullable: true, description: 'resume after this name — the previous page\'s next' })),
47
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('limit', type => type_graphql_1.Int, { nullable: true, description: 'rows per page — omit only when the axis is small enough to pull whole' })),
48
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
34
49
  tslib_1.__metadata("design:type", Function),
35
- tslib_1.__metadata("design:paramtypes", [Object]),
50
+ tslib_1.__metadata("design:paramtypes", [String, Number, Object]),
36
51
  tslib_1.__metadata("design:returntype", Promise)
37
52
  ], OperationQuery.prototype, "operationMaster", null);
38
53
  exports.OperationQuery = OperationQuery = tslib_1.__decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"operation-query.js","sourceRoot":"","sources":["../../../server/service/operation/operation-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAsE;AAEtE,iDAAqD;AAErD,iEAA4D;AAC5D,yDAA4E;AAGrE,IAAM,eAAe,GAArB,MAAM,eAAe;CAG3B,CAAA;AAHY,0CAAe;AAE1B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC;;mDACpD;0BAFP,eAAe;IAD3B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;GAClE,eAAe,CAG3B;AAGM,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,qCAAqC;IAE/B,AAAN,KAAK,CAAC,eAAe,CAAQ,OAAwB;QACnD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,0CAAmB,CAAC,CAAC,IAAI,CAAC;YAC/D,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE;YACpC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;SACvB,CAAC,CAAA;QAEF,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,IAAA,kCAAoB,EAAC,UAAU,CAAC,CAAC,UAAU,CAAC,EAAE,CAAA;IACpF,CAAC;CACF,CAAA;AAbY,wCAAc;AAGnB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,eAAe,EAAE,EAAE,WAAW,EAAE,4CAA4C,EAAE,CAAC;IAC1E,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;qDAS3B;yBAZU,cAAc;IAD1B,IAAA,uBAAQ,EAAC,0CAAmB,CAAC;GACjB,cAAc,CAa1B","sourcesContent":["import { Ctx, Field, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { OperationDefinition } from './operation-definition'\nimport { operationMaster as buildOperationMaster } from './operation-master'\n\n@ObjectType({ description: 'Operation definitions as the twin receives them' })\nexport class OperationMaster {\n @Field(type => String, { description: 'OperationDef[] as JSON text' })\n operations: string\n}\n\n@Resolver(OperationDefinition)\nexport class OperationQuery {\n /** 공정 정의 전체 — 라우트의 단계가 이 키를 가리킨다. */\n @Query(returns => OperationMaster, { description: 'Operation definitions for the twin to pull' })\n async operationMaster(@Ctx() context: ResolverContext): Promise<OperationMaster> {\n const { domain } = context.state\n\n const operations = await getRepository(OperationDefinition).find({\n where: { domain: { id: domain.id } },\n order: { name: 'ASC' }\n })\n\n return { operations: JSON.stringify(buildOperationMaster(operations).operations) }\n }\n}\n"]}
1
+ {"version":3,"file":"operation-query.js","sourceRoot":"","sources":["../../../server/service/operation/operation-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAgF;AAIhF,4DAAiE;AAEjE,iEAA4D;AAC5D,yDAA4E;AAGrE,IAAM,eAAe,GAArB,MAAM,eAAe;CAgB3B,CAAA;AAhBY,0CAAe;AAE1B;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC;;mDACpD;AAQlB;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC;;gDACvE;AAIhB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uDAAuD,EAAE,CAAC;;6CACnG;0BAdF,eAAe;IAD3B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,iDAAiD,EAAE,CAAC;GAClE,eAAe,CAgB3B;AAGM,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,qCAAqC;IAE/B,AAAN,KAAK,CAAC,eAAe,CACkF,KAAyB,EACO,KAAyB,EACvJ,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEhC,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAChC,MAAM,IAAI,GAAG,MAAM,IAAA,4BAAQ,EAAsB,0CAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QAEtF,0DAA0D;QAC1D,IAAA,oCAAgB,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAErC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAA;QAE5B,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,IAAA,kCAAoB,EAAC,UAAU,CAAC,CAAC,UAAU,CAAC;YACvE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAA;IACH,CAAC;CACF,CAAA;AAxBY,wCAAc;AAGnB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,eAAe,EAAE,EAAE,WAAW,EAAE,4CAA4C,EAAE,CAAC;IAE9F,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC,CAAA;IACnG,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uEAAuE,EAAE,CAAC,CAAA;IACnI,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;qDAiBP;yBAvBU,cAAc;IAD1B,IAAA,uBAAQ,EAAC,0CAAmB,CAAC;GACjB,cAAc,CAwB1B","sourcesContent":["import { Arg, Ctx, Field, Int, ObjectType, Query, Resolver } from 'type-graphql'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { pullPage, refuseIfTooLarge } from '../master-page-query'\n\nimport { OperationDefinition } from './operation-definition'\nimport { operationMaster as buildOperationMaster } from './operation-master'\n\n@ObjectType({ description: 'Operation definitions as the twin receives them' })\nexport class OperationMaster {\n @Field(type => String, { description: 'OperationDef[] as JSON text' })\n operations: string\n\n /**\n * 더 있나 — **이 값을 안 보고 쓰면 조용히 잘린 마스터로 트윈을 세우게 된다.**\n *\n * 거짓이 될 때까지 `next` 를 `after` 로 넘겨 이어 받는다.\n */\n @Field({ description: 'true when more rows remain — keep pulling with next as after' })\n hasMore: boolean\n\n /** 이어 받을 자리. 더 없으면 없다. */\n @Field(type => String, { nullable: true, description: 'cursor for the next page — the last name in this page' })\n next?: string\n\n}\n\n@Resolver(OperationDefinition)\nexport class OperationQuery {\n /** 공정 정의 전체 — 라우팅의 단계가 이 키를 가리킨다. */\n @Query(returns => OperationMaster, { description: 'Operation definitions for the twin to pull' })\n async operationMaster(\n @Arg('after', { nullable: true, description: 'resume after this name — the previous page\\'s next' }) after: string | undefined,\n @Arg('limit', type => Int, { nullable: true, description: 'rows per page — omit only when the axis is small enough to pull whole' }) limit: number | undefined,\n @Ctx() context: ResolverContext\n ): Promise<OperationMaster> {\n const { domain } = context.state\n\n const request = { after, limit }\n const page = await pullPage<OperationDefinition>(OperationDefinition, domain, request)\n\n /* 통째로 달라고 했는데 한도를 넘으면 **자르지 않고 거절한다**(§`master-page`). */\n refuseIfTooLarge('공정', request, page)\n\n const operations = page.rows\n\n return {\n operations: JSON.stringify(buildOperationMaster(operations).operations),\n hasMore: page.hasMore,\n ...(page.next ? { next: page.next } : {})\n }\n }\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { OperationDefinition } from './operation-definition';
2
+ export declare class PersonnelReadinessType {
3
+ classId: string;
4
+ required: number;
5
+ qualified: number;
6
+ /** 곧 끊기는 것을 따로 센다 — 합쳐 세면 만료가 닥쳐서야 알게 된다. */
7
+ expiringSoon: number;
8
+ sample: string[];
9
+ }
10
+ export declare class AssetReadinessType {
11
+ classId: string;
12
+ required: number;
13
+ /** 수명과 교정은 세지 않는다 — 이 화면이 답하는 물음은 「채울 자산이 있나」다. */
14
+ registered: number;
15
+ }
16
+ export declare class OperationReadinessType {
17
+ operation: OperationDefinition;
18
+ personnel: PersonnelReadinessType[];
19
+ assets: AssetReadinessType[];
20
+ /** 품목당 표준 시간(분). 선언되지 않았으면 없다 — 0 으로 두면 「즉시 끝난다」가 된다. */
21
+ standardMinutes?: number;
22
+ peopleTotal: number;
23
+ /**
24
+ * 그중 자격을 실제로 확인한 수.
25
+ *
26
+ * `peopleTotal` 보다 작으면 잘린 것이다. 화면이 그 사실을 말해야 한다 — 자른 것을 말하지 않으면
27
+ * 「자격자 3명」이 실제로는 더 많을 수 있다.
28
+ */
29
+ peopleScanned: number;
30
+ }
31
+ /**
32
+ * 선언 옆에 현실을 놓는다.
33
+ *
34
+ * 「용접 자격자 2명이 필요하다」는 선언이고, 그 선언이 지금 채워지는지는 다른 곳에 있었다. 두 화면을
35
+ * 오가며 사람이 머릿속으로 맞춰야 했고, 맞춰 보지 않으면 아무도 몰랐다.
36
+ */
37
+ export declare class OperationReadinessResolver {
38
+ operationReadiness(name: string, context: ResolverContext): Promise<OperationReadinessType | undefined>;
39
+ }