terrier-engine 4.4.0 → 4.4.3

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 (313) hide show
  1. package/data-dive/dd-app.ts +45 -0
  2. package/data-dive/dd-db.ts +12 -0
  3. package/data-dive/dd-routes.ts +10 -0
  4. package/data-dive/dd-session.ts +45 -0
  5. package/data-dive/dd-user.ts +12 -0
  6. package/data-dive/dives/dive-editor.ts +244 -0
  7. package/data-dive/dives/dive-list.ts +164 -0
  8. package/data-dive/dives/dive-runs.ts +272 -0
  9. package/data-dive/dives/dive-settings.ts +227 -0
  10. package/data-dive/dives/dives.ts +81 -0
  11. package/data-dive/dives/group-editor.ts +139 -0
  12. package/data-dive/gen/models.ts +192 -0
  13. package/data-dive/queries/columns.ts +355 -0
  14. package/data-dive/queries/dates.ts +286 -0
  15. package/data-dive/queries/filters.ts +723 -0
  16. package/data-dive/queries/queries.ts +263 -0
  17. package/data-dive/queries/query-editor.ts +232 -0
  18. package/data-dive/queries/query-form.ts +51 -0
  19. package/data-dive/queries/tables.ts +395 -0
  20. package/data-dive/queries/test/dates.test.ts +178 -0
  21. package/package.json +1 -1
  22. package/{parts → terrier/parts}/panel-part.ts +5 -1
  23. package/tsconfig.json +21 -0
  24. /package/{README.md → terrier/README.md} +0 -0
  25. /package/{api.ts → terrier/api.ts} +0 -0
  26. /package/{app.ts → terrier/app.ts} +0 -0
  27. /package/{attachments.ts → terrier/attachments.ts} +0 -0
  28. /package/{db-client.ts → terrier/db-client.ts} +0 -0
  29. /package/{dropdowns.ts → terrier/dropdowns.ts} +0 -0
  30. /package/{format.ts → terrier/format.ts} +0 -0
  31. /package/{forms.ts → terrier/forms.ts} +0 -0
  32. /package/{fragments.ts → terrier/fragments.ts} +0 -0
  33. /package/{gen → terrier/gen}/hub-icons.ts +0 -0
  34. /package/{glyps.ts → terrier/glyps.ts} +0 -0
  35. /package/{ids.ts → terrier/ids.ts} +0 -0
  36. /package/{images → terrier/images}/icons/active.svg +0 -0
  37. /package/{images → terrier/images}/icons/admin.svg +0 -0
  38. /package/{images → terrier/images}/icons/archive.svg +0 -0
  39. /package/{images → terrier/images}/icons/arrow_down.svg +0 -0
  40. /package/{images → terrier/images}/icons/arrow_left.svg +0 -0
  41. /package/{images → terrier/images}/icons/arrow_right.svg +0 -0
  42. /package/{images → terrier/images}/icons/arrow_up.svg +0 -0
  43. /package/{images → terrier/images}/icons/assign.svg +0 -0
  44. /package/{images → terrier/images}/icons/attachment.svg +0 -0
  45. /package/{images → terrier/images}/icons/back.svg +0 -0
  46. /package/{images → terrier/images}/icons/badge.svg +0 -0
  47. /package/{images → terrier/images}/icons/board.svg +0 -0
  48. /package/{images → terrier/images}/icons/branch.svg +0 -0
  49. /package/{images → terrier/images}/icons/bug.svg +0 -0
  50. /package/{images → terrier/images}/icons/calculator.svg +0 -0
  51. /package/{images → terrier/images}/icons/checkmark.svg +0 -0
  52. /package/{images → terrier/images}/icons/close.svg +0 -0
  53. /package/{images → terrier/images}/icons/clypboard.svg +0 -0
  54. /package/{images → terrier/images}/icons/comment.svg +0 -0
  55. /package/{images → terrier/images}/icons/complete.svg +0 -0
  56. /package/{images → terrier/images}/icons/dashboard.svg +0 -0
  57. /package/{images → terrier/images}/icons/data_pull.svg +0 -0
  58. /package/{images → terrier/images}/icons/data_update.svg +0 -0
  59. /package/{images → terrier/images}/icons/database.svg +0 -0
  60. /package/{images → terrier/images}/icons/day.svg +0 -0
  61. /package/{images → terrier/images}/icons/delete.svg +0 -0
  62. /package/{images → terrier/images}/icons/documentation.svg +0 -0
  63. /package/{images → terrier/images}/icons/edit.svg +0 -0
  64. /package/{images → terrier/images}/icons/feature.svg +0 -0
  65. /package/{images → terrier/images}/icons/flex.svg +0 -0
  66. /package/{images → terrier/images}/icons/forward.svg +0 -0
  67. /package/{images → terrier/images}/icons/github.svg +0 -0
  68. /package/{images → terrier/images}/icons/history.svg +0 -0
  69. /package/{images → terrier/images}/icons/home.svg +0 -0
  70. /package/{images → terrier/images}/icons/image.svg +0 -0
  71. /package/{images → terrier/images}/icons/inbox.svg +0 -0
  72. /package/{images → terrier/images}/icons/info.svg +0 -0
  73. /package/{images → terrier/images}/icons/issue.svg +0 -0
  74. /package/{images → terrier/images}/icons/lane.svg +0 -0
  75. /package/{images → terrier/images}/icons/lane_asap.svg +0 -0
  76. /package/{images → terrier/images}/icons/lane_days.svg +0 -0
  77. /package/{images → terrier/images}/icons/lane_hours.svg +0 -0
  78. /package/{images → terrier/images}/icons/lane_weeks.svg +0 -0
  79. /package/{images → terrier/images}/icons/lanes_board.svg +0 -0
  80. /package/{images → terrier/images}/icons/level_complete.svg +0 -0
  81. /package/{images → terrier/images}/icons/level_highway.svg +0 -0
  82. /package/{images → terrier/images}/icons/level_on_ramp.svg +0 -0
  83. /package/{images → terrier/images}/icons/level_parking.svg +0 -0
  84. /package/{images → terrier/images}/icons/minus.svg +0 -0
  85. /package/{images → terrier/images}/icons/night.svg +0 -0
  86. /package/{images → terrier/images}/icons/origin.svg +0 -0
  87. /package/{images → terrier/images}/icons/pending.svg +0 -0
  88. /package/{images → terrier/images}/icons/plus.svg +0 -0
  89. /package/{images → terrier/images}/icons/post.svg +0 -0
  90. /package/{images → terrier/images}/icons/pr_closed.svg +0 -0
  91. /package/{images → terrier/images}/icons/pr_merged.svg +0 -0
  92. /package/{images → terrier/images}/icons/pr_open.svg +0 -0
  93. /package/{images → terrier/images}/icons/prioritized.svg +0 -0
  94. /package/{images → terrier/images}/icons/project.svg +0 -0
  95. /package/{images → terrier/images}/icons/question.svg +0 -0
  96. /package/{images → terrier/images}/icons/reaction.svg +0 -0
  97. /package/{images → terrier/images}/icons/recent.svg +0 -0
  98. /package/{images → terrier/images}/icons/refresh.svg +0 -0
  99. /package/{images → terrier/images}/icons/request.svg +0 -0
  100. /package/{images → terrier/images}/icons/settings.svg +0 -0
  101. /package/{images → terrier/images}/icons/status.svg +0 -0
  102. /package/{images → terrier/images}/icons/step_deploy.svg +0 -0
  103. /package/{images → terrier/images}/icons/step_develop.svg +0 -0
  104. /package/{images → terrier/images}/icons/step_investigate.svg +0 -0
  105. /package/{images → terrier/images}/icons/step_review.svg +0 -0
  106. /package/{images → terrier/images}/icons/step_test.svg +0 -0
  107. /package/{images → terrier/images}/icons/steps.svg +0 -0
  108. /package/{images → terrier/images}/icons/steps_board.svg +0 -0
  109. /package/{images → terrier/images}/icons/subscribe.svg +0 -0
  110. /package/{images → terrier/images}/icons/support.svg +0 -0
  111. /package/{images → terrier/images}/icons/terrier.svg +0 -0
  112. /package/{images → terrier/images}/icons/thumbs_up.svg +0 -0
  113. /package/{images → terrier/images}/icons/type.svg +0 -0
  114. /package/{images → terrier/images}/icons/unprioritized.svg +0 -0
  115. /package/{images → terrier/images}/icons/upload.svg +0 -0
  116. /package/{images → terrier/images}/icons/user.svg +0 -0
  117. /package/{images → terrier/images}/icons/users.svg +0 -0
  118. /package/{images → terrier/images}/optimized/icon-active.svg +0 -0
  119. /package/{images → terrier/images}/optimized/icon-admin.svg +0 -0
  120. /package/{images → terrier/images}/optimized/icon-archive.svg +0 -0
  121. /package/{images → terrier/images}/optimized/icon-arrow_down.svg +0 -0
  122. /package/{images → terrier/images}/optimized/icon-arrow_left.svg +0 -0
  123. /package/{images → terrier/images}/optimized/icon-arrow_right.svg +0 -0
  124. /package/{images → terrier/images}/optimized/icon-arrow_up.svg +0 -0
  125. /package/{images → terrier/images}/optimized/icon-assign.svg +0 -0
  126. /package/{images → terrier/images}/optimized/icon-attachment.svg +0 -0
  127. /package/{images → terrier/images}/optimized/icon-back.svg +0 -0
  128. /package/{images → terrier/images}/optimized/icon-badge.svg +0 -0
  129. /package/{images → terrier/images}/optimized/icon-board.svg +0 -0
  130. /package/{images → terrier/images}/optimized/icon-branch.svg +0 -0
  131. /package/{images → terrier/images}/optimized/icon-bug.svg +0 -0
  132. /package/{images → terrier/images}/optimized/icon-calculator.svg +0 -0
  133. /package/{images → terrier/images}/optimized/icon-checkmark.svg +0 -0
  134. /package/{images → terrier/images}/optimized/icon-close.svg +0 -0
  135. /package/{images → terrier/images}/optimized/icon-clypboard.svg +0 -0
  136. /package/{images → terrier/images}/optimized/icon-comment.svg +0 -0
  137. /package/{images → terrier/images}/optimized/icon-complete.svg +0 -0
  138. /package/{images → terrier/images}/optimized/icon-dashboard.svg +0 -0
  139. /package/{images → terrier/images}/optimized/icon-data_pull.svg +0 -0
  140. /package/{images → terrier/images}/optimized/icon-data_update.svg +0 -0
  141. /package/{images → terrier/images}/optimized/icon-database.svg +0 -0
  142. /package/{images → terrier/images}/optimized/icon-day.svg +0 -0
  143. /package/{images → terrier/images}/optimized/icon-delete.svg +0 -0
  144. /package/{images → terrier/images}/optimized/icon-documentation.svg +0 -0
  145. /package/{images → terrier/images}/optimized/icon-edit.svg +0 -0
  146. /package/{images → terrier/images}/optimized/icon-feature.svg +0 -0
  147. /package/{images → terrier/images}/optimized/icon-flex.svg +0 -0
  148. /package/{images → terrier/images}/optimized/icon-forward.svg +0 -0
  149. /package/{images → terrier/images}/optimized/icon-github.svg +0 -0
  150. /package/{images → terrier/images}/optimized/icon-history.svg +0 -0
  151. /package/{images → terrier/images}/optimized/icon-home.svg +0 -0
  152. /package/{images → terrier/images}/optimized/icon-image.svg +0 -0
  153. /package/{images → terrier/images}/optimized/icon-inbox.svg +0 -0
  154. /package/{images → terrier/images}/optimized/icon-info.svg +0 -0
  155. /package/{images → terrier/images}/optimized/icon-issue.svg +0 -0
  156. /package/{images → terrier/images}/optimized/icon-lane.svg +0 -0
  157. /package/{images → terrier/images}/optimized/icon-lane_asap.svg +0 -0
  158. /package/{images → terrier/images}/optimized/icon-lane_days.svg +0 -0
  159. /package/{images → terrier/images}/optimized/icon-lane_hours.svg +0 -0
  160. /package/{images → terrier/images}/optimized/icon-lane_weeks.svg +0 -0
  161. /package/{images → terrier/images}/optimized/icon-lanes_board.svg +0 -0
  162. /package/{images → terrier/images}/optimized/icon-level_complete.svg +0 -0
  163. /package/{images → terrier/images}/optimized/icon-level_highway.svg +0 -0
  164. /package/{images → terrier/images}/optimized/icon-level_on_ramp.svg +0 -0
  165. /package/{images → terrier/images}/optimized/icon-level_parking.svg +0 -0
  166. /package/{images → terrier/images}/optimized/icon-minus.svg +0 -0
  167. /package/{images → terrier/images}/optimized/icon-night.svg +0 -0
  168. /package/{images → terrier/images}/optimized/icon-origin.svg +0 -0
  169. /package/{images → terrier/images}/optimized/icon-pending.svg +0 -0
  170. /package/{images → terrier/images}/optimized/icon-plus.svg +0 -0
  171. /package/{images → terrier/images}/optimized/icon-post.svg +0 -0
  172. /package/{images → terrier/images}/optimized/icon-pr_closed.svg +0 -0
  173. /package/{images → terrier/images}/optimized/icon-pr_merged.svg +0 -0
  174. /package/{images → terrier/images}/optimized/icon-pr_open.svg +0 -0
  175. /package/{images → terrier/images}/optimized/icon-prioritized.svg +0 -0
  176. /package/{images → terrier/images}/optimized/icon-project.svg +0 -0
  177. /package/{images → terrier/images}/optimized/icon-question.svg +0 -0
  178. /package/{images → terrier/images}/optimized/icon-reaction.svg +0 -0
  179. /package/{images → terrier/images}/optimized/icon-recent.svg +0 -0
  180. /package/{images → terrier/images}/optimized/icon-refresh.svg +0 -0
  181. /package/{images → terrier/images}/optimized/icon-request.svg +0 -0
  182. /package/{images → terrier/images}/optimized/icon-settings.svg +0 -0
  183. /package/{images → terrier/images}/optimized/icon-status.svg +0 -0
  184. /package/{images → terrier/images}/optimized/icon-step_deploy.svg +0 -0
  185. /package/{images → terrier/images}/optimized/icon-step_develop.svg +0 -0
  186. /package/{images → terrier/images}/optimized/icon-step_investigate.svg +0 -0
  187. /package/{images → terrier/images}/optimized/icon-step_review.svg +0 -0
  188. /package/{images → terrier/images}/optimized/icon-step_test.svg +0 -0
  189. /package/{images → terrier/images}/optimized/icon-steps.svg +0 -0
  190. /package/{images → terrier/images}/optimized/icon-steps_board.svg +0 -0
  191. /package/{images → terrier/images}/optimized/icon-subscribe.svg +0 -0
  192. /package/{images → terrier/images}/optimized/icon-support.svg +0 -0
  193. /package/{images → terrier/images}/optimized/icon-terrier.svg +0 -0
  194. /package/{images → terrier/images}/optimized/icon-thumbs_up.svg +0 -0
  195. /package/{images → terrier/images}/optimized/icon-type.svg +0 -0
  196. /package/{images → terrier/images}/optimized/icon-unprioritized.svg +0 -0
  197. /package/{images → terrier/images}/optimized/icon-upload.svg +0 -0
  198. /package/{images → terrier/images}/optimized/icon-user.svg +0 -0
  199. /package/{images → terrier/images}/optimized/icon-users.svg +0 -0
  200. /package/{images → terrier/images}/optimized/terrier-hub-favicon.svg +0 -0
  201. /package/{images → terrier/images}/optimized/terrier-hub-icon-dark.svg +0 -0
  202. /package/{images → terrier/images}/optimized/terrier-hub-icon-light.svg +0 -0
  203. /package/{images → terrier/images}/optimized/terrier-hub-loader.svg +0 -0
  204. /package/{images → terrier/images}/optimized/terrier-hub-logo-dark.svg +0 -0
  205. /package/{images → terrier/images}/optimized/terrier-hub-logo-light.svg +0 -0
  206. /package/{images → terrier/images}/raw/icon-active.svg +0 -0
  207. /package/{images → terrier/images}/raw/icon-admin.svg +0 -0
  208. /package/{images → terrier/images}/raw/icon-archive.svg +0 -0
  209. /package/{images → terrier/images}/raw/icon-arrow_down.svg +0 -0
  210. /package/{images → terrier/images}/raw/icon-arrow_left.svg +0 -0
  211. /package/{images → terrier/images}/raw/icon-arrow_right.svg +0 -0
  212. /package/{images → terrier/images}/raw/icon-arrow_up.svg +0 -0
  213. /package/{images → terrier/images}/raw/icon-assign.svg +0 -0
  214. /package/{images → terrier/images}/raw/icon-attachment.svg +0 -0
  215. /package/{images → terrier/images}/raw/icon-back.svg +0 -0
  216. /package/{images → terrier/images}/raw/icon-badge.svg +0 -0
  217. /package/{images → terrier/images}/raw/icon-board.svg +0 -0
  218. /package/{images → terrier/images}/raw/icon-branch.svg +0 -0
  219. /package/{images → terrier/images}/raw/icon-bug.svg +0 -0
  220. /package/{images → terrier/images}/raw/icon-calculator.svg +0 -0
  221. /package/{images → terrier/images}/raw/icon-checkmark.svg +0 -0
  222. /package/{images → terrier/images}/raw/icon-close.svg +0 -0
  223. /package/{images → terrier/images}/raw/icon-clypboard.svg +0 -0
  224. /package/{images → terrier/images}/raw/icon-comment.svg +0 -0
  225. /package/{images → terrier/images}/raw/icon-complete.svg +0 -0
  226. /package/{images → terrier/images}/raw/icon-dashboard.svg +0 -0
  227. /package/{images → terrier/images}/raw/icon-data_pull.svg +0 -0
  228. /package/{images → terrier/images}/raw/icon-data_update.svg +0 -0
  229. /package/{images → terrier/images}/raw/icon-database.svg +0 -0
  230. /package/{images → terrier/images}/raw/icon-day.svg +0 -0
  231. /package/{images → terrier/images}/raw/icon-delete.svg +0 -0
  232. /package/{images → terrier/images}/raw/icon-documentation.svg +0 -0
  233. /package/{images → terrier/images}/raw/icon-edit.svg +0 -0
  234. /package/{images → terrier/images}/raw/icon-feature.svg +0 -0
  235. /package/{images → terrier/images}/raw/icon-flex.svg +0 -0
  236. /package/{images → terrier/images}/raw/icon-forward.svg +0 -0
  237. /package/{images → terrier/images}/raw/icon-github.svg +0 -0
  238. /package/{images → terrier/images}/raw/icon-history.svg +0 -0
  239. /package/{images → terrier/images}/raw/icon-home.svg +0 -0
  240. /package/{images → terrier/images}/raw/icon-image.svg +0 -0
  241. /package/{images → terrier/images}/raw/icon-inbox.svg +0 -0
  242. /package/{images → terrier/images}/raw/icon-info.svg +0 -0
  243. /package/{images → terrier/images}/raw/icon-issue.svg +0 -0
  244. /package/{images → terrier/images}/raw/icon-lane.svg +0 -0
  245. /package/{images → terrier/images}/raw/icon-lane_asap.svg +0 -0
  246. /package/{images → terrier/images}/raw/icon-lane_days.svg +0 -0
  247. /package/{images → terrier/images}/raw/icon-lane_hours.svg +0 -0
  248. /package/{images → terrier/images}/raw/icon-lane_weeks.svg +0 -0
  249. /package/{images → terrier/images}/raw/icon-lanes_board.svg +0 -0
  250. /package/{images → terrier/images}/raw/icon-level_complete.svg +0 -0
  251. /package/{images → terrier/images}/raw/icon-level_highway.svg +0 -0
  252. /package/{images → terrier/images}/raw/icon-level_on_ramp.svg +0 -0
  253. /package/{images → terrier/images}/raw/icon-level_parking.svg +0 -0
  254. /package/{images → terrier/images}/raw/icon-minus.svg +0 -0
  255. /package/{images → terrier/images}/raw/icon-night.svg +0 -0
  256. /package/{images → terrier/images}/raw/icon-origin.svg +0 -0
  257. /package/{images → terrier/images}/raw/icon-pending.svg +0 -0
  258. /package/{images → terrier/images}/raw/icon-plus.svg +0 -0
  259. /package/{images → terrier/images}/raw/icon-post.svg +0 -0
  260. /package/{images → terrier/images}/raw/icon-pr_closed.svg +0 -0
  261. /package/{images → terrier/images}/raw/icon-pr_merged.svg +0 -0
  262. /package/{images → terrier/images}/raw/icon-pr_open.svg +0 -0
  263. /package/{images → terrier/images}/raw/icon-prioritized.svg +0 -0
  264. /package/{images → terrier/images}/raw/icon-project.svg +0 -0
  265. /package/{images → terrier/images}/raw/icon-question.svg +0 -0
  266. /package/{images → terrier/images}/raw/icon-reaction.svg +0 -0
  267. /package/{images → terrier/images}/raw/icon-recent.svg +0 -0
  268. /package/{images → terrier/images}/raw/icon-refresh.svg +0 -0
  269. /package/{images → terrier/images}/raw/icon-request.svg +0 -0
  270. /package/{images → terrier/images}/raw/icon-settings.svg +0 -0
  271. /package/{images → terrier/images}/raw/icon-status.svg +0 -0
  272. /package/{images → terrier/images}/raw/icon-step_deploy.svg +0 -0
  273. /package/{images → terrier/images}/raw/icon-step_develop.svg +0 -0
  274. /package/{images → terrier/images}/raw/icon-step_investigate.svg +0 -0
  275. /package/{images → terrier/images}/raw/icon-step_review.svg +0 -0
  276. /package/{images → terrier/images}/raw/icon-step_test.svg +0 -0
  277. /package/{images → terrier/images}/raw/icon-steps.svg +0 -0
  278. /package/{images → terrier/images}/raw/icon-steps_board.svg +0 -0
  279. /package/{images → terrier/images}/raw/icon-subscribe.svg +0 -0
  280. /package/{images → terrier/images}/raw/icon-support.svg +0 -0
  281. /package/{images → terrier/images}/raw/icon-terrier.svg +0 -0
  282. /package/{images → terrier/images}/raw/icon-thumbs_up.svg +0 -0
  283. /package/{images → terrier/images}/raw/icon-type.svg +0 -0
  284. /package/{images → terrier/images}/raw/icon-unprioritized.svg +0 -0
  285. /package/{images → terrier/images}/raw/icon-upload.svg +0 -0
  286. /package/{images → terrier/images}/raw/icon-user.svg +0 -0
  287. /package/{images → terrier/images}/raw/icon-users.svg +0 -0
  288. /package/{images → terrier/images}/raw/terrier-hub-favicon-alert.png +0 -0
  289. /package/{images → terrier/images}/raw/terrier-hub-favicon-dark.png +0 -0
  290. /package/{images → terrier/images}/raw/terrier-hub-favicon.png +0 -0
  291. /package/{images → terrier/images}/raw/terrier-hub-favicon.svg +0 -0
  292. /package/{images → terrier/images}/raw/terrier-hub-icon-dark.svg +0 -0
  293. /package/{images → terrier/images}/raw/terrier-hub-icon-light.png +0 -0
  294. /package/{images → terrier/images}/raw/terrier-hub-icon-light.svg +0 -0
  295. /package/{images → terrier/images}/raw/terrier-hub-loader.svg +0 -0
  296. /package/{images → terrier/images}/raw/terrier-hub-logo-dark.svg +0 -0
  297. /package/{images → terrier/images}/raw/terrier-hub-logo-light.png +0 -0
  298. /package/{images → terrier/images}/raw/terrier-hub-logo-light.svg +0 -0
  299. /package/{lightbox.ts → terrier/lightbox.ts} +0 -0
  300. /package/{loading.ts → terrier/loading.ts} +0 -0
  301. /package/{modals.ts → terrier/modals.ts} +0 -0
  302. /package/{overlays.ts → terrier/overlays.ts} +0 -0
  303. /package/{parts → terrier/parts}/content-part.ts +0 -0
  304. /package/{parts → terrier/parts}/not-found-page.ts +0 -0
  305. /package/{parts → terrier/parts}/page-part.ts +0 -0
  306. /package/{parts → terrier/parts}/terrier-form-part.ts +0 -0
  307. /package/{parts → terrier/parts}/terrier-part.ts +0 -0
  308. /package/{schema.ts → terrier/schema.ts} +0 -0
  309. /package/{sheets.ts → terrier/sheets.ts} +0 -0
  310. /package/{tabs.ts → terrier/tabs.ts} +0 -0
  311. /package/{theme.ts → terrier/theme.ts} +0 -0
  312. /package/{toasts.ts → terrier/toasts.ts} +0 -0
  313. /package/{tooltips.ts → terrier/tooltips.ts} +0 -0
