@things-factory/kpi 10.1.248 → 10.1.249

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 (409) hide show
  1. package/dist-client/bootstrap.d.ts +2 -0
  2. package/dist-client/bootstrap.js +7 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/charts/kpi-boxplot-chart.d.ts +24 -0
  5. package/dist-client/charts/kpi-boxplot-chart.js +324 -0
  6. package/dist-client/charts/kpi-boxplot-chart.js.map +1 -0
  7. package/dist-client/charts/kpi-mini-trend-chart.d.ts +14 -0
  8. package/dist-client/charts/kpi-mini-trend-chart.js +148 -0
  9. package/dist-client/charts/kpi-mini-trend-chart.js.map +1 -0
  10. package/dist-client/charts/kpi-radar-chart.d.ts +16 -0
  11. package/dist-client/charts/kpi-radar-chart.js +138 -0
  12. package/dist-client/charts/kpi-radar-chart.js.map +1 -0
  13. package/dist-client/charts/kpi-trend-chart.d.ts +25 -0
  14. package/dist-client/charts/kpi-trend-chart.js +186 -0
  15. package/dist-client/charts/kpi-trend-chart.js.map +1 -0
  16. package/dist-client/google-map/common-google-map.d.ts +34 -0
  17. package/dist-client/google-map/common-google-map.js +333 -0
  18. package/dist-client/google-map/common-google-map.js.map +1 -0
  19. package/dist-client/google-map/google-map-loader.d.ts +8 -0
  20. package/dist-client/google-map/google-map-loader.js +22 -0
  21. package/dist-client/google-map/google-map-loader.js.map +1 -0
  22. package/dist-client/index.d.ts +1 -0
  23. package/dist-client/index.js +2 -0
  24. package/dist-client/index.js.map +1 -0
  25. package/dist-client/pages/kpi/kpi-grade-editor.d.ts +35 -0
  26. package/dist-client/pages/kpi/kpi-grade-editor.js +165 -0
  27. package/dist-client/pages/kpi/kpi-grade-editor.js.map +1 -0
  28. package/dist-client/pages/kpi/kpi-importer.d.ts +23 -0
  29. package/dist-client/pages/kpi/kpi-importer.js +92 -0
  30. package/dist-client/pages/kpi/kpi-importer.js.map +1 -0
  31. package/dist-client/pages/kpi/kpi-list-page.d.ts +136 -0
  32. package/dist-client/pages/kpi/kpi-list-page.js +948 -0
  33. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -0
  34. package/dist-client/pages/kpi/kpi-overview-sample.d.ts +36 -0
  35. package/dist-client/pages/kpi/kpi-overview-sample.js +264 -0
  36. package/dist-client/pages/kpi/kpi-overview-sample.js.map +1 -0
  37. package/dist-client/pages/kpi/kpi-overview.d.ts +14 -0
  38. package/dist-client/pages/kpi/kpi-overview.js +361 -0
  39. package/dist-client/pages/kpi/kpi-overview.js.map +1 -0
  40. package/dist-client/pages/kpi/kpi-tree-page.d.ts +51 -0
  41. package/dist-client/pages/kpi/kpi-tree-page.js +355 -0
  42. package/dist-client/pages/kpi/kpi-tree-page.js.map +1 -0
  43. package/dist-client/pages/kpi/kpi-view.d.ts +12 -0
  44. package/dist-client/pages/kpi/kpi-view.js +193 -0
  45. package/dist-client/pages/kpi/kpi-view.js.map +1 -0
  46. package/dist-client/pages/kpi/kpi-viz-editor.d.ts +19 -0
  47. package/dist-client/pages/kpi/kpi-viz-editor.js +562 -0
  48. package/dist-client/pages/kpi/kpi-viz-editor.js.map +1 -0
  49. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +17 -0
  50. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +279 -0
  51. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  52. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +19 -0
  53. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +385 -0
  54. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  55. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +23 -0
  56. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +465 -0
  57. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  58. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  59. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  60. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  61. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +24 -0
  62. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +440 -0
  63. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  64. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +33 -0
  65. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +444 -0
  66. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  67. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +23 -0
  68. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +369 -0
  69. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  70. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  71. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +128 -0
  72. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  73. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +31 -0
  74. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +493 -0
  75. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  76. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +50 -0
  77. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +884 -0
  78. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  79. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  80. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  81. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  82. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  83. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  84. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  85. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  86. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  87. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  88. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  89. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +146 -0
  90. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  91. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  92. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  93. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  94. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +21 -0
  95. package/dist-client/pages/kpi-history/kpi-history-list-page.js +160 -0
  96. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -0
  97. package/dist-client/pages/kpi-metric/kpi-metric-importer.d.ts +23 -0
  98. package/dist-client/pages/kpi-metric/kpi-metric-importer.js +92 -0
  99. package/dist-client/pages/kpi-metric/kpi-metric-importer.js.map +1 -0
  100. package/dist-client/pages/kpi-metric/kpi-metric-list-page.d.ts +65 -0
  101. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +415 -0
  102. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -0
  103. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +52 -0
  104. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +678 -0
  105. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  106. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  107. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +75 -0
  108. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  109. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +64 -0
  110. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +311 -0
  111. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  112. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  113. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +175 -0
  114. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  115. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +35 -0
  116. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +161 -0
  117. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  118. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.d.ts +47 -0
  119. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js +655 -0
  120. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js.map +1 -0
  121. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.d.ts +23 -0
  122. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.js +92 -0
  123. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.js.map +1 -0
  124. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.d.ts +65 -0
  125. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js +416 -0
  126. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js.map +1 -0
  127. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +50 -0
  128. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +700 -0
  129. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -0
  130. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  131. package/dist-client/pages/kpi-value/kpi-value-importer.js +92 -0
  132. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  133. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +73 -0
  134. package/dist-client/pages/kpi-value/kpi-value-list-page.js +403 -0
  135. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  136. package/dist-client/route.d.ts +1 -0
  137. package/dist-client/route.js +47 -0
  138. package/dist-client/route.js.map +1 -0
  139. package/dist-client/tsconfig.tsbuildinfo +1 -0
  140. package/dist-client/viewparts/kpi-metric-input.d.ts +23 -0
  141. package/dist-client/viewparts/kpi-metric-input.js +140 -0
  142. package/dist-client/viewparts/kpi-metric-input.js.map +1 -0
  143. package/dist-client/viewparts/kpi-metric-meta-editor.d.ts +36 -0
  144. package/dist-client/viewparts/kpi-metric-meta-editor.js +321 -0
  145. package/dist-client/viewparts/kpi-metric-meta-editor.js.map +1 -0
  146. package/dist-client/viewparts/metric-input-hint.d.ts +26 -0
  147. package/dist-client/viewparts/metric-input-hint.js +19 -0
  148. package/dist-client/viewparts/metric-input-hint.js.map +1 -0
  149. package/dist-client/viewparts/metric-input.test.d.ts +1 -0
  150. package/dist-client/viewparts/metric-input.test.js +43 -0
  151. package/dist-client/viewparts/metric-input.test.js.map +1 -0
  152. package/dist-client/viewparts/metric-renderer-registry.d.ts +18 -0
  153. package/dist-client/viewparts/metric-renderer-registry.js +29 -0
  154. package/dist-client/viewparts/metric-renderer-registry.js.map +1 -0
  155. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.d.ts +19 -0
  156. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.js +76 -0
  157. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.js.map +1 -0
  158. package/dist-server/calculator/calculator.test.d.ts +1 -0
  159. package/dist-server/calculator/calculator.test.js +126 -0
  160. package/dist-server/calculator/calculator.test.js.map +1 -0
  161. package/dist-server/calculator/evaluator.d.ts +8 -0
  162. package/dist-server/calculator/evaluator.js +42 -0
  163. package/dist-server/calculator/evaluator.js.map +1 -0
  164. package/dist-server/calculator/functions.d.ts +3 -0
  165. package/dist-server/calculator/functions.js +62 -0
  166. package/dist-server/calculator/functions.js.map +1 -0
  167. package/dist-server/calculator/index.d.ts +6 -0
  168. package/dist-server/calculator/index.js +10 -0
  169. package/dist-server/calculator/index.js.map +1 -0
  170. package/dist-server/calculator/parser.d.ts +34 -0
  171. package/dist-server/calculator/parser.js +185 -0
  172. package/dist-server/calculator/parser.js.map +1 -0
  173. package/dist-server/calculator/provider.d.ts +8 -0
  174. package/dist-server/calculator/provider.js +13 -0
  175. package/dist-server/calculator/provider.js.map +1 -0
  176. package/dist-server/calculator/score.d.ts +21 -0
  177. package/dist-server/calculator/score.js +36 -0
  178. package/dist-server/calculator/score.js.map +1 -0
  179. package/dist-server/calculator/score.test.d.ts +1 -0
  180. package/dist-server/calculator/score.test.js +47 -0
  181. package/dist-server/calculator/score.test.js.map +1 -0
  182. package/dist-server/calculator/validate.d.ts +15 -0
  183. package/dist-server/calculator/validate.js +30 -0
  184. package/dist-server/calculator/validate.js.map +1 -0
  185. package/dist-server/calculator/validate.test.d.ts +1 -0
  186. package/dist-server/calculator/validate.test.js +45 -0
  187. package/dist-server/calculator/validate.test.js.map +1 -0
  188. package/dist-server/controllers/index.d.ts +2 -0
  189. package/dist-server/controllers/index.js +6 -0
  190. package/dist-server/controllers/index.js.map +1 -0
  191. package/dist-server/controllers/kpi-metric-value-provider.d.ts +11 -0
  192. package/dist-server/controllers/kpi-metric-value-provider.js +97 -0
  193. package/dist-server/controllers/kpi-metric-value-provider.js.map +1 -0
  194. package/dist-server/controllers/kpi-value-provider.d.ts +11 -0
  195. package/dist-server/controllers/kpi-value-provider.js +50 -0
  196. package/dist-server/controllers/kpi-value-provider.js.map +1 -0
  197. package/dist-server/index.d.ts +5 -0
  198. package/dist-server/index.js +9 -0
  199. package/dist-server/index.js.map +1 -0
  200. package/dist-server/migrations/1752190849680-seed-kpi-metrics.d.ts +6 -0
  201. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js +102 -0
  202. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js.map +1 -0
  203. package/dist-server/migrations/1752190849681-seed-kpi.d.ts +5 -0
  204. package/dist-server/migrations/1752190849681-seed-kpi.js +315 -0
  205. package/dist-server/migrations/1752190849681-seed-kpi.js.map +1 -0
  206. package/dist-server/migrations/1752192090123-add-grades-to-kpi.d.ts +7 -0
  207. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js +51 -0
  208. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js.map +1 -0
  209. package/dist-server/migrations/1752192090124-add-kpi-statistics.d.ts +5 -0
  210. package/dist-server/migrations/1752192090124-add-kpi-statistics.js +710 -0
  211. package/dist-server/migrations/1752192090124-add-kpi-statistics.js.map +1 -0
  212. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.d.ts +6 -0
  213. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js +111 -0
  214. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js.map +1 -0
  215. package/dist-server/migrations/1752192090129-seed-kpi-values.d.ts +6 -0
  216. package/dist-server/migrations/1752192090129-seed-kpi-values.js +187 -0
  217. package/dist-server/migrations/1752192090129-seed-kpi-values.js.map +1 -0
  218. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.d.ts +10 -0
  219. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.js +26 -0
  220. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.js.map +1 -0
  221. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.d.ts +11 -0
  222. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.js +54 -0
  223. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.js.map +1 -0
  224. package/dist-server/migrations/grade-data/x11-performance-table.json +962 -0
  225. package/dist-server/migrations/grade-data/x12-performance-table.json +611 -0
  226. package/dist-server/migrations/grade-data/x14-performance-table.json +42 -0
  227. package/dist-server/migrations/grade-data/x21-performance-table.json +889 -0
  228. package/dist-server/migrations/grade-data/x22-performance-table.json +1064 -0
  229. package/dist-server/migrations/grade-data/x23-performance-table.json +42 -0
  230. package/dist-server/migrations/grade-data/x31-performance-table.json +644 -0
  231. package/dist-server/migrations/grade-data/x32-performance-table.json +993 -0
  232. package/dist-server/migrations/grade-data/x33-performance-table.json +195 -0
  233. package/dist-server/migrations/grade-data/x34-performance-table.json +12 -0
  234. package/dist-server/migrations/grade-data/x35-performance-table.json +42 -0
  235. package/dist-server/migrations/grade-data/x41-performance-table.json +825 -0
  236. package/dist-server/migrations/grade-data/x42-performance-table.json +786 -0
  237. package/dist-server/migrations/grade-data/x43-performance-table.json +12 -0
  238. package/dist-server/migrations/grade-data/x44-performance-table.json +42 -0
  239. package/dist-server/migrations/grade-data/x51-performance-table.json +924 -0
  240. package/dist-server/migrations/grade-data/x52-performance-table.json +42 -0
  241. package/dist-server/migrations/grade-data/x61-performance-table.json +261 -0
  242. package/dist-server/migrations/grade-data/x62-performance-table.json +42 -0
  243. package/dist-server/migrations/index.d.ts +1 -0
  244. package/dist-server/migrations/index.js +12 -0
  245. package/dist-server/migrations/index.js.map +1 -0
  246. package/dist-server/migrations/seed-data/kpi-metrics-seed.json +517 -0
  247. package/dist-server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  248. package/dist-server/migrations/seed-data/kpi-scopes-seed.json +121 -0
  249. package/dist-server/migrations/seed-data/kpi-values-seed.json +402 -0
  250. package/dist-server/migrations/seed-data/kpis-seed.json +488 -0
  251. package/dist-server/migrations/seed-data/scope-definitions-seed.json +90 -0
  252. package/dist-server/routes.d.ts +1 -0
  253. package/dist-server/routes.js +72 -0
  254. package/dist-server/routes.js.map +1 -0
  255. package/dist-server/service/index.d.ts +15 -0
  256. package/dist-server/service/index.js +49 -0
  257. package/dist-server/service/index.js.map +1 -0
  258. package/dist-server/service/kpi/aggregate-kpi.d.ts +8 -0
  259. package/dist-server/service/kpi/aggregate-kpi.js +123 -0
  260. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -0
  261. package/dist-server/service/kpi/event-subscriber.d.ts +9 -0
  262. package/dist-server/service/kpi/event-subscriber.js +31 -0
  263. package/dist-server/service/kpi/event-subscriber.js.map +1 -0
  264. package/dist-server/service/kpi/index.d.ts +8 -0
  265. package/dist-server/service/kpi/index.js +12 -0
  266. package/dist-server/service/kpi/index.js.map +1 -0
  267. package/dist-server/service/kpi/kpi-formula.service.d.ts +49 -0
  268. package/dist-server/service/kpi/kpi-formula.service.js +165 -0
  269. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -0
  270. package/dist-server/service/kpi/kpi-grade.types.d.ts +22 -0
  271. package/dist-server/service/kpi/kpi-grade.types.js +3 -0
  272. package/dist-server/service/kpi/kpi-grade.types.js.map +1 -0
  273. package/dist-server/service/kpi/kpi-history.d.ts +29 -0
  274. package/dist-server/service/kpi/kpi-history.js +148 -0
  275. package/dist-server/service/kpi/kpi-history.js.map +1 -0
  276. package/dist-server/service/kpi/kpi-mutation.d.ts +14 -0
  277. package/dist-server/service/kpi/kpi-mutation.js +553 -0
  278. package/dist-server/service/kpi/kpi-mutation.js.map +1 -0
  279. package/dist-server/service/kpi/kpi-query.d.ts +24 -0
  280. package/dist-server/service/kpi/kpi-query.js +309 -0
  281. package/dist-server/service/kpi/kpi-query.js.map +1 -0
  282. package/dist-server/service/kpi/kpi-type.d.ts +48 -0
  283. package/dist-server/service/kpi/kpi-type.js +221 -0
  284. package/dist-server/service/kpi/kpi-type.js.map +1 -0
  285. package/dist-server/service/kpi/kpi.d.ts +130 -0
  286. package/dist-server/service/kpi/kpi.js +356 -0
  287. package/dist-server/service/kpi/kpi.js.map +1 -0
  288. package/dist-server/service/kpi-alert/index.d.ts +2 -0
  289. package/dist-server/service/kpi-alert/index.js +6 -0
  290. package/dist-server/service/kpi-alert/index.js.map +1 -0
  291. package/dist-server/service/kpi-alert/kpi-alert-query.d.ts +4 -0
  292. package/dist-server/service/kpi-alert/kpi-alert-query.js +72 -0
  293. package/dist-server/service/kpi-alert/kpi-alert-query.js.map +1 -0
  294. package/dist-server/service/kpi-alert/kpi-alert-type.d.ts +8 -0
  295. package/dist-server/service/kpi-alert/kpi-alert-type.js +33 -0
  296. package/dist-server/service/kpi-alert/kpi-alert-type.js.map +1 -0
  297. package/dist-server/service/kpi-metric/aggregate-kpi-metric.d.ts +8 -0
  298. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +126 -0
  299. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -0
  300. package/dist-server/service/kpi-metric/index.d.ts +6 -0
  301. package/dist-server/service/kpi-metric/index.js +10 -0
  302. package/dist-server/service/kpi-metric/index.js.map +1 -0
  303. package/dist-server/service/kpi-metric/kpi-metric-meta.d.ts +46 -0
  304. package/dist-server/service/kpi-metric/kpi-metric-meta.js +27 -0
  305. package/dist-server/service/kpi-metric/kpi-metric-meta.js.map +1 -0
  306. package/dist-server/service/kpi-metric/kpi-metric-meta.test.d.ts +1 -0
  307. package/dist-server/service/kpi-metric/kpi-metric-meta.test.js +43 -0
  308. package/dist-server/service/kpi-metric/kpi-metric-meta.test.js.map +1 -0
  309. package/dist-server/service/kpi-metric/kpi-metric-mutation.d.ts +10 -0
  310. package/dist-server/service/kpi-metric/kpi-metric-mutation.js +296 -0
  311. package/dist-server/service/kpi-metric/kpi-metric-mutation.js.map +1 -0
  312. package/dist-server/service/kpi-metric/kpi-metric-query.d.ts +14 -0
  313. package/dist-server/service/kpi-metric/kpi-metric-query.js +126 -0
  314. package/dist-server/service/kpi-metric/kpi-metric-query.js.map +1 -0
  315. package/dist-server/service/kpi-metric/kpi-metric-type.d.ts +45 -0
  316. package/dist-server/service/kpi-metric/kpi-metric-type.js +177 -0
  317. package/dist-server/service/kpi-metric/kpi-metric-type.js.map +1 -0
  318. package/dist-server/service/kpi-metric/kpi-metric.d.ts +39 -0
  319. package/dist-server/service/kpi-metric/kpi-metric.js +174 -0
  320. package/dist-server/service/kpi-metric/kpi-metric.js.map +1 -0
  321. package/dist-server/service/kpi-metric-value/index.d.ts +6 -0
  322. package/dist-server/service/kpi-metric-value/index.js +10 -0
  323. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  324. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +11 -0
  325. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +283 -0
  326. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  327. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +13 -0
  328. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +106 -0
  329. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  330. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.d.ts +26 -0
  331. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js +112 -0
  332. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js.map +1 -0
  333. package/dist-server/service/kpi-metric-value/kpi-metric-value.d.ts +23 -0
  334. package/dist-server/service/kpi-metric-value/kpi-metric-value.js +107 -0
  335. package/dist-server/service/kpi-metric-value/kpi-metric-value.js.map +1 -0
  336. package/dist-server/service/kpi-org-scope/index.d.ts +5 -0
  337. package/dist-server/service/kpi-org-scope/index.js +9 -0
  338. package/dist-server/service/kpi-org-scope/index.js.map +1 -0
  339. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.d.ts +8 -0
  340. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js +170 -0
  341. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js.map +1 -0
  342. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.d.ts +14 -0
  343. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js +152 -0
  344. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js.map +1 -0
  345. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.d.ts +26 -0
  346. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js +101 -0
  347. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js.map +1 -0
  348. package/dist-server/service/kpi-org-scope/kpi-org-scope.d.ts +26 -0
  349. package/dist-server/service/kpi-org-scope/kpi-org-scope.js +135 -0
  350. package/dist-server/service/kpi-org-scope/kpi-org-scope.js.map +1 -0
  351. package/dist-server/service/kpi-scope/index.d.ts +9 -0
  352. package/dist-server/service/kpi-scope/index.js +14 -0
  353. package/dist-server/service/kpi-scope/index.js.map +1 -0
  354. package/dist-server/service/kpi-scope/kpi-scope-mutation.d.ts +9 -0
  355. package/dist-server/service/kpi-scope/kpi-scope-mutation.js +140 -0
  356. package/dist-server/service/kpi-scope/kpi-scope-mutation.js.map +1 -0
  357. package/dist-server/service/kpi-scope/kpi-scope-query.d.ts +11 -0
  358. package/dist-server/service/kpi-scope/kpi-scope-query.js +89 -0
  359. package/dist-server/service/kpi-scope/kpi-scope-query.js.map +1 -0
  360. package/dist-server/service/kpi-scope/kpi-scope-type.d.ts +35 -0
  361. package/dist-server/service/kpi-scope/kpi-scope-type.js +138 -0
  362. package/dist-server/service/kpi-scope/kpi-scope-type.js.map +1 -0
  363. package/dist-server/service/kpi-scope/kpi-scope.d.ts +38 -0
  364. package/dist-server/service/kpi-scope/kpi-scope.js +144 -0
  365. package/dist-server/service/kpi-scope/kpi-scope.js.map +1 -0
  366. package/dist-server/service/kpi-statistic/index.d.ts +6 -0
  367. package/dist-server/service/kpi-statistic/index.js +10 -0
  368. package/dist-server/service/kpi-statistic/index.js.map +1 -0
  369. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.d.ts +43 -0
  370. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.js +181 -0
  371. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.js.map +1 -0
  372. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.d.ts +50 -0
  373. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.js +324 -0
  374. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.js.map +1 -0
  375. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.d.ts +14 -0
  376. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.js +279 -0
  377. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.js.map +1 -0
  378. package/dist-server/service/kpi-statistic/kpi-statistic-query.d.ts +17 -0
  379. package/dist-server/service/kpi-statistic/kpi-statistic-query.js +183 -0
  380. package/dist-server/service/kpi-statistic/kpi-statistic-query.js.map +1 -0
  381. package/dist-server/service/kpi-statistic/kpi-statistic-type.d.ts +59 -0
  382. package/dist-server/service/kpi-statistic/kpi-statistic-type.js +200 -0
  383. package/dist-server/service/kpi-statistic/kpi-statistic-type.js.map +1 -0
  384. package/dist-server/service/kpi-statistic/kpi-statistic.d.ts +42 -0
  385. package/dist-server/service/kpi-statistic/kpi-statistic.js +210 -0
  386. package/dist-server/service/kpi-statistic/kpi-statistic.js.map +1 -0
  387. package/dist-server/service/kpi-value/index.d.ts +6 -0
  388. package/dist-server/service/kpi-value/index.js +10 -0
  389. package/dist-server/service/kpi-value/index.js.map +1 -0
  390. package/dist-server/service/kpi-value/kpi-value-mutation.d.ts +13 -0
  391. package/dist-server/service/kpi-value/kpi-value-mutation.js +447 -0
  392. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -0
  393. package/dist-server/service/kpi-value/kpi-value-query.d.ts +22 -0
  394. package/dist-server/service/kpi-value/kpi-value-query.js +149 -0
  395. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  396. package/dist-server/service/kpi-value/kpi-value-score.service.d.ts +24 -0
  397. package/dist-server/service/kpi-value/kpi-value-score.service.js +61 -0
  398. package/dist-server/service/kpi-value/kpi-value-score.service.js.map +1 -0
  399. package/dist-server/service/kpi-value/kpi-value-type.d.ts +33 -0
  400. package/dist-server/service/kpi-value/kpi-value-type.js +156 -0
  401. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -0
  402. package/dist-server/service/kpi-value/kpi-value.d.ts +32 -0
  403. package/dist-server/service/kpi-value/kpi-value.js +175 -0
  404. package/dist-server/service/kpi-value/kpi-value.js.map +1 -0
  405. package/dist-server/service/utils/value-date-util.d.ts +4 -0
  406. package/dist-server/service/utils/value-date-util.js +117 -0
  407. package/dist-server/service/utils/value-date-util.js.map +1 -0
  408. package/dist-server/tsconfig.tsbuildinfo +1 -0
  409. package/package.json +3 -3