@@ -0,0 +1,263 @@
1
+ import {TableRef} from "./tables"
2
+ import api, {ApiResponse} from "../../terrier/api"
3
+ import {PartTag} from "tuff-core/parts"
4
+ import {TableCellTag} from "tuff-core/html"
5
+ import dayjs from "dayjs"
6
+ import QueryEditor from "./query-editor"
7
+ import TerrierPart from "../../terrier/parts/terrier-part"
8
+ import Schema, {ModelDef, SchemaDef} from "../../terrier/schema"
9
+ import {arrays, messages} from "tuff-core"
10
+ import {Logger} from "tuff-core/logging"
11
+
12
+ const log = new Logger("Queries")
13
+
14
+
15
+ ////////////////////////////////////////////////////////////////////////////////
16
+ // Query
17
+ ////////////////////////////////////////////////////////////////////////////////
18
+
19
+ export type Query = {
20
+ id: string
21
+ name: string
22
+ notes: string
23
+ from: TableRef
24
+ }
25
+
26
+
27
+ ////////////////////////////////////////////////////////////////////////////////
28
+ // Validation
29
+ ////////////////////////////////////////////////////////////////////////////////
30
+
31
+ /**
32
+ * Type for the response to a server-side query validation.
33
+ */
34
+ export type QueryValidation = ApiResponse & {
35
+ query: Query
36
+ sql?: string
37
+ sql_html?: string
38
+ explain?: string
39
+ error?: string
40
+ error_html?: string
41
+ }
42
+
43
+ /**
44
+ * Has the server validate the given query and generate SQL for it.
45
+ * @param query
46
+ */
47
+ async function validate(query: Query): Promise<QueryValidation> {
48
+ return await api.post<QueryValidation>("/data_dive/validate_query.json", {query})
49
+ }
50
+
51
+
52
+ ////////////////////////////////////////////////////////////////////////////////
53
+ // Inputs
54
+ ////////////////////////////////////////////////////////////////////////////////
55
+
56
+
57
+
58
+ ////////////////////////////////////////////////////////////////////////////////
59
+ // Preview
60
+ ////////////////////////////////////////////////////////////////////////////////
61
+
62
+ export type QueryResultRow = Record<string, any>
63
+
64
+ const ColumnTypes = ['string', 'integer', 'float', 'date', 'time', 'dollars'] as const
65
+
66
+ export type ColumnType = typeof ColumnTypes[number]
67
+
68
+ export type QueryResultColumn = {
69
+ name: string
70
+ type: ColumnType
71
+ }
72
+
73
+ /**
74
+ * Type of the result of running the query on the server.
75
+ */
76
+ export type QueryResult = ApiResponse & {
77
+ rows?: QueryResultRow[]
78
+ columns?: QueryResultColumn[]
79
+ }
80
+
81
+ /**
82
+ * Executes the query on the server with a reasonable limit suitable for previewing the results.
83
+ * @param query
84
+ */
85
+ async function preview(query: Query): Promise<QueryResult> {
86
+ return await api.post<QueryResult>("/data_dive/preview_query.json", {query})
87
+ }
88
+
89
+
90
+ ////////////////////////////////////////////////////////////////////////////////
91
+ // Preview Rendering
92
+ ////////////////////////////////////////////////////////////////////////////////
93
+
94
+ const DateFormat = 'MM/DD/YY'
95
+
96
+ const TimeFormat = `h:mm A`
97
+
98
+ function renderCell(td: TableCellTag, col: QueryResultColumn, val: any): any {
99
+ td.class(col.type)
100
+ switch (col.type) {
101
+ case 'date':
102
+ const date = dayjs(val.toString())
103
+ return td.div('.date').text(date.format(DateFormat))
104
+ case 'time':
105
+ const time = dayjs(val.toString())
106
+ td.div('.date').text(time.format(DateFormat))
107
+ return td.div('.time').text(time.format(TimeFormat))
108
+ case 'dollars':
109
+ const dollars = parseFloat(val)
110
+ return td.div('.dollars').text(`\$${dollars}`)
111
+ case 'string':
112
+ if (col.name.endsWith('id')) {
113
+ const id = val.toString()
114
+ td.a('.id')
115
+ .data({tooltip: id})
116
+ .text(`...${id.substring(id.length-6)}`)
117
+ .emitClick(QueryEditor.copyToClipboardKey, {value: id})
118
+ }
119
+ else {
120
+ td.text(val.toString())
121
+ }
122
+ return
123
+ default:
124
+ td.text(val.toString())
125
+ }
126
+ td.text(val.toString())
127
+ }
128
+
129
+ function renderTable(parent: PartTag, rows: QueryResultRow[], columns: QueryResultColumn[]) {
130
+ parent.table('.dd-query-result', table => {
131
+ // header
132
+ table.thead(thead => {
133
+ thead.tr(tr => {
134
+ for (const col of columns) {
135
+ tr.th(col.type, th => {
136
+ th.a().text(col.name)
137
+ })
138
+ }
139
+ })
140
+ })
141
+
142
+ // body
143
+ table.tbody(tbody => {
144
+ for (const row of rows) {
145
+ tbody.tr(tr => {
146
+ for (const col of columns) {
147
+ tr.td(td => {
148
+ const val = row[col.name]
149
+ if (val) {
150
+ renderCell(td, col, val)
151
+ }
152
+ })
153
+ }
154
+ })
155
+ }
156
+ })
157
+ })
158
+ }
159
+
160
+ /**
161
+ * Renders a preview table if the result is successful, otherwise an error bubble.
162
+ * @param parent
163
+ * @param result
164
+ */
165
+ function renderPreview(parent: PartTag, result: QueryResult) {
166
+ if (result.rows && result.columns) {
167
+ renderTable(parent, result.rows, result.columns)
168
+ } else {
169
+ parent.div('.tt-bubble.alert').text(result.message)
170
+ }
171
+ }
172
+
173
+
174
+ ////////////////////////////////////////////////////////////////////////////////
175
+ // Model Picker
176
+ ////////////////////////////////////////////////////////////////////////////////
177
+
178
+ export type QueryModelPickerState = {
179
+ schema: SchemaDef
180
+ }
181
+
182
+ /**
183
+ * Presents a bunch of radio buttons to select the model for a query.
184
+ */
185
+ export class QueryModelPicker extends TerrierPart<QueryModelPickerState> {
186
+
187
+ pickedKey = messages.typedKey<{ model: string }>()
188
+ model?: ModelDef
189
+
190
+ async init() {
191
+
192
+ this.onChange(this.pickedKey, m => {
193
+ log.info(`Picked model ${m.data.model}`)
194
+ this.model = this.state.schema.models[m.data.model]
195
+ })
196
+ }
197
+
198
+
199
+ get parentClasses(): Array<string> {
200
+ return ['dd-query-model-picker', 'padded', 'tt-inset-box', 'tt-flex', 'column', 'gap']
201
+ }
202
+
203
+ renderModelOption(parent: PartTag, model: ModelDef) {
204
+ parent.label('.model-option', label => {
205
+ label.input({type: 'radio', name: `new-query-model-${this.id}`, value: model.name})
206
+ .emitChange(this.pickedKey, {model: model.name})
207
+ label.div(col => {
208
+ col.div('.name').text(model.name)
209
+ if (model.metadata?.description) {
210
+ col.div('.description').text(model.metadata.description)
211
+ }
212
+ })
213
+ })
214
+ }
215
+
216
+ render(parent: PartTag): any {
217
+ parent.h2('.centered', h2 => {
218
+ h2.i('.glyp-table')
219
+ h2.span().text("Select a Table")
220
+ })
221
+ parent.p('.caption').text("The table forms the basis of the query. Other tables can be joined into the query but they will all flow from the one selected below.")
222
+ parent.div('.tt-flex.gap.collapsible', row => {
223
+ row.div('.stretch.tt-flex.column.gap', col => {
224
+ const commonModels = Schema.commonModels(this.state.schema)
225
+ if (commonModels.length) {
226
+ col.h3(h3 => {
227
+ h3.i('.glyp-refresh')
228
+ h3.span().text("Common Tables")
229
+ })
230
+ for (const model of arrays.sortBy(commonModels, 'name')) {
231
+ this.renderModelOption(col, model)
232
+ }
233
+ }
234
+ })
235
+
236
+ row.div('.stretch.tt-flex.column.gap', col => {
237
+ const uncommonModels = Schema.uncommonModels(this.state.schema)
238
+ if (uncommonModels.length) {
239
+ col.h3(h3 => {
240
+ h3.i('.glyp-pending')
241
+ h3.span().text("Other Tables")
242
+ })
243
+ for (const model of arrays.sortBy(uncommonModels, 'name')) {
244
+ this.renderModelOption(col, model)
245
+ }
246
+ }
247
+ })
248
+ })
249
+ }
250
+ }
251
+
252
+
253
+ ////////////////////////////////////////////////////////////////////////////////
254
+ // Export
255
+ ////////////////////////////////////////////////////////////////////////////////
256
+
257
+ const Queries = {
258
+ validate,
259
+ preview,
260
+ renderPreview
261
+ }
262
+
263
+ export default Queries
@@ -0,0 +1,232 @@
1
+ import {PartTag} from "tuff-core/parts"
2
+ import Queries, {Query, QueryResult, QueryValidation} from "./queries"
3
+ import Tables, {FromTableView} from "./tables"
4
+ import {Logger} from "tuff-core/logging"
5
+ import QueryForm, {QuerySettings, QuerySettingsColumns} from "./query-form"
6
+ import DiveEditor, {DiveEditorState} from "../dives/dive-editor"
7
+ import Objects from "tuff-core/objects"
8
+ import {messages} from "tuff-core"
9
+ import Html from "tuff-core/html"
10
+ import ContentPart from "../../terrier/parts/content-part"
11
+ import {TabContainerPart} from "../../terrier/tabs"
12
+
13
+ const log = new Logger("QueryEditor")
14
+
15
+
16
+ ////////////////////////////////////////////////////////////////////////////////
17
+ // Keys
18
+ ////////////////////////////////////////////////////////////////////////////////
19
+
20
+ const validationKey = messages.typedKey<QueryValidation>()
21
+
22
+
23
+ ////////////////////////////////////////////////////////////////////////////////
24
+ // Settings Part
25
+ ////////////////////////////////////////////////////////////////////////////////
26
+
27
+ class SettingsPart extends ContentPart<SubEditorState> {
28
+
29
+ form!: QueryForm
30
+
31
+ async init() {
32
+ this.form = this.makePart(QueryForm, {query: Objects.slice(this.state.query, ...QuerySettingsColumns)})
33
+ }
34
+
35
+
36
+ get parentClasses(): Array<string> {
37
+ return ['tt-flex', 'column', 'gap']
38
+ }
39
+
40
+ renderContent(parent: PartTag) {
41
+ parent.part(this.form)
42
+ parent.div('.tt-flex.justify-end', row => {
43
+ row.a('.alert.tt-flex', a => {
44
+ a.i('.glyp-delete')
45
+ a.span({text: "Delete"})
46
+ }).emitClick(DiveEditor.deleteQueryKey, {id: this.state.query.id})
47
+ })
48
+ }
49
+
50
+
51
+ }
52
+
53
+
54
+ ////////////////////////////////////////////////////////////////////////////////
55
+ // SQL Part
56
+ ////////////////////////////////////////////////////////////////////////////////
57
+
58
+ class SqlPart extends ContentPart<SubEditorState> {
59
+
60
+ validation?: QueryValidation
61
+
62
+ setValidation(validation: QueryValidation) {
63
+ this.validation = validation
64
+ this.dirty()
65
+ }
66
+
67
+ renderContent(parent: PartTag) {
68
+ parent.div('.dd-sql-output.tt-flex.gap', row => {
69
+ if (this.validation) {
70
+ const validation = this.validation
71
+ row.div('.sql.stretch', col => {
72
+ if (validation.error_html?.length) {
73
+ col.class('alert')
74
+ col.pre().text(validation.error_html)
75
+ } else if (validation.sql_html) {
76
+ col.pre().text(validation.sql_html)
77
+ } else {
78
+ col.div('.alert.tt-bubble').text(Html.escape(validation.message))
79
+ }
80
+ })
81
+ }
82
+ else {
83
+ row.div({text: 'SQL Goes Here'})
84
+ }
85
+ })
86
+ }
87
+
88
+
89
+ }
90
+
91
+
92
+ ////////////////////////////////////////////////////////////////////////////////
93
+ // Preview Part
94
+ ////////////////////////////////////////////////////////////////////////////////
95
+
96
+ class PreviewPart extends ContentPart<SubEditorState> {
97
+
98
+ result?: QueryResult
99
+
100
+ async updateResult() {
101
+ const query = this.state.query
102
+ log.info(`Generating preview for`, query)
103
+ this.startLoading()
104
+ this.result = await Queries.preview(query)
105
+ this.stopLoading()
106
+ this.dirty()
107
+ }
108
+
109
+ async init() {
110
+ }
111
+
112
+
113
+ get parentClasses(): Array<string> {
114
+ return ['dd-query-preview']
115
+ }
116
+
117
+ renderContent(parent: PartTag) {
118
+ if (this.result) {
119
+ parent.div('.table-container', col => {
120
+ Queries.renderPreview(col, this.result!)
121
+ })
122
+ }
123
+ else {
124
+ parent.a('.tt-button.stretch', a => {
125
+ a.i('.glyp-refresh')
126
+ a.span('.title').text("Load Preview")
127
+ }).emitClick(this.state.editor.updatePreviewKey)
128
+ }
129
+ }
130
+
131
+
132
+ }
133
+
134
+
135
+
136
+ ////////////////////////////////////////////////////////////////////////////////
137
+ // Editor
138
+ ////////////////////////////////////////////////////////////////////////////////
139
+
140
+ export type QueryEditorState = DiveEditorState & {
141
+ query: Query
142
+ }
143
+
144
+ type SubEditorState = {
145
+ editor: QueryEditor
146
+ query: Query
147
+ }
148
+
149
+ export default class QueryEditor extends ContentPart<QueryEditorState> {
150
+
151
+ tableEditor!: FromTableView
152
+ tabs!: TabContainerPart
153
+ settingsPart!: SettingsPart
154
+ sqlPart!: SqlPart
155
+ previewPart!: PreviewPart
156
+
157
+ updatePreviewKey = messages.untypedKey()
158
+
159
+ async init() {
160
+ const query = this.state.query
161
+
162
+ log.info("Initializing query editor", query)
163
+
164
+ this.tabs = this.makePart(TabContainerPart, {side: 'left'})
165
+ this.settingsPart = this.tabs.upsertTab({key: 'settings', title: 'Settings', icon: 'glyp-settings'},
166
+ SettingsPart, {editor: this, query})
167
+
168
+
169
+ this.listenMessage(QueryForm.settingsChangedKey, m => {
170
+ log.info(`Query settings changed`, m.data)
171
+ this.updateSettings(m.data)
172
+ })
173
+
174
+ this.sqlPart = this.tabs.upsertTab({key: 'sql', title: 'SQL', icon: 'glyp-code'},
175
+ SqlPart, {editor: this, query})
176
+
177
+ this.previewPart = this.tabs.upsertTab({key: 'preview', title: 'Preview', icon: 'glyp-table', classes: ['no-padding'], click: {key: this.updatePreviewKey}},
178
+ PreviewPart, {editor: this, query})
179
+
180
+ this.tableEditor = this.makePart(FromTableView, {schema: this.state.schema, table: this.state.query.from})
181
+
182
+ this.listenMessage(Tables.updatedKey, m => {
183
+ log.info(`Table ${m.data.model} updated`, m.data)
184
+ this.validate()
185
+ this.updatePreview()
186
+ })
187
+
188
+ this.onClick(this.updatePreviewKey, async _ => {
189
+ await this.previewPart.updateResult()
190
+ })
191
+
192
+ this.onClick(QueryEditor.copyToClipboardKey, async m => {
193
+ log.info(`Copy value to clipboard: ${m.data.value}`)
194
+ await navigator.clipboard.writeText(m.data.value)
195
+ this.showToast(`Copied '${m.data.value}' to clipboard`, {color: 'primary'})
196
+ })
197
+
198
+ this.validate().then()
199
+ this.updatePreview().then()
200
+ }
201
+
202
+
203
+ get parentClasses(): Array<string> {
204
+ return ['dd-query-editor']
205
+ }
206
+
207
+ renderContent(parent: PartTag): void {
208
+ parent.div('.dd-query-editor-canvas').part(this.tableEditor)
209
+ parent.div('.dd-query-sub-editors').part(this.tabs)
210
+ }
211
+
212
+ updateSettings(settings: QuerySettings) {
213
+ log.info("Updating settings", settings)
214
+ Object.assign(this.state.query, settings)
215
+ this.dirty()
216
+ }
217
+
218
+ async validate() {
219
+ const res = await Queries.validate(this.state.query)
220
+ log.info(`Query validated`, res)
221
+ this.emitMessage(validationKey, res)
222
+ this.sqlPart.setValidation(res)
223
+ this.dirty()
224
+ }
225
+
226
+ async updatePreview() {
227
+ await this.previewPart.updateResult()
228
+ this.tabs.showTab('preview')
229
+ }
230
+
231
+ static readonly copyToClipboardKey = messages.typedKey<{ value: string }>()
232
+ }
@@ -0,0 +1,51 @@
1
+ import {Query} from "./queries"
2
+ import {PartTag} from "tuff-core/parts"
3
+ import {FormFields} from "tuff-core/forms"
4
+ import {Logger} from "tuff-core/logging"
5
+ import {messages} from "tuff-core"
6
+ import ContentPart from "../../terrier/parts/content-part";
7
+
8
+ const log = new Logger("QueryForm")
9
+
10
+ export const QuerySettingsColumns = ['id', 'name', 'notes'] as const
11
+ export type QuerySettingsColumn = typeof QuerySettingsColumns[number]
12
+
13
+ export type QuerySettings = Pick<Query, QuerySettingsColumn>
14
+
15
+ export default class QueryForm extends ContentPart<{ query: QuerySettings }> {
16
+
17
+ fields!: FormFields<QuerySettings>
18
+
19
+ async init() {
20
+ this.fields = new FormFields<QuerySettings>(this, this.state.query)
21
+ this.listen('datachanged', this.fields.dataChangedKey, m => {
22
+ log.info(`Query fields changed`, m.data)
23
+ Object.assign(this.state.query, m.data)
24
+ this.emitMessage(QueryForm.settingsChangedKey, m.data)
25
+ }, {attach: 'passive'})
26
+ }
27
+
28
+
29
+ get parentClasses(): Array<string> {
30
+ return ['tt-form']
31
+ }
32
+
33
+ renderContent(parent: PartTag): void {
34
+ parent.div('.tt-flex.gap', row => {
35
+ row.div('.stretch', col => {
36
+ col.label().text("Name")
37
+ const nameField = this.fields.textInput(col, 'name')
38
+ if (!this.state.query.name.length) {
39
+ nameField.class('error')
40
+ }
41
+ })
42
+ row.div('.stretch', col => {
43
+ col.label().text("Notes")
44
+ this.fields.textArea(col, 'notes')
45
+ })
46
+ })
47
+ }
48
+
49
+ static readonly settingsChangedKey = messages.typedKey<QuerySettings>()
50
+
51
+ }