@@ -0,0 +1,140 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { html, css, LitElement, nothing } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ import { resolveInputHint } from './metric-input-hint';
5
+ import { MetricRendererRegistry } from './metric-renderer-registry';
6
+ /**
7
+ * metric 정의(meta.input)에 따라 입력 위젯을 **선언적으로 자동 렌더**하는 제네릭 컴포넌트.
8
+ * 이름 추측(isRating 등) 없이 `resolveInputHint` 로 위젯을 결정한다.
9
+ *
10
+ * <kpi-metric-input .metric=${metric} .value=${v}
11
+ * @metric-input-change=${e => (v = e.detail.value)}></kpi-metric-input>
12
+ *
13
+ * 예외 UI 는 MetricRendererRegistry 로 등록(제네릭 우선순위보다 먼저 적용).
14
+ */
15
+ let KpiMetricInput = class KpiMetricInput extends LitElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.metric = {};
19
+ /** 상위에서 강제 비활성화(권한 등). readonly 힌트와 별개. */
20
+ this.disabled = false;
21
+ }
22
+ static { this.styles = css `
23
+ :host {
24
+ display: inline-flex;
25
+ align-items: baseline;
26
+ gap: 2px;
27
+ font: 13px/18px var(--theme-font, sans-serif);
28
+ }
29
+ input,
30
+ select {
31
+ background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));
32
+ color: var(--input-field-color, var(--md-sys-color-on-surface));
33
+ font: inherit;
34
+ padding: 2px 4px;
35
+ }
36
+ input[type='number'] {
37
+ width: 5em;
38
+ text-align: right;
39
+ }
40
+ .stars {
41
+ display: inline-flex;
42
+ cursor: pointer;
43
+ font-size: 18px;
44
+ line-height: 1;
45
+ color: var(--md-sys-color-primary, #2e79be);
46
+ }
47
+ .stars[readonly] {
48
+ cursor: default;
49
+ opacity: 0.85;
50
+ }
51
+ .star {
52
+ width: 1em;
53
+ }
54
+ .unit {
55
+ color: var(--md-sys-color-on-surface-variant, #888);
56
+ font-size: 11px;
57
+ }
58
+ `; }
59
+ _emit(value) {
60
+ this.value = value;
61
+ this.dispatchEvent(new CustomEvent('metric-input-change', { detail: { value }, bubbles: true, composed: true }));
62
+ }
63
+ render() {
64
+ const custom = MetricRendererRegistry.resolve(this.metric);
65
+ if (custom)
66
+ return custom(this.metric, this.value, v => this._emit(v));
67
+ const hint = resolveInputHint(this.metric);
68
+ const ro = this.disabled || !!hint.readonly;
69
+ const unit = this.metric?.unit;
70
+ // 값(우측정렬) 바로 옆에 단위 — 값이 단위에 붙어 자연스럽게. (rating/toggle 등엔 unit 보통 없음)
71
+ return html `
72
+ ${this._renderWidget(hint, ro)}${unit ? html `<span class="unit">${unit}</span>` : nothing}
73
+ `;
74
+ }
75
+ _renderWidget(hint, ro) {
76
+ switch (hint.widget) {
77
+ case 'rating':
78
+ return this._renderRating(hint, ro);
79
+ case 'select':
80
+ return this._renderSelect(hint, ro);
81
+ case 'date':
82
+ return html `<input type="date" .value=${this.value ?? ''} ?disabled=${ro}
83
+ @change=${(e) => this._emit(e.target.value)} />`;
84
+ case 'toggle':
85
+ return html `<input type="checkbox" .checked=${!!this.value} ?disabled=${ro}
86
+ @change=${(e) => this._emit(e.target.checked)} />`;
87
+ case 'text':
88
+ return html `<input type="text" .value=${this.value ?? ''} ?disabled=${ro}
89
+ placeholder=${hint.placeholder ?? ''} @input=${(e) => this._emit(e.target.value)} />`;
90
+ case 'number':
91
+ default:
92
+ return html `<input type="number" .value=${this.value ?? ''} ?disabled=${ro}
93
+ min=${hint.min ?? nothing} max=${hint.max ?? nothing} step=${hint.step ?? nothing}
94
+ placeholder=${hint.placeholder ?? ''}
95
+ @input=${(e) => {
96
+ const raw = e.target.value;
97
+ this._emit(raw === '' ? null : Number(raw));
98
+ }} />`;
99
+ }
100
+ }
101
+ _renderRating(hint, ro) {
102
+ const max = hint.max ?? 5;
103
+ const score = Number(this.value ?? 0);
104
+ const stars = Array.from({ length: max }, (_, idx) => {
105
+ const i = idx + 1;
106
+ const filled = i <= Math.round(score);
107
+ return html `<span class="star" @click=${() => (ro ? null : this._emit(i))}>${filled ? '★' : '☆'}</span>`;
108
+ });
109
+ return html `<span class="stars" ?readonly=${ro} title=${`${score}/${max}`}>${stars}</span>`;
110
+ }
111
+ _renderSelect(hint, ro) {
112
+ const options = hint.options ?? [];
113
+ return html `<select ?disabled=${ro} @change=${(e) => {
114
+ const raw = e.target.value;
115
+ // 옵션의 원래 타입(숫자 등)을 보존해 방출 — 문자열 강제 방지.
116
+ const opt = options.find(o => String(o.value) === raw);
117
+ this._emit(raw === '' ? null : opt ? opt.value : raw);
118
+ }}>
119
+ <option value="" ?selected=${this.value == null || this.value === ''}>-</option>
120
+ ${options.map(o => html `<option value=${o.value} ?selected=${String(this.value) === String(o.value)}>${o.label}</option>`)}
121
+ </select>`;
122
+ }
123
+ };
124
+ __decorate([
125
+ property({ type: Object }),
126
+ __metadata("design:type", Object)
127
+ ], KpiMetricInput.prototype, "metric", void 0);
128
+ __decorate([
129
+ property(),
130
+ __metadata("design:type", Object)
131
+ ], KpiMetricInput.prototype, "value", void 0);
132
+ __decorate([
133
+ property({ type: Boolean }),
134
+ __metadata("design:type", Object)
135
+ ], KpiMetricInput.prototype, "disabled", void 0);
136
+ KpiMetricInput = __decorate([
137
+ customElement('kpi-metric-input')
138
+ ], KpiMetricInput);
139
+ export { KpiMetricInput };
140
+ //# sourceMappingURL=kpi-metric-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kpi-metric-input.js","sourceRoot":"","sources":["../../client/viewparts/kpi-metric-input.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { resolveInputHint, InputHint, KpiMetricLike } from './metric-input-hint'\nimport { MetricRendererRegistry } from './metric-renderer-registry'\n\n/**\n * metric 정의(meta.input)에 따라 입력 위젯을 **선언적으로 자동 렌더**하는 제네릭 컴포넌트.\n * 이름 추측(isRating 등) 없이 `resolveInputHint` 로 위젯을 결정한다.\n *\n * <kpi-metric-input .metric=${metric} .value=${v}\n * @metric-input-change=${e => (v = e.detail.value)}></kpi-metric-input>\n *\n * 예외 UI 는 MetricRendererRegistry 로 등록(제네릭 우선순위보다 먼저 적용).\n */\n@customElement('kpi-metric-input')\nexport class KpiMetricInput extends LitElement {\n static styles = css`\n :host {\n display: inline-flex;\n align-items: baseline;\n gap: 2px;\n font: 13px/18px var(--theme-font, sans-serif);\n }\n input,\n select {\n background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n color: var(--input-field-color, var(--md-sys-color-on-surface));\n font: inherit;\n padding: 2px 4px;\n }\n input[type='number'] {\n width: 5em;\n text-align: right;\n }\n .stars {\n display: inline-flex;\n cursor: pointer;\n font-size: 18px;\n line-height: 1;\n color: var(--md-sys-color-primary, #2e79be);\n }\n .stars[readonly] {\n cursor: default;\n opacity: 0.85;\n }\n .star {\n width: 1em;\n }\n .unit {\n color: var(--md-sys-color-on-surface-variant, #888);\n font-size: 11px;\n }\n `\n\n @property({ type: Object }) metric: KpiMetricLike = {}\n @property() value: any\n /** 상위에서 강제 비활성화(권한 등). readonly 힌트와 별개. */\n @property({ type: Boolean }) disabled = false\n\n private _emit(value: any) {\n this.value = value\n this.dispatchEvent(new CustomEvent('metric-input-change', { detail: { value }, bubbles: true, composed: true }))\n }\n\n render() {\n const custom = MetricRendererRegistry.resolve(this.metric)\n if (custom) return custom(this.metric, this.value, v => this._emit(v))\n\n const hint = resolveInputHint(this.metric)\n const ro = this.disabled || !!hint.readonly\n const unit = (this.metric as any)?.unit\n\n // 값(우측정렬) 바로 옆에 단위 — 값이 단위에 붙어 자연스럽게. (rating/toggle 등엔 unit 보통 없음)\n return html`\n ${this._renderWidget(hint, ro)}${unit ? html`<span class=\"unit\">${unit}</span>` : nothing}\n `\n }\n\n private _renderWidget(hint: InputHint, ro: boolean) {\n switch (hint.widget) {\n case 'rating':\n return this._renderRating(hint, ro)\n case 'select':\n return this._renderSelect(hint, ro)\n case 'date':\n return html`<input type=\"date\" .value=${this.value ?? ''} ?disabled=${ro}\n @change=${(e: Event) => this._emit((e.target as HTMLInputElement).value)} />`\n case 'toggle':\n return html`<input type=\"checkbox\" .checked=${!!this.value} ?disabled=${ro}\n @change=${(e: Event) => this._emit((e.target as HTMLInputElement).checked)} />`\n case 'text':\n return html`<input type=\"text\" .value=${this.value ?? ''} ?disabled=${ro}\n placeholder=${hint.placeholder ?? ''} @input=${(e: Event) => this._emit((e.target as HTMLInputElement).value)} />`\n case 'number':\n default:\n return html`<input type=\"number\" .value=${this.value ?? ''} ?disabled=${ro}\n min=${hint.min ?? nothing} max=${hint.max ?? nothing} step=${hint.step ?? nothing}\n placeholder=${hint.placeholder ?? ''}\n @input=${(e: Event) => {\n const raw = (e.target as HTMLInputElement).value\n this._emit(raw === '' ? null : Number(raw))\n }} />`\n }\n }\n\n private _renderRating(hint: InputHint, ro: boolean) {\n const max = hint.max ?? 5\n const score = Number(this.value ?? 0)\n const stars = Array.from({ length: max }, (_, idx) => {\n const i = idx + 1\n const filled = i <= Math.round(score)\n return html`<span class=\"star\" @click=${() => (ro ? null : this._emit(i))}>${filled ? '★' : '☆'}</span>`\n })\n return html`<span class=\"stars\" ?readonly=${ro} title=${`${score}/${max}`}>${stars}</span>`\n }\n\n private _renderSelect(hint: InputHint, ro: boolean) {\n const options = hint.options ?? []\n return html`<select ?disabled=${ro} @change=${(e: Event) => {\n const raw = (e.target as HTMLSelectElement).value\n // 옵션의 원래 타입(숫자 등)을 보존해 방출 — 문자열 강제 방지.\n const opt = options.find(o => String(o.value) === raw)\n this._emit(raw === '' ? null : opt ? opt.value : raw)\n }}>\n <option value=\"\" ?selected=${this.value == null || this.value === ''}>-</option>\n ${options.map(\n o => html`<option value=${o.value} ?selected=${String(this.value) === String(o.value)}>${o.label}</option>`\n )}\n </select>`\n }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import '@material/web/icon/icon.js';
2
+ import { LitElement } from 'lit';
3
+ /**
4
+ * KpiMetric.meta.input(입력 위젯 힌트) 구조화 에디터.
5
+ *
6
+ * metric 관리 화면(kpi-metric-list-page)에서 팝업으로 열려 meta.input 을 편집한다.
7
+ * raw JSON 을 직접 만지지 않고 위젯/필드를 폼으로 구성 → 내부적으로 meta 객체 생성.
8
+ * meta 의 다른 키(kind/source…)는 보존하고 input 만 교체/삭제한다.
9
+ *
10
+ * - `metric-meta-save` detail:{ meta } — 저장 (widget 미선택 시 input 제거된 meta)
11
+ * - `metric-meta-cancel` — 취소
12
+ */
13
+ export declare class KpiMetricMetaEditor extends LitElement {
14
+ static styles: import("lit").CSSResult[];
15
+ /** { name, meta, collectType } */
16
+ metric: any;
17
+ widget: string;
18
+ min: string;
19
+ max: string;
20
+ step: string;
21
+ decimals: string;
22
+ placeholder: string;
23
+ optionsText: string;
24
+ readonly: boolean;
25
+ required: boolean;
26
+ hasPlan: boolean;
27
+ connectedCallback(): void;
28
+ render(): import("lit-html").TemplateResult<1>;
29
+ private _num;
30
+ private _buildInput;
31
+ /** 기존 meta 는 보존하고 input 만 교체(또는 삭제). */
32
+ private _buildMeta;
33
+ private _save;
34
+ private _clear;
35
+ private _cancel;
36
+ }
@@ -0,0 +1,321 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import { css, html, LitElement } from 'lit';
4
+ import { customElement, property, state } from 'lit/decorators.js';
5
+ import { CommonHeaderStyles } from '@operato/styles';
6
+ /**
7
+ * KpiMetric.meta.input(입력 위젯 힌트) 구조화 에디터.
8
+ *
9
+ * metric 관리 화면(kpi-metric-list-page)에서 팝업으로 열려 meta.input 을 편집한다.
10
+ * raw JSON 을 직접 만지지 않고 위젯/필드를 폼으로 구성 → 내부적으로 meta 객체 생성.
11
+ * meta 의 다른 키(kind/source…)는 보존하고 input 만 교체/삭제한다.
12
+ *
13
+ * - `metric-meta-save` detail:{ meta } — 저장 (widget 미선택 시 input 제거된 meta)
14
+ * - `metric-meta-cancel` — 취소
15
+ */
16
+ let KpiMetricMetaEditor = class KpiMetricMetaEditor extends LitElement {
17
+ constructor() {
18
+ super(...arguments);
19
+ /** { name, meta, collectType } */
20
+ this.metric = {};
21
+ this.widget = '';
22
+ this.min = '';
23
+ this.max = '';
24
+ this.step = '';
25
+ this.decimals = '';
26
+ this.placeholder = '';
27
+ this.optionsText = '';
28
+ this.readonly = false;
29
+ this.required = false;
30
+ this.hasPlan = false;
31
+ }
32
+ static { this.styles = [
33
+ CommonHeaderStyles,
34
+ css `
35
+ :host {
36
+ display: flex;
37
+ flex-direction: column;
38
+ height: 100%;
39
+ box-sizing: border-box;
40
+ width: 100%;
41
+ min-width: 520px;
42
+ font-size: 14px;
43
+ color: #212529;
44
+ }
45
+ /* 스크롤되는 내용부 — 버튼은 아래에 고정 (kpi-metric-value-manual-entry-form 패턴) */
46
+ .content {
47
+ flex: 1;
48
+ overflow-y: auto;
49
+ padding: 20px 24px 8px 24px;
50
+ }
51
+ h3 {
52
+ margin: 0 0 4px 0;
53
+ font-size: 15px;
54
+ }
55
+ .sub {
56
+ color: #6b7684;
57
+ margin-bottom: 14px;
58
+ }
59
+ .field {
60
+ display: grid;
61
+ grid-template-columns: 96px 1fr;
62
+ align-items: center;
63
+ gap: 8px 10px;
64
+ margin-bottom: 10px;
65
+ }
66
+ label {
67
+ color: #35618e;
68
+ font-weight: 500;
69
+ }
70
+ input[type='text'],
71
+ input[type='number'],
72
+ select,
73
+ textarea {
74
+ background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));
75
+ color: var(--input-field-color, var(--md-sys-color-on-surface));
76
+ width: 100%;
77
+ box-sizing: border-box;
78
+ padding: 6px 8px;
79
+ border: 1px solid #cdd5df;
80
+ border-radius: 5px;
81
+ font-size: 13px;
82
+ }
83
+ textarea {
84
+ min-height: 72px;
85
+ resize: vertical;
86
+ font-family: monospace;
87
+ }
88
+ .checks {
89
+ display: flex;
90
+ gap: 16px;
91
+ flex-wrap: wrap;
92
+ margin: 4px 0 12px 0;
93
+ }
94
+ .checks label {
95
+ display: inline-flex;
96
+ align-items: center;
97
+ gap: 5px;
98
+ color: #212529;
99
+ font-weight: 400;
100
+ }
101
+ .hint {
102
+ color: #8b95a1;
103
+ font-size: 11px;
104
+ grid-column: 2;
105
+ margin-top: -4px;
106
+ }
107
+ `
108
+ ]; }
109
+ connectedCallback() {
110
+ super.connectedCallback();
111
+ const input = this.metric?.meta?.input || {};
112
+ this.widget = input.widget || '';
113
+ this.min = input.min !== undefined ? String(input.min) : '';
114
+ this.max = input.max !== undefined ? String(input.max) : '';
115
+ this.step = input.step !== undefined ? String(input.step) : '';
116
+ this.decimals = input.decimals !== undefined ? String(input.decimals) : '';
117
+ this.placeholder = input.placeholder || '';
118
+ this.optionsText = (input.options || []).map((o) => `${o.value}|${o.label ?? o.value}`).join('\n');
119
+ this.readonly = !!input.readonly;
120
+ this.required = !!input.required;
121
+ this.hasPlan = !!input.hasPlan;
122
+ }
123
+ render() {
124
+ const w = this.widget;
125
+ return html `
126
+ <div class="content">
127
+ <h3>입력 힌트 · ${this.metric?.name || ''}</h3>
128
+ <div class="sub">값 입력 화면(월별/완료평가 등)이 이 힌트로 위젯을 그립니다. 위젯을 비우면 힌트가 제거되어 숫자 입력으로 폴백합니다.</div>
129
+
130
+ <div class="field">
131
+ <label>위젯</label>
132
+ <select .value=${w} @change=${(e) => (this.widget = e.target.value)}>
133
+ <option value="">(자동/폴백 — 숫자)</option>
134
+ <option value="number" ?selected=${w === 'number'}>number — 숫자</option>
135
+ <option value="rating" ?selected=${w === 'rating'}>rating — 별점</option>
136
+ <option value="select" ?selected=${w === 'select'}>select — 선택목록</option>
137
+ <option value="toggle" ?selected=${w === 'toggle'}>toggle — 스위치</option>
138
+ <option value="text" ?selected=${w === 'text'}>text — 텍스트</option>
139
+ <option value="date" ?selected=${w === 'date'}>date — 날짜</option>
140
+ </select>
141
+ </div>
142
+
143
+ ${w === 'number' || w === 'rating'
144
+ ? html `
145
+ ${w === 'number'
146
+ ? html `<div class="field">
147
+ <label>최소</label>
148
+ <input type="number" .value=${this.min} @input=${(e) => (this.min = e.target.value)} />
149
+ </div>`
150
+ : ''}
151
+ <div class="field">
152
+ <label>최대</label>
153
+ <input type="number" .value=${this.max} @input=${(e) => (this.max = e.target.value)} />
154
+ ${w === 'rating' ? html `<span class="hint">별 개수 (기본 5)</span>` : ''}
155
+ </div>
156
+ <div class="field">
157
+ <label>스텝</label>
158
+ <input type="number" .value=${this.step} @input=${(e) => (this.step = e.target.value)} />
159
+ ${w === 'rating' ? html `<span class="hint">1=정수, 0.5=반별 (기본 1)</span>` : ''}
160
+ </div>
161
+ ${w === 'number'
162
+ ? html `<div class="field">
163
+ <label>소수자리</label>
164
+ <input type="number" .value=${this.decimals} @input=${(e) => (this.decimals = e.target.value)} />
165
+ </div>`
166
+ : ''}
167
+ `
168
+ : ''}
169
+ ${w === 'select'
170
+ ? html `
171
+ <div class="field">
172
+ <label>옵션</label>
173
+ <textarea
174
+ .value=${this.optionsText}
175
+ placeholder="한 줄에 하나: 값|표시라벨&#10;예) 1|양호&#10;2|보통"
176
+ @input=${(e) => (this.optionsText = e.target.value)}
177
+ ></textarea>
178
+ <span class="hint">한 줄당 <code>값|라벨</code> (라벨 생략 시 값 사용)</span>
179
+ </div>
180
+ `
181
+ : ''}
182
+ ${w === 'text'
183
+ ? html `<div class="field">
184
+ <label>placeholder</label>
185
+ <input type="text" .value=${this.placeholder} @input=${(e) => (this.placeholder = e.target.value)} />
186
+ </div>`
187
+ : ''}
188
+
189
+ ${w
190
+ ? html `<div class="checks">
191
+ <label><input type="checkbox" .checked=${this.readonly} @change=${(e) => (this.readonly = e.target.checked)} /> 읽기전용</label>
192
+ <label><input type="checkbox" .checked=${this.required} @change=${(e) => (this.required = e.target.checked)} /> 필수</label>
193
+ <label><input type="checkbox" .checked=${this.hasPlan} @change=${(e) => (this.hasPlan = e.target.checked)} /> 계획/실제 2열</label>
194
+ </div>`
195
+ : ''}
196
+ </div>
197
+
198
+ <div class="footer">
199
+ ${this.metric?.meta?.input
200
+ ? html `<button danger @click=${this._clear}><md-icon>delete</md-icon>힌트 삭제</button>`
201
+ : ''}
202
+ <div filler></div>
203
+ <button @click=${this._cancel}><md-icon>cancel</md-icon>취소</button>
204
+ <button done @click=${this._save}><md-icon>done</md-icon>저장</button>
205
+ </div>
206
+ `;
207
+ }
208
+ _num(v) {
209
+ if (v === '' || v === null || v === undefined)
210
+ return undefined;
211
+ const n = Number(v);
212
+ return Number.isNaN(n) ? undefined : n;
213
+ }
214
+ _buildInput() {
215
+ if (!this.widget)
216
+ return undefined;
217
+ const input = { widget: this.widget };
218
+ if (this.widget === 'number' || this.widget === 'rating') {
219
+ const min = this._num(this.min);
220
+ const max = this._num(this.max);
221
+ const step = this._num(this.step);
222
+ const decimals = this._num(this.decimals);
223
+ if (this.widget === 'number' && min !== undefined)
224
+ input.min = min;
225
+ if (max !== undefined)
226
+ input.max = max;
227
+ if (step !== undefined)
228
+ input.step = step;
229
+ if (this.widget === 'number' && decimals !== undefined)
230
+ input.decimals = decimals;
231
+ }
232
+ if (this.widget === 'select') {
233
+ const options = this.optionsText
234
+ .split('\n')
235
+ .map(line => line.trim())
236
+ .filter(Boolean)
237
+ .map(line => {
238
+ const [value, label] = line.split('|').map(s => s.trim());
239
+ return { value, label: label || value };
240
+ });
241
+ if (options.length)
242
+ input.options = options;
243
+ }
244
+ if (this.widget === 'text' && this.placeholder)
245
+ input.placeholder = this.placeholder;
246
+ if (this.readonly)
247
+ input.readonly = true;
248
+ if (this.required)
249
+ input.required = true;
250
+ if (this.hasPlan)
251
+ input.hasPlan = true;
252
+ return input;
253
+ }
254
+ /** 기존 meta 는 보존하고 input 만 교체(또는 삭제). */
255
+ _buildMeta() {
256
+ const rest = { ...(this.metric?.meta || {}) };
257
+ delete rest.input;
258
+ const input = this._buildInput();
259
+ const meta = input ? { ...rest, input } : rest;
260
+ return Object.keys(meta).length ? meta : null;
261
+ }
262
+ _save() {
263
+ this.dispatchEvent(new CustomEvent('metric-meta-save', { detail: { meta: this._buildMeta() }, bubbles: true, composed: true }));
264
+ }
265
+ _clear() {
266
+ this.widget = '';
267
+ this.dispatchEvent(new CustomEvent('metric-meta-save', { detail: { meta: this._buildMeta() }, bubbles: true, composed: true }));
268
+ }
269
+ _cancel() {
270
+ this.dispatchEvent(new CustomEvent('metric-meta-cancel', { bubbles: true, composed: true }));
271
+ }
272
+ };
273
+ __decorate([
274
+ property({ type: Object }),
275
+ __metadata("design:type", Object)
276
+ ], KpiMetricMetaEditor.prototype, "metric", void 0);
277
+ __decorate([
278
+ state(),
279
+ __metadata("design:type", Object)
280
+ ], KpiMetricMetaEditor.prototype, "widget", void 0);
281
+ __decorate([
282
+ state(),
283
+ __metadata("design:type", Object)
284
+ ], KpiMetricMetaEditor.prototype, "min", void 0);
285
+ __decorate([
286
+ state(),
287
+ __metadata("design:type", Object)
288
+ ], KpiMetricMetaEditor.prototype, "max", void 0);
289
+ __decorate([
290
+ state(),
291
+ __metadata("design:type", Object)
292
+ ], KpiMetricMetaEditor.prototype, "step", void 0);
293
+ __decorate([
294
+ state(),
295
+ __metadata("design:type", Object)
296
+ ], KpiMetricMetaEditor.prototype, "decimals", void 0);
297
+ __decorate([
298
+ state(),
299
+ __metadata("design:type", Object)
300
+ ], KpiMetricMetaEditor.prototype, "placeholder", void 0);
301
+ __decorate([
302
+ state(),
303
+ __metadata("design:type", Object)
304
+ ], KpiMetricMetaEditor.prototype, "optionsText", void 0);
305
+ __decorate([
306
+ state(),
307
+ __metadata("design:type", Object)
308
+ ], KpiMetricMetaEditor.prototype, "readonly", void 0);
309
+ __decorate([
310
+ state(),
311
+ __metadata("design:type", Object)
312
+ ], KpiMetricMetaEditor.prototype, "required", void 0);
313
+ __decorate([
314
+ state(),
315
+ __metadata("design:type", Object)
316
+ ], KpiMetricMetaEditor.prototype, "hasPlan", void 0);
317
+ KpiMetricMetaEditor = __decorate([
318
+ customElement('kpi-metric-meta-editor')
319
+ ], KpiMetricMetaEditor);
320
+ export { KpiMetricMetaEditor };
321
+ //# sourceMappingURL=kpi-metric-meta-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kpi-metric-meta-editor.js","sourceRoot":"","sources":["../../client/viewparts/kpi-metric-meta-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { CommonHeaderStyles } from '@operato/styles'\n\n/**\n * KpiMetric.meta.input(입력 위젯 힌트) 구조화 에디터.\n *\n * metric 관리 화면(kpi-metric-list-page)에서 팝업으로 열려 meta.input 을 편집한다.\n * raw JSON 을 직접 만지지 않고 위젯/필드를 폼으로 구성 → 내부적으로 meta 객체 생성.\n * meta 의 다른 키(kind/source…)는 보존하고 input 만 교체/삭제한다.\n *\n * - `metric-meta-save` detail:{ meta } — 저장 (widget 미선택 시 input 제거된 meta)\n * - `metric-meta-cancel` — 취소\n */\n@customElement('kpi-metric-meta-editor')\nexport class KpiMetricMetaEditor extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n box-sizing: border-box;\n width: 100%;\n min-width: 520px;\n font-size: 14px;\n color: #212529;\n }\n /* 스크롤되는 내용부 — 버튼은 아래에 고정 (kpi-metric-value-manual-entry-form 패턴) */\n .content {\n flex: 1;\n overflow-y: auto;\n padding: 20px 24px 8px 24px;\n }\n h3 {\n margin: 0 0 4px 0;\n font-size: 15px;\n }\n .sub {\n color: #6b7684;\n margin-bottom: 14px;\n }\n .field {\n display: grid;\n grid-template-columns: 96px 1fr;\n align-items: center;\n gap: 8px 10px;\n margin-bottom: 10px;\n }\n label {\n color: #35618e;\n font-weight: 500;\n }\n input[type='text'],\n input[type='number'],\n select,\n textarea {\n background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n color: var(--input-field-color, var(--md-sys-color-on-surface));\n width: 100%;\n box-sizing: border-box;\n padding: 6px 8px;\n border: 1px solid #cdd5df;\n border-radius: 5px;\n font-size: 13px;\n }\n textarea {\n min-height: 72px;\n resize: vertical;\n font-family: monospace;\n }\n .checks {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n margin: 4px 0 12px 0;\n }\n .checks label {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n color: #212529;\n font-weight: 400;\n }\n .hint {\n color: #8b95a1;\n font-size: 11px;\n grid-column: 2;\n margin-top: -4px;\n }\n `\n ]\n\n /** { name, meta, collectType } */\n @property({ type: Object }) metric: any = {}\n\n @state() widget = ''\n @state() min = ''\n @state() max = ''\n @state() step = ''\n @state() decimals = ''\n @state() placeholder = ''\n @state() optionsText = ''\n @state() readonly = false\n @state() required = false\n @state() hasPlan = false\n\n connectedCallback() {\n super.connectedCallback()\n const input = this.metric?.meta?.input || {}\n this.widget = input.widget || ''\n this.min = input.min !== undefined ? String(input.min) : ''\n this.max = input.max !== undefined ? String(input.max) : ''\n this.step = input.step !== undefined ? String(input.step) : ''\n this.decimals = input.decimals !== undefined ? String(input.decimals) : ''\n this.placeholder = input.placeholder || ''\n this.optionsText = (input.options || []).map((o: any) => `${o.value}|${o.label ?? o.value}`).join('\\n')\n this.readonly = !!input.readonly\n this.required = !!input.required\n this.hasPlan = !!input.hasPlan\n }\n\n render() {\n const w = this.widget\n return html`\n <div class=\"content\">\n <h3>입력 힌트 · ${this.metric?.name || ''}</h3>\n <div class=\"sub\">값 입력 화면(월별/완료평가 등)이 이 힌트로 위젯을 그립니다. 위젯을 비우면 힌트가 제거되어 숫자 입력으로 폴백합니다.</div>\n\n <div class=\"field\">\n <label>위젯</label>\n <select .value=${w} @change=${(e: any) => (this.widget = e.target.value)}>\n <option value=\"\">(자동/폴백 — 숫자)</option>\n <option value=\"number\" ?selected=${w === 'number'}>number — 숫자</option>\n <option value=\"rating\" ?selected=${w === 'rating'}>rating — 별점</option>\n <option value=\"select\" ?selected=${w === 'select'}>select — 선택목록</option>\n <option value=\"toggle\" ?selected=${w === 'toggle'}>toggle — 스위치</option>\n <option value=\"text\" ?selected=${w === 'text'}>text — 텍스트</option>\n <option value=\"date\" ?selected=${w === 'date'}>date — 날짜</option>\n </select>\n </div>\n\n ${w === 'number' || w === 'rating'\n ? html`\n ${w === 'number'\n ? html`<div class=\"field\">\n <label>최소</label>\n <input type=\"number\" .value=${this.min} @input=${(e: any) => (this.min = e.target.value)} />\n </div>`\n : ''}\n <div class=\"field\">\n <label>최대</label>\n <input type=\"number\" .value=${this.max} @input=${(e: any) => (this.max = e.target.value)} />\n ${w === 'rating' ? html`<span class=\"hint\">별 개수 (기본 5)</span>` : ''}\n </div>\n <div class=\"field\">\n <label>스텝</label>\n <input type=\"number\" .value=${this.step} @input=${(e: any) => (this.step = e.target.value)} />\n ${w === 'rating' ? html`<span class=\"hint\">1=정수, 0.5=반별 (기본 1)</span>` : ''}\n </div>\n ${w === 'number'\n ? html`<div class=\"field\">\n <label>소수자리</label>\n <input type=\"number\" .value=${this.decimals} @input=${(e: any) => (this.decimals = e.target.value)} />\n </div>`\n : ''}\n `\n : ''}\n ${w === 'select'\n ? html`\n <div class=\"field\">\n <label>옵션</label>\n <textarea\n .value=${this.optionsText}\n placeholder=\"한 줄에 하나: 값|표시라벨&#10;예) 1|양호&#10;2|보통\"\n @input=${(e: any) => (this.optionsText = e.target.value)}\n ></textarea>\n <span class=\"hint\">한 줄당 <code>값|라벨</code> (라벨 생략 시 값 사용)</span>\n </div>\n `\n : ''}\n ${w === 'text'\n ? html`<div class=\"field\">\n <label>placeholder</label>\n <input type=\"text\" .value=${this.placeholder} @input=${(e: any) => (this.placeholder = e.target.value)} />\n </div>`\n : ''}\n\n ${w\n ? html`<div class=\"checks\">\n <label><input type=\"checkbox\" .checked=${this.readonly} @change=${(e: any) => (this.readonly = e.target.checked)} /> 읽기전용</label>\n <label><input type=\"checkbox\" .checked=${this.required} @change=${(e: any) => (this.required = e.target.checked)} /> 필수</label>\n <label><input type=\"checkbox\" .checked=${this.hasPlan} @change=${(e: any) => (this.hasPlan = e.target.checked)} /> 계획/실제 2열</label>\n </div>`\n : ''}\n </div>\n\n <div class=\"footer\">\n ${this.metric?.meta?.input\n ? html`<button danger @click=${this._clear}><md-icon>delete</md-icon>힌트 삭제</button>`\n : ''}\n <div filler></div>\n <button @click=${this._cancel}><md-icon>cancel</md-icon>취소</button>\n <button done @click=${this._save}><md-icon>done</md-icon>저장</button>\n </div>\n `\n }\n\n private _num(v: string): number | undefined {\n if (v === '' || v === null || v === undefined) return undefined\n const n = Number(v)\n return Number.isNaN(n) ? undefined : n\n }\n\n private _buildInput(): any {\n if (!this.widget) return undefined\n const input: any = { widget: this.widget }\n\n if (this.widget === 'number' || this.widget === 'rating') {\n const min = this._num(this.min)\n const max = this._num(this.max)\n const step = this._num(this.step)\n const decimals = this._num(this.decimals)\n if (this.widget === 'number' && min !== undefined) input.min = min\n if (max !== undefined) input.max = max\n if (step !== undefined) input.step = step\n if (this.widget === 'number' && decimals !== undefined) input.decimals = decimals\n }\n\n if (this.widget === 'select') {\n const options = this.optionsText\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => {\n const [value, label] = line.split('|').map(s => s.trim())\n return { value, label: label || value }\n })\n if (options.length) input.options = options\n }\n\n if (this.widget === 'text' && this.placeholder) input.placeholder = this.placeholder\n\n if (this.readonly) input.readonly = true\n if (this.required) input.required = true\n if (this.hasPlan) input.hasPlan = true\n\n return input\n }\n\n /** 기존 meta 는 보존하고 input 만 교체(또는 삭제). */\n private _buildMeta(): any {\n const rest = { ...(this.metric?.meta || {}) }\n delete rest.input\n const input = this._buildInput()\n const meta = input ? { ...rest, input } : rest\n return Object.keys(meta).length ? meta : null\n }\n\n private _save() {\n this.dispatchEvent(\n new CustomEvent('metric-meta-save', { detail: { meta: this._buildMeta() }, bubbles: true, composed: true })\n )\n }\n\n private _clear() {\n this.widget = ''\n this.dispatchEvent(\n new CustomEvent('metric-meta-save', { detail: { meta: this._buildMeta() }, bubbles: true, composed: true })\n )\n }\n\n private _cancel() {\n this.dispatchEvent(new CustomEvent('metric-meta-cancel', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export type InputWidget = 'number' | 'rating' | 'select' | 'date' | 'text' | 'toggle';
2
+ export interface InputHint {
3
+ widget: InputWidget;
4
+ min?: number;
5
+ max?: number;
6
+ step?: number;
7
+ options?: {
8
+ value: string | number;
9
+ label: string;
10
+ }[];
11
+ required?: boolean;
12
+ decimals?: number;
13
+ readonly?: boolean;
14
+ hasPlan?: boolean;
15
+ placeholder?: string;
16
+ default?: any;
17
+ }
18
+ export interface KpiMetricLike {
19
+ meta?: {
20
+ input?: InputHint;
21
+ [k: string]: any;
22
+ } | null;
23
+ collectType?: string;
24
+ }
25
+ /** meta.input 우선, 없으면 number 폴백(이름추측 금지). readonly 는 명시값 우선, 미지정+AUTO 면 true. */
26
+ export declare function resolveInputHint(metric: KpiMetricLike | null | undefined): InputHint;
@@ -0,0 +1,19 @@
1
+ // 클라이언트용 InputHint 타입 + resolveInputHint.
2
+ //
3
+ // ⚠️ 원본(진실의 원천): server/service/kpi-metric/kpi-metric-meta.ts
4
+ // client/server tsconfig 가 분리되어 server 를 import 할 수 없어 동형 복제한다.
5
+ // 변경 시 양쪽을 함께 수정할 것.
6
+ /** meta.input 우선, 없으면 number 폴백(이름추측 금지). readonly 는 명시값 우선, 미지정+AUTO 면 true. */
7
+ export function resolveInputHint(metric) {
8
+ const isAuto = metric?.collectType === 'AUTO';
9
+ const hint = metric?.meta?.input;
10
+ if (hint?.widget) {
11
+ const readonly = hint.readonly ?? isAuto;
12
+ if (hint.widget === 'rating') {
13
+ return { ...hint, max: hint.max ?? 5, step: hint.step ?? 1, readonly };
14
+ }
15
+ return { ...hint, readonly };
16
+ }
17
+ return { widget: 'number', readonly: isAuto };
18
+ }
19
+ //# sourceMappingURL=metric-input-hint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-input-hint.js","sourceRoot":"","sources":["../../client/viewparts/metric-input-hint.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,8DAA8D;AAC9D,mEAAmE;AACnE,wBAAwB;AAuBxB,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,MAAwC;IACvE,MAAM,MAAM,GAAG,MAAM,EAAE,WAAW,KAAK,MAAM,CAAA;IAC7C,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,CAAA;IAEhC,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAA;QACxC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAA;QACxE,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAA;IAC9B,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;AAC/C,CAAC","sourcesContent":["// 클라이언트용 InputHint 타입 + resolveInputHint.\n//\n// ⚠️ 원본(진실의 원천): server/service/kpi-metric/kpi-metric-meta.ts\n// client/server tsconfig 가 분리되어 server 를 import 할 수 없어 동형 복제한다.\n// 변경 시 양쪽을 함께 수정할 것.\n\nexport type InputWidget = 'number' | 'rating' | 'select' | 'date' | 'text' | 'toggle'\n\nexport interface InputHint {\n widget: InputWidget\n min?: number\n max?: number\n step?: number\n options?: { value: string | number; label: string }[]\n required?: boolean\n decimals?: number\n readonly?: boolean\n hasPlan?: boolean\n placeholder?: string\n default?: any\n}\n\nexport interface KpiMetricLike {\n meta?: { input?: InputHint; [k: string]: any } | null\n collectType?: string\n}\n\n/** meta.input 우선, 없으면 number 폴백(이름추측 금지). readonly 는 명시값 우선, 미지정+AUTO 면 true. */\nexport function resolveInputHint(metric: KpiMetricLike | null | undefined): InputHint {\n const isAuto = metric?.collectType === 'AUTO'\n const hint = metric?.meta?.input\n\n if (hint?.widget) {\n const readonly = hint.readonly ?? isAuto\n if (hint.widget === 'rating') {\n return { ...hint, max: hint.max ?? 5, step: hint.step ?? 1, readonly }\n }\n return { ...hint, readonly }\n }\n return { widget: 'number', readonly: isAuto }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import { resolveInputHint } from './metric-input-hint';
2
+ import { MetricRendererRegistry } from './metric-renderer-registry';
3
+ describe('resolveInputHint (client copy)', () => {
4
+ it('meta 없음 → number 폴백', () => {
5
+ expect(resolveInputHint(null)).toEqual({ widget: 'number', readonly: false });
6
+ expect(resolveInputHint({ collectType: 'AUTO' })).toEqual({ widget: 'number', readonly: true });
7
+ });
8
+ it('rating 기본값(max 5, step 1)', () => {
9
+ expect(resolveInputHint({ meta: { input: { widget: 'rating' } } })).toEqual({
10
+ widget: 'rating',
11
+ max: 5,
12
+ step: 1,
13
+ readonly: false
14
+ });
15
+ });
16
+ it('readonly 명시 false 는 AUTO 라도 존중', () => {
17
+ expect(resolveInputHint({ collectType: 'AUTO', meta: { input: { widget: 'number', readonly: false } } }).readonly).toBe(false);
18
+ });
19
+ });
20
+ describe('MetricRendererRegistry', () => {
21
+ const dummy = () => null;
22
+ beforeEach(() => MetricRendererRegistry.clear());
23
+ it('매칭 없으면 undefined (→ 제네릭)', () => {
24
+ expect(MetricRendererRegistry.resolve({ meta: {} })).toBeUndefined();
25
+ });
26
+ it('predicate 매칭 시 렌더러 반환, 먼저 등록된 것 우선', () => {
27
+ const r1 = () => 'r1';
28
+ const r2 = () => 'r2';
29
+ MetricRendererRegistry.register((m) => m.name === 'X', r1);
30
+ MetricRendererRegistry.register((m) => m.name === 'X', r2);
31
+ expect(MetricRendererRegistry.resolve({ name: 'X' })).toBe(r1);
32
+ expect(MetricRendererRegistry.resolve({ name: 'Y' })).toBeUndefined();
33
+ });
34
+ it('predicate 예외는 매칭 실패로 처리(다음으로 진행)', () => {
35
+ MetricRendererRegistry.register(() => {
36
+ throw new Error('boom');
37
+ }, dummy);
38
+ const ok = () => 'ok';
39
+ MetricRendererRegistry.register((m) => m.name === 'Z', ok);
40
+ expect(MetricRendererRegistry.resolve({ name: 'Z' })).toBe(ok);
41
+ });
42
+ });
43
+ //# sourceMappingURL=metric-input.test.js.map