create-appraise 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +52 -0
  2. package/package.json +63 -0
  3. package/templates/default/.env.example +2 -0
  4. package/templates/default/README.md +51 -0
  5. package/templates/default/appraise.config.json +4 -0
  6. package/templates/default/components.json +24 -0
  7. package/templates/default/eslint.config.mjs +15 -0
  8. package/templates/default/next-env.d.ts +6 -0
  9. package/templates/default/next.config.ts +7 -0
  10. package/templates/default/package-lock.json +14321 -0
  11. package/templates/default/package.json +124 -0
  12. package/templates/default/postcss.config.mjs +8 -0
  13. package/templates/default/prisma/migrations/20251026202316_migrate_back_to_sqlite/migration.sql +257 -0
  14. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -0
  15. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -0
  16. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -0
  17. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -0
  18. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -0
  19. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -0
  20. package/templates/default/prisma/migrations/20251130190737_add_trace_path_to_test_run_test_case/migration.sql +2 -0
  21. package/templates/default/prisma/migrations/20251213074835_add_log_path_to_test_run/migration.sql +2 -0
  22. package/templates/default/prisma/migrations/20251213183952_add_name_property_for_the_test_run_entities/migration.sql +30 -0
  23. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -0
  24. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -0
  25. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -0
  26. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -0
  27. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -0
  28. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -0
  29. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -0
  30. package/templates/default/prisma/migrations/migration_lock.toml +3 -0
  31. package/templates/default/prisma/schema.prisma +554 -0
  32. package/templates/default/public/favicon.ico +0 -0
  33. package/templates/default/public/file.svg +1 -0
  34. package/templates/default/public/globe.svg +1 -0
  35. package/templates/default/public/next.svg +1 -0
  36. package/templates/default/public/vercel.svg +1 -0
  37. package/templates/default/public/window.svg +1 -0
  38. package/templates/default/scripts/regenerate-features.ts +94 -0
  39. package/templates/default/scripts/setup-env.ts +19 -0
  40. package/templates/default/scripts/sync-all.ts +341 -0
  41. package/templates/default/scripts/sync-environments.ts +323 -0
  42. package/templates/default/scripts/sync-locator-groups.ts +413 -0
  43. package/templates/default/scripts/sync-locators.ts +402 -0
  44. package/templates/default/scripts/sync-modules.ts +349 -0
  45. package/templates/default/scripts/sync-tags.ts +292 -0
  46. package/templates/default/scripts/sync-template-step-groups.ts +399 -0
  47. package/templates/default/scripts/sync-template-steps.ts +806 -0
  48. package/templates/default/scripts/sync-test-cases.ts +905 -0
  49. package/templates/default/scripts/sync-test-suites.ts +411 -0
  50. package/templates/default/src/actions/conflict/conflict.action.ts +33 -0
  51. package/templates/default/src/actions/dashboard/dashboard-actions.ts +241 -0
  52. package/templates/default/src/actions/environments/environment-actions.ts +205 -0
  53. package/templates/default/src/actions/locator/locator-actions.ts +547 -0
  54. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -0
  55. package/templates/default/src/actions/modules/module-actions.ts +133 -0
  56. package/templates/default/src/actions/reports/report-actions.ts +614 -0
  57. package/templates/default/src/actions/review/review-actions.ts +147 -0
  58. package/templates/default/src/actions/tags/tag-actions.ts +104 -0
  59. package/templates/default/src/actions/template-step/template-step-actions.ts +332 -0
  60. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -0
  61. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -0
  62. package/templates/default/src/actions/test-case/test-case-actions.ts +419 -0
  63. package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -0
  64. package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -0
  65. package/templates/default/src/actions/user/user-actions.ts +13 -0
  66. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -0
  67. package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -0
  68. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -0
  69. package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -0
  70. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -0
  71. package/templates/default/src/app/(base)/environments/page.tsx +59 -0
  72. package/templates/default/src/app/(base)/layout.tsx +10 -0
  73. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -0
  74. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -0
  75. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -0
  76. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -0
  77. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -0
  78. package/templates/default/src/app/(base)/locator-groups/page.tsx +61 -0
  79. package/templates/default/src/app/(base)/locators/create/page.tsx +38 -0
  80. package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -0
  81. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +90 -0
  82. package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -0
  83. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -0
  84. package/templates/default/src/app/(base)/locators/page.tsx +65 -0
  85. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -0
  86. package/templates/default/src/app/(base)/modules/create/page.tsx +34 -0
  87. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -0
  88. package/templates/default/src/app/(base)/modules/module-form.tsx +126 -0
  89. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -0
  90. package/templates/default/src/app/(base)/modules/module-table.tsx +24 -0
  91. package/templates/default/src/app/(base)/modules/page.tsx +59 -0
  92. package/templates/default/src/app/(base)/reports/[id]/page.tsx +517 -0
  93. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -0
  94. package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -0
  95. package/templates/default/src/app/(base)/reports/overview-chart.tsx +46 -0
  96. package/templates/default/src/app/(base)/reports/page.tsx +98 -0
  97. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -0
  98. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -0
  99. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -0
  100. package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +131 -0
  101. package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -0
  102. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -0
  103. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -0
  104. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -0
  105. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -0
  106. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -0
  107. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -0
  108. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +60 -0
  109. package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -0
  110. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -0
  111. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -0
  112. package/templates/default/src/app/(base)/reviews/page.tsx +26 -0
  113. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -0
  114. package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -0
  115. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -0
  116. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -0
  117. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -0
  118. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -0
  119. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -0
  120. package/templates/default/src/app/(base)/tags/page.tsx +58 -0
  121. package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -0
  122. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -0
  123. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -0
  124. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -0
  125. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -0
  126. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -0
  127. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -0
  128. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -0
  129. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -0
  130. package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -0
  131. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -0
  132. package/templates/default/src/app/(base)/template-steps/page.tsx +59 -0
  133. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -0
  134. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -0
  135. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -0
  136. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -0
  137. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -0
  138. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -0
  139. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -0
  140. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -0
  141. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -0
  142. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -0
  143. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -0
  144. package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -0
  145. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -0
  146. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -0
  147. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -0
  148. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -0
  149. package/templates/default/src/app/(base)/test-cases/page.tsx +60 -0
  150. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -0
  151. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -0
  152. package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +90 -0
  153. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -0
  154. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -0
  155. package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -0
  156. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -0
  157. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +512 -0
  158. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -0
  159. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -0
  160. package/templates/default/src/app/(base)/test-suites/create/page.tsx +45 -0
  161. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -0
  162. package/templates/default/src/app/(base)/test-suites/page.tsx +82 -0
  163. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -0
  164. package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -0
  165. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -0
  166. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -0
  167. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +13 -0
  168. package/templates/default/src/app/(dashboard-components)/data-card.tsx +27 -0
  169. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +57 -0
  170. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -0
  171. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +45 -0
  172. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +133 -0
  173. package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -0
  174. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -0
  175. package/templates/default/src/app/favicon.ico +0 -0
  176. package/templates/default/src/app/globals.css +147 -0
  177. package/templates/default/src/app/layout.tsx +171 -0
  178. package/templates/default/src/app/page.tsx +64 -0
  179. package/templates/default/src/assets/icons/empty-tube.tsx +23 -0
  180. package/templates/default/src/assets/icons/tube-plus.tsx +29 -0
  181. package/templates/default/src/components/base-node.tsx +21 -0
  182. package/templates/default/src/components/chart/pie-chart.tsx +73 -0
  183. package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -0
  184. package/templates/default/src/components/data-state/empty-state.tsx +40 -0
  185. package/templates/default/src/components/data-visualization/info-card.tsx +70 -0
  186. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -0
  187. package/templates/default/src/components/devtools/providers.tsx +13 -0
  188. package/templates/default/src/components/diagram/button-edge.tsx +54 -0
  189. package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -0
  190. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -0
  191. package/templates/default/src/components/diagram/flow-diagram.tsx +470 -0
  192. package/templates/default/src/components/diagram/node-form.tsx +262 -0
  193. package/templates/default/src/components/diagram/options-header-node.tsx +57 -0
  194. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -0
  195. package/templates/default/src/components/form/error-message.tsx +7 -0
  196. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -0
  197. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -0
  198. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -0
  199. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -0
  200. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -0
  201. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -0
  202. package/templates/default/src/components/logo.tsx +15 -0
  203. package/templates/default/src/components/navigation/command-badge.tsx +34 -0
  204. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -0
  205. package/templates/default/src/components/navigation/entity-search-command.tsx +116 -0
  206. package/templates/default/src/components/navigation/nav-card.tsx +31 -0
  207. package/templates/default/src/components/navigation/nav-command.tsx +508 -0
  208. package/templates/default/src/components/navigation/nav-link.tsx +60 -0
  209. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -0
  210. package/templates/default/src/components/node-header.tsx +159 -0
  211. package/templates/default/src/components/reports/test-case-logs-modal.tsx +253 -0
  212. package/templates/default/src/components/table/table-actions.tsx +172 -0
  213. package/templates/default/src/components/test-run/download-logs-button.tsx +99 -0
  214. package/templates/default/src/components/test-run/log-viewer.tsx +445 -0
  215. package/templates/default/src/components/test-run/test-run-details.tsx +611 -0
  216. package/templates/default/src/components/test-run/test-run-header.tsx +149 -0
  217. package/templates/default/src/components/test-run/view-report-button.tsx +102 -0
  218. package/templates/default/src/components/theme/mode-toggle.tsx +54 -0
  219. package/templates/default/src/components/theme/theme-provider.tsx +8 -0
  220. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -0
  221. package/templates/default/src/components/typography/page-header.tsx +7 -0
  222. package/templates/default/src/components/ui/alert-dialog.tsx +106 -0
  223. package/templates/default/src/components/ui/alert.tsx +43 -0
  224. package/templates/default/src/components/ui/avatar.tsx +40 -0
  225. package/templates/default/src/components/ui/badge.tsx +29 -0
  226. package/templates/default/src/components/ui/button.tsx +47 -0
  227. package/templates/default/src/components/ui/calendar.tsx +158 -0
  228. package/templates/default/src/components/ui/card.tsx +43 -0
  229. package/templates/default/src/components/ui/chart.tsx +369 -0
  230. package/templates/default/src/components/ui/checkbox.tsx +28 -0
  231. package/templates/default/src/components/ui/command.tsx +135 -0
  232. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -0
  233. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -0
  234. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -0
  235. package/templates/default/src/components/ui/data-table.tsx +267 -0
  236. package/templates/default/src/components/ui/dialog.tsx +97 -0
  237. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -0
  238. package/templates/default/src/components/ui/empty.tsx +104 -0
  239. package/templates/default/src/components/ui/input.tsx +22 -0
  240. package/templates/default/src/components/ui/kbd.tsx +28 -0
  241. package/templates/default/src/components/ui/label.tsx +19 -0
  242. package/templates/default/src/components/ui/loading.tsx +12 -0
  243. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -0
  244. package/templates/default/src/components/ui/multi-select.tsx +142 -0
  245. package/templates/default/src/components/ui/navigation-menu.tsx +120 -0
  246. package/templates/default/src/components/ui/popover.tsx +33 -0
  247. package/templates/default/src/components/ui/progress.tsx +25 -0
  248. package/templates/default/src/components/ui/radio-group.tsx +44 -0
  249. package/templates/default/src/components/ui/scroll-area.tsx +40 -0
  250. package/templates/default/src/components/ui/select.tsx +144 -0
  251. package/templates/default/src/components/ui/separator.tsx +22 -0
  252. package/templates/default/src/components/ui/skeleton.tsx +7 -0
  253. package/templates/default/src/components/ui/table.tsx +76 -0
  254. package/templates/default/src/components/ui/tabs.tsx +55 -0
  255. package/templates/default/src/components/ui/textarea.tsx +21 -0
  256. package/templates/default/src/components/ui/toast.tsx +113 -0
  257. package/templates/default/src/components/ui/toaster.tsx +26 -0
  258. package/templates/default/src/components/ui/tooltip.tsx +32 -0
  259. package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -0
  260. package/templates/default/src/config/db-config.ts +10 -0
  261. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -0
  262. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -0
  263. package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -0
  264. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -0
  265. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -0
  266. package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -0
  267. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -0
  268. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -0
  269. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -0
  270. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -0
  271. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -0
  272. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -0
  273. package/templates/default/src/constants/form-opts/test-run-form-opts.ts +31 -0
  274. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -0
  275. package/templates/default/src/hooks/use-toast.ts +187 -0
  276. package/templates/default/src/lib/bidirectional-sync.ts +432 -0
  277. package/templates/default/src/lib/database-sync.ts +531 -0
  278. package/templates/default/src/lib/environment-file-utils.ts +221 -0
  279. package/templates/default/src/lib/feature-file-generator.ts +411 -0
  280. package/templates/default/src/lib/gherkin-parser.ts +259 -0
  281. package/templates/default/src/lib/locator-group-file-utils.ts +370 -0
  282. package/templates/default/src/lib/metrics/metric-calculator.ts +613 -0
  283. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -0
  284. package/templates/default/src/lib/path-helpers/module-path.ts +71 -0
  285. package/templates/default/src/lib/test-case-utils.ts +6 -0
  286. package/templates/default/src/lib/test-run/log-formatter.ts +83 -0
  287. package/templates/default/src/lib/test-run/process-manager.ts +191 -0
  288. package/templates/default/src/lib/test-run/report-parser.ts +316 -0
  289. package/templates/default/src/lib/test-run/test-run-executor.ts +144 -0
  290. package/templates/default/src/lib/test-run/winston-logger.ts +95 -0
  291. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -0
  292. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -0
  293. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -0
  294. package/templates/default/src/lib/utils/node-param-validation.ts +81 -0
  295. package/templates/default/src/lib/utils/template-step-file-generator.ts +167 -0
  296. package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -0
  297. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -0
  298. package/templates/default/src/lib/utils.ts +31 -0
  299. package/templates/default/src/tests/config/environments/environments.json +14 -0
  300. package/templates/default/src/tests/config/executor/world.ts +41 -0
  301. package/templates/default/src/tests/executor.ts +80 -0
  302. package/templates/default/src/tests/hooks/hooks.ts +99 -0
  303. package/templates/default/src/tests/mapping/locator-map.json +1 -0
  304. package/templates/default/src/tests/steps/actions/click.step.ts +62 -0
  305. package/templates/default/src/tests/steps/actions/hover.step.ts +31 -0
  306. package/templates/default/src/tests/steps/actions/input.step.ts +149 -0
  307. package/templates/default/src/tests/steps/actions/navigation.step.ts +72 -0
  308. package/templates/default/src/tests/steps/actions/random_data.step.ts +146 -0
  309. package/templates/default/src/tests/steps/actions/store.step.ts +90 -0
  310. package/templates/default/src/tests/steps/actions/wait.step.ts +107 -0
  311. package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -0
  312. package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +23 -0
  313. package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -0
  314. package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -0
  315. package/templates/default/src/tests/support/parameter-types.ts +12 -0
  316. package/templates/default/src/tests/utils/cache.util.ts +260 -0
  317. package/templates/default/src/tests/utils/cli.util.ts +177 -0
  318. package/templates/default/src/tests/utils/environment.util.ts +65 -0
  319. package/templates/default/src/tests/utils/locator.util.ts +248 -0
  320. package/templates/default/src/tests/utils/random-data.util.ts +45 -0
  321. package/templates/default/src/tests/utils/spawner.util.ts +617 -0
  322. package/templates/default/src/types/diagram/diagram.ts +34 -0
  323. package/templates/default/src/types/diagram/template-step.ts +11 -0
  324. package/templates/default/src/types/executor/browser.type.ts +1 -0
  325. package/templates/default/src/types/form/actionHandler.ts +6 -0
  326. package/templates/default/src/types/locator/locator.type.ts +11 -0
  327. package/templates/default/src/types/step/step.type.ts +1 -0
  328. package/templates/default/src/types/table/data-table.ts +6 -0
  329. package/templates/default/tailwind.config.ts +62 -0
  330. package/templates/default/tsconfig.json +28 -0
@@ -0,0 +1,146 @@
1
+ import { NextRequest, NextResponse } from 'next/server'
2
+ import { promises as fs } from 'fs'
3
+ import { taskSpawner } from '@/tests/utils/spawner.util'
4
+ import prisma from '@/config/db-config'
5
+ import path from 'path'
6
+
7
+ // Ensure this route runs in Node.js runtime (not Edge) for singleton to work
8
+ export const runtime = 'nodejs'
9
+
10
+ /**
11
+ * GET handler for checking if trace viewer is running
12
+ *
13
+ * This endpoint checks if a trace viewer process is currently running for a test case.
14
+ */
15
+ export async function GET(
16
+ request: NextRequest,
17
+ { params }: { params: Promise<{ runId: string; testCaseId: string }> },
18
+ ) {
19
+ const { runId, testCaseId } = await params
20
+
21
+ try {
22
+ // Verify test run exists
23
+ const testRun = await prisma.testRun.findUnique({
24
+ where: { runId },
25
+ include: {
26
+ testCases: {
27
+ where: { id: testCaseId },
28
+ },
29
+ },
30
+ })
31
+
32
+ if (!testRun) {
33
+ return NextResponse.json({ error: 'Test run not found' }, { status: 404 })
34
+ }
35
+
36
+ // Verify test case belongs to this test run
37
+ const testRunTestCase = testRun.testCases.find(tc => tc.id === testCaseId)
38
+ if (!testRunTestCase) {
39
+ return NextResponse.json({ error: 'Test case not found in this test run' }, { status: 404 })
40
+ }
41
+
42
+ // Check if trace viewer process is running
43
+ const processName = `trace-viewer-${testCaseId}`
44
+ const process = taskSpawner.getProcess(processName)
45
+ const isRunning = process?.isRunning ?? false
46
+
47
+ return NextResponse.json({
48
+ isRunning,
49
+ processName: isRunning ? processName : null,
50
+ })
51
+ } catch (error) {
52
+ console.error(`[TraceViewer] Error checking trace viewer status for runId: ${runId}, testCaseId: ${testCaseId}:`, error)
53
+ return NextResponse.json(
54
+ {
55
+ error: `Failed to check trace viewer status: ${error instanceof Error ? error.message : 'Unknown error'}`,
56
+ },
57
+ { status: 500 },
58
+ )
59
+ }
60
+ }
61
+
62
+ /**
63
+ * POST handler for spawning Playwright trace viewer
64
+ *
65
+ * This endpoint spawns a process to open the Playwright trace viewer for a failed test scenario.
66
+ * The process is self-closing and doesn't require cleanup.
67
+ *
68
+ * Security: Verifies test run and test case exist and belong together before allowing access.
69
+ * TODO: Add user authentication check when authentication is implemented.
70
+ */
71
+ export async function POST(
72
+ request: NextRequest,
73
+ { params }: { params: Promise<{ runId: string; testCaseId: string }> },
74
+ ) {
75
+ const { runId, testCaseId } = await params
76
+
77
+ try {
78
+ // Verify test run exists
79
+ const testRun = await prisma.testRun.findUnique({
80
+ where: { runId },
81
+ include: {
82
+ testCases: {
83
+ where: { id: testCaseId },
84
+ include: {
85
+ testCase: true,
86
+ },
87
+ },
88
+ },
89
+ })
90
+
91
+ if (!testRun) {
92
+ return NextResponse.json({ error: 'Test run not found' }, { status: 404 })
93
+ }
94
+
95
+ // Verify test case belongs to this test run
96
+ const testRunTestCase = testRun.testCases.find(tc => tc.id === testCaseId)
97
+ if (!testRunTestCase) {
98
+ return NextResponse.json({ error: 'Test case not found in this test run' }, { status: 404 })
99
+ }
100
+
101
+ // Get trace path from database
102
+ const tracePath = testRunTestCase.tracePath
103
+ if (!tracePath) {
104
+ return NextResponse.json({ error: 'No trace path available for this test case' }, { status: 400 })
105
+ }
106
+
107
+ // Validate trace file exists
108
+ try {
109
+ await fs.access(tracePath)
110
+ } catch {
111
+ return NextResponse.json(
112
+ { error: `Trace file not found at path: ${tracePath}` },
113
+ { status: 404 },
114
+ )
115
+ }
116
+
117
+ // Resolve absolute path if relative
118
+ const absoluteTracePath = path.isAbsolute(tracePath) ? tracePath : path.join(process.cwd(), tracePath)
119
+
120
+ // Spawn playwright show-trace command
121
+ // The process is self-closing when the user closes the trace viewer
122
+ const spawnedProcess = await taskSpawner.spawn('npx', ['playwright', 'show-trace', absoluteTracePath], {
123
+ streamLogs: true,
124
+ prefixLogs: true,
125
+ logPrefix: `trace-viewer-${testCaseId}`,
126
+ captureOutput: false, // No need to capture output for trace viewer
127
+ })
128
+
129
+ console.log(`[TraceViewer] Spawned trace viewer process for testCaseId: ${testCaseId}, tracePath: ${absoluteTracePath}`)
130
+
131
+ return NextResponse.json({
132
+ success: true,
133
+ message: 'Trace viewer launched successfully',
134
+ processName: spawnedProcess.name,
135
+ })
136
+ } catch (error) {
137
+ console.error(`[TraceViewer] Error spawning trace viewer for runId: ${runId}, testCaseId: ${testCaseId}:`, error)
138
+ return NextResponse.json(
139
+ {
140
+ error: `Failed to spawn trace viewer: ${error instanceof Error ? error.message : 'Unknown error'}`,
141
+ },
142
+ { status: 500 },
143
+ )
144
+ }
145
+ }
146
+
@@ -0,0 +1,147 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ body {
6
+ font-family: Arial, Helvetica, sans-serif;
7
+ }
8
+
9
+ @layer base {
10
+ :root {
11
+ --background: oklch(0.9751 0.0127 244.2507);
12
+ --foreground: oklch(0.3729 0.0306 259.7328);
13
+ --card: oklch(1 0 0);
14
+ --card-foreground: oklch(0.3729 0.0306 259.7328);
15
+ --popover: oklch(1 0 0);
16
+ --popover-foreground: oklch(0.3729 0.0306 259.7328);
17
+ --primary: oklch(0.5606 0.192 149.5793);
18
+ --primary-foreground: oklch(1 0 0);
19
+ --secondary: oklch(0.9514 0.025 236.8242);
20
+ --secondary-foreground: oklch(0.4461 0.0263 256.8018);
21
+ --muted: oklch(0.967 0.0029 264.5419);
22
+ --muted-foreground: oklch(0.551 0.0234 264.3637);
23
+ --accent: oklch(0.9505 0.0507 163.0508);
24
+ --accent-foreground: oklch(0.3729 0.0306 259.7328);
25
+ --destructive: oklch(0.6368 0.2078 25.3313);
26
+ --destructive-foreground: oklch(1 0 0);
27
+ --border: oklch(0.9276 0.0058 264.5313);
28
+ --input: oklch(0.9276 0.0058 264.5313);
29
+ --ring: oklch(0.7227 0.192 149.5793);
30
+ --chart-1: oklch(0.7227 0.192 149.5793);
31
+ --chart-2: oklch(0.6959 0.1491 162.4796);
32
+ --chart-3: oklch(0.596 0.1274 163.2254);
33
+ --chart-4: oklch(0.5081 0.1049 165.6121);
34
+ --chart-5: oklch(0.4318 0.0865 166.9128);
35
+ --sidebar: oklch(0.9514 0.025 236.8242);
36
+ --sidebar-foreground: oklch(0.3729 0.0306 259.7328);
37
+ --sidebar-primary: oklch(0.7227 0.192 149.5793);
38
+ --sidebar-primary-foreground: oklch(1 0 0);
39
+ --sidebar-accent: oklch(0.9505 0.0507 163.0508);
40
+ --sidebar-accent-foreground: oklch(0.3729 0.0306 259.7328);
41
+ --sidebar-border: oklch(0.9276 0.0058 264.5313);
42
+ --sidebar-ring: oklch(0.7227 0.192 149.5793);
43
+ --font-sans: DM Sans, sans-serif;
44
+ --font-serif: Lora, serif;
45
+ --font-mono: IBM Plex Mono, monospace;
46
+ --radius: 0.5rem;
47
+ --shadow-x: 0px;
48
+ --shadow-y: 4px;
49
+ --shadow-blur: 8px;
50
+ --shadow-spread: -1px;
51
+ --shadow-opacity: 0.1;
52
+ --shadow-color: hsl(0 0% 0%);
53
+ --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
54
+ --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
55
+ --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
56
+ --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
57
+ --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1);
58
+ --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1);
59
+ --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1);
60
+ --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
61
+ --tracking-normal: 0em;
62
+ --spacing: 0.25rem;
63
+ --shadow-offset-x: 0px;
64
+ --shadow-offset-y: 4px;
65
+ --letter-spacing: 0em;
66
+ }
67
+
68
+ .dark {
69
+ --background: oklch(0.2077 0.0398 265.7549);
70
+ --foreground: oklch(0.8717 0.0093 258.3382);
71
+ --card: oklch(0.2795 0.0368 260.031);
72
+ --card-foreground: oklch(0.8717 0.0093 258.3382);
73
+ --popover: oklch(0.2795 0.0368 260.031);
74
+ --popover-foreground: oklch(0.8717 0.0093 258.3382);
75
+ --primary: oklch(0.7729 0.1535 163.2231);
76
+ --primary-foreground: oklch(0.2077 0.0398 265.7549);
77
+ --secondary: oklch(0.3351 0.0331 260.912);
78
+ --secondary-foreground: oklch(0.7118 0.0129 286.0665);
79
+ --muted: oklch(0.2463 0.0275 259.9628);
80
+ --muted-foreground: oklch(0.551 0.0234 264.3637);
81
+ --accent: oklch(0.3729 0.0306 259.7328);
82
+ --accent-foreground: oklch(0.7118 0.0129 286.0665);
83
+ --destructive: oklch(0.6368 0.2078 25.3313);
84
+ --destructive-foreground: oklch(0.2077 0.0398 265.7549);
85
+ --border: oklch(0.4461 0.0263 256.8018);
86
+ --input: oklch(0.4461 0.0263 256.8018);
87
+ --ring: oklch(0.7729 0.1535 163.2231);
88
+ --chart-1: oklch(0.7729 0.1535 163.2231);
89
+ --chart-2: oklch(0.7845 0.1325 181.912);
90
+ --chart-3: oklch(0.7227 0.192 149.5793);
91
+ --chart-4: oklch(0.6959 0.1491 162.4796);
92
+ --chart-5: oklch(0.596 0.1274 163.2254);
93
+ --sidebar: oklch(0.2795 0.0368 260.031);
94
+ --sidebar-foreground: oklch(0.8717 0.0093 258.3382);
95
+ --sidebar-primary: oklch(0.7729 0.1535 163.2231);
96
+ --sidebar-primary-foreground: oklch(0.2077 0.0398 265.7549);
97
+ --sidebar-accent: oklch(0.3729 0.0306 259.7328);
98
+ --sidebar-accent-foreground: oklch(0.7118 0.0129 286.0665);
99
+ --sidebar-border: oklch(0.4461 0.0263 256.8018);
100
+ --sidebar-ring: oklch(0.7729 0.1535 163.2231);
101
+ --font-sans: DM Sans, sans-serif;
102
+ --font-serif: Lora, serif;
103
+ --font-mono: IBM Plex Mono, monospace;
104
+ --radius: 0.5rem;
105
+ --shadow-x: 0px;
106
+ --shadow-y: 4px;
107
+ --shadow-blur: 8px;
108
+ --shadow-spread: -1px;
109
+ --shadow-opacity: 0.1;
110
+ --shadow-color: hsl(0 0% 0%);
111
+ --shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
112
+ --shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
113
+ --shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
114
+ --shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 1px 2px -2px hsl(0 0% 0% / 0.1);
115
+ --shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 2px 4px -2px hsl(0 0% 0% / 0.1);
116
+ --shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 4px 6px -2px hsl(0 0% 0% / 0.1);
117
+ --shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.1), 0px 8px 10px -2px hsl(0 0% 0% / 0.1);
118
+ --shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
119
+ --shadow-offset-x: 0px;
120
+ --shadow-offset-y: 4px;
121
+ --letter-spacing: 0em;
122
+ --spacing: 0.25rem;
123
+ }
124
+ .theme {
125
+ --font-sans: DM Sans, sans-serif;
126
+ --font-mono: IBM Plex Mono, monospace;
127
+ --font-serif: Lora, serif;
128
+ --radius: 0.5rem;
129
+ --tracking-tighter: calc(var(--tracking-normal) - 0.05em);
130
+ --tracking-tight: calc(var(--tracking-normal) - 0.025em);
131
+ --tracking-wide: calc(var(--tracking-normal) + 0.025em);
132
+ --tracking-wider: calc(var(--tracking-normal) + 0.05em);
133
+ --tracking-widest: calc(var(--tracking-normal) + 0.1em);
134
+ }
135
+ body {
136
+ letter-spacing: var(--tracking-normal);
137
+ }
138
+ }
139
+
140
+ @layer base {
141
+ * {
142
+ @apply border-border;
143
+ }
144
+ body {
145
+ @apply bg-background text-foreground;
146
+ }
147
+ }
@@ -0,0 +1,171 @@
1
+ import type { Metadata } from 'next'
2
+ import { Inter, Inter_Tight } from 'next/font/google'
3
+ import './globals.css'
4
+ import { ThemeProvider } from '@/components/theme/theme-provider'
5
+ import { ModeToggle } from '@/components/theme/mode-toggle'
6
+ import { Toaster } from '@/components/ui/toaster'
7
+
8
+ const inter = Inter({
9
+ variable: '--font-inter',
10
+ subsets: ['latin'],
11
+ })
12
+
13
+ const interTight = Inter_Tight({
14
+ variable: '--font-inter-tight',
15
+ subsets: ['latin'],
16
+ })
17
+
18
+ export const metadata: Metadata = {
19
+ title: 'Appraise | Dashboard',
20
+ description: 'Welcome to the dashboard. Here you can see your test suites and run them.',
21
+ }
22
+
23
+ import Logo from '@/components/logo'
24
+ import NavLink from '@/components/navigation/nav-link'
25
+ import {
26
+ Blocks,
27
+ Bot,
28
+ BrickWall,
29
+ Code,
30
+ Component,
31
+ FileCheck,
32
+ FileSliders,
33
+ Group,
34
+ LayoutDashboard,
35
+ LayoutTemplate,
36
+ ListChecks,
37
+ Puzzle,
38
+ Server,
39
+ Tag,
40
+ TestTubeDiagonal,
41
+ TestTubes,
42
+ } from 'lucide-react'
43
+ import Link from 'next/link'
44
+ import NavMenuCardDeck from '@/components/navigation/nav-menu-card-deck'
45
+ import { DevtoolsProviders } from '@/components/devtools/providers'
46
+ import NavCommand from '@/components/navigation/nav-command'
47
+
48
+ export default function RootLayout({
49
+ children,
50
+ }: Readonly<{
51
+ children: React.ReactNode
52
+ }>) {
53
+ return (
54
+ <html lang="en" suppressHydrationWarning>
55
+ <body className={`${inter.variable} ${interTight.variable} min-h-screen antialiased`}>
56
+ <DevtoolsProviders>
57
+ <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
58
+ <ModeToggle />
59
+ <div className="mx-auto lg:max-w-screen-xl 2xl:max-w-screen-2xl">
60
+ <nav className="mb-6 py-2">
61
+ <div className="flex items-center gap-1">
62
+ <div className="-ml-2">
63
+ <Link href="/">
64
+ <Logo />
65
+ </Link>
66
+ </div>
67
+ <NavLink href="/" icon={<LayoutDashboard className="h-5 w-5 text-primary" />}>
68
+ Dashboard
69
+ </NavLink>
70
+ <NavMenuCardDeck
71
+ containerButtonText="Automate"
72
+ containerButtonIcon={<Bot className="h-5 w-5 text-primary" />}
73
+ dropdownItems={[
74
+ {
75
+ text: 'Test Suites',
76
+ icon: <TestTubes className="h-6 w-6 text-primary" />,
77
+ href: '/test-suites',
78
+ description: 'Group tests into logical units',
79
+ },
80
+ {
81
+ text: 'Test Cases',
82
+ icon: <TestTubeDiagonal className="h-6 w-6 text-primary" />,
83
+ href: '/test-cases',
84
+ description: 'Define test scenarios',
85
+ },
86
+ {
87
+ text: 'Test Runs',
88
+ icon: <ListChecks className="h-6 w-6 text-primary" />,
89
+ href: '/test-runs',
90
+ description: 'Execute test scenarios',
91
+ },
92
+ {
93
+ text: 'Reports',
94
+ icon: <FileCheck className="h-6 w-6 text-primary" />,
95
+ href: '/reports',
96
+ description: 'Analyze test results',
97
+ },
98
+ ]}
99
+ />
100
+ <NavMenuCardDeck
101
+ containerButtonText="Template"
102
+ containerButtonIcon={<BrickWall className="h-5 w-5 text-primary" />}
103
+ dropdownItems={[
104
+ {
105
+ text: 'Template Steps',
106
+ icon: <LayoutTemplate className="h-6 w-6 text-primary" />,
107
+ href: '/template-steps',
108
+ description: 'Define reusable test steps',
109
+ },
110
+ {
111
+ text: 'Template Step Groups',
112
+ icon: <Component className="h-6 w-6 text-primary" />,
113
+ href: '/template-step-groups',
114
+ description: 'Organize template steps into logical groups',
115
+ },
116
+ {
117
+ text: 'Template Test Cases',
118
+ icon: <Blocks className="h-6 w-6 text-primary" />,
119
+ href: '/template-test-cases',
120
+ description: 'Define reusable test scenario templates',
121
+ },
122
+ ]}
123
+ />
124
+ <NavMenuCardDeck
125
+ containerButtonText="Configuration"
126
+ containerButtonIcon={<FileSliders className="h-5 w-5 text-primary" />}
127
+ dropdownItems={[
128
+ {
129
+ text: 'Locators',
130
+ icon: <Code className="h-6 w-6 text-primary" />,
131
+ href: '/locators',
132
+ description: 'Define reusable locators',
133
+ },
134
+ {
135
+ text: 'Locator Groups',
136
+ icon: <Group className="h-6 w-6 text-primary" />,
137
+ href: '/locator-groups',
138
+ description: 'Organize locators into logical groups',
139
+ },
140
+ {
141
+ text: 'Modules',
142
+ icon: <Puzzle className="h-6 w-6 text-primary" />,
143
+ href: '/modules',
144
+ description: 'Organize tests into logical units',
145
+ },
146
+ {
147
+ text: 'Environments',
148
+ icon: <Server className="h-6 w-6 text-primary" />,
149
+ href: '/environments',
150
+ description: 'Define test environment configurations',
151
+ },
152
+ {
153
+ text: 'Tags',
154
+ icon: <Tag className="h-6 w-6 text-primary" />,
155
+ href: '/tags',
156
+ description: 'Define tags for test scenarios and suites',
157
+ },
158
+ ]}
159
+ />
160
+ <NavCommand className="ml-auto" />
161
+ </div>
162
+ </nav>
163
+ {children}
164
+ <Toaster />
165
+ </div>
166
+ </ThemeProvider>
167
+ </DevtoolsProviders>
168
+ </body>
169
+ </html>
170
+ )
171
+ }
@@ -0,0 +1,64 @@
1
+ import PageHeader from '@/components/typography/page-header'
2
+ import HeaderSubtitle from '@/components/typography/page-header-subtitle'
3
+ import AppDrawer from './(dashboard-components)/app-drawer'
4
+ import {
5
+ EntityMetrics,
6
+ getDashboardMetricsAction,
7
+ getEntityMetricsAction,
8
+ getTestSuiteExecutionDataAction,
9
+ TestSuiteExecutionData,
10
+ } from '@/actions/dashboard/dashboard-actions'
11
+ import { DashboardMetrics } from '@prisma/client'
12
+ import QuickActionsDrawer from './(dashboard-components)/quick-actions-drawer'
13
+ import DataCard from './(dashboard-components)/data-card'
14
+ import OngoingTestRunsCard from './(dashboard-components)/ongoing-test-runs-card'
15
+ import { DataCardGrid } from './(dashboard-components)/data-card-grid'
16
+ import { ExecutionHealthPanel } from './(dashboard-components)/execution-health-panel'
17
+
18
+ const Dashboard = async () => {
19
+ const metricsResponse = await getDashboardMetricsAction()
20
+ const metrics = metricsResponse.status === 200 ? (metricsResponse.data as DashboardMetrics | null) : null
21
+
22
+ const entityMetricsResponse = await getEntityMetricsAction()
23
+ const entityMetrics = entityMetricsResponse.status === 200 ? (entityMetricsResponse.data as unknown as EntityMetrics) : null
24
+ if (!entityMetrics) {
25
+ return <div>Error loading entity metrics</div>
26
+ }
27
+
28
+ const { testCasesCount, testSuitesCount, templateStepsCount, runningTestRunsCount } = entityMetrics
29
+
30
+ // Fetch test suite execution data
31
+ const testSuiteExecutionResponse = await getTestSuiteExecutionDataAction()
32
+ const testSuiteExecutionData =
33
+ testSuiteExecutionResponse.status === 200
34
+ ? (testSuiteExecutionResponse.data as TestSuiteExecutionData)
35
+ : []
36
+
37
+ return (
38
+ <div>
39
+ <div className="mb-8">
40
+ <PageHeader>Dashboard</PageHeader>
41
+ <HeaderSubtitle>Welcome to the dashboard. Here you can see your test suites and run them.</HeaderSubtitle>
42
+ </div>
43
+ <div className="flex gap-7" id="dashboard-content">
44
+ <div className="flex flex-col gap-7">
45
+ <div className="flex gap-7">
46
+ <AppDrawer metrics={metrics} title="Attention Needed" description="Issues that require immediate action" />
47
+ <DataCardGrid>
48
+ <DataCard title="Test Cases" value={testCasesCount} link="/test-cases" />
49
+ <DataCard title="Test Suites" value={testSuitesCount} link="/test-suites" />
50
+ <DataCard title="Template Steps" value={templateStepsCount} link="/template-steps" />
51
+ <OngoingTestRunsCard initialCount={runningTestRunsCount} link="/test-runs" />
52
+ </DataCardGrid>
53
+ </div>
54
+ <QuickActionsDrawer />
55
+ </div>
56
+ <div className="flex-1">
57
+ <ExecutionHealthPanel featureData={testSuiteExecutionData} />
58
+ </div>
59
+ </div>
60
+ </div>
61
+ )
62
+ }
63
+
64
+ export default Dashboard
@@ -0,0 +1,23 @@
1
+ import { cn } from '@/lib/utils'
2
+
3
+ const EmptyTube = ({ className }: { className?: string }) => {
4
+ return (
5
+ <svg
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="24"
8
+ height="24"
9
+ viewBox="0 0 24 24"
10
+ fill="none"
11
+ stroke="currentColor"
12
+ strokeWidth="2"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ className={cn('lucide lucide-test-tube-icon lucide-test-tube', className)}
16
+ >
17
+ <path d="M14.5 2v17.5c0 1.4-1.1 2.5-2.5 2.5c-1.4 0-2.5-1.1-2.5-2.5V2" />
18
+ <path d="M8.5 2h7" />
19
+ </svg>
20
+ )
21
+ }
22
+
23
+ export default EmptyTube
@@ -0,0 +1,29 @@
1
+ import { cn } from '@/lib/utils'
2
+
3
+ export const TubePlus = ({ className }: { className?: string }) => {
4
+ return (
5
+ <>
6
+ <svg
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ width="24"
9
+ height="24"
10
+ viewBox="0 0 24 24"
11
+ fill="none"
12
+ stroke="currentColor"
13
+ strokeWidth="2"
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ className={cn('lucide', className)}
17
+ >
18
+ {/* Empty tube icon */}
19
+ <path d="M14.5 2v17.5c0 1.4-1.1 2.5-2.5 2.5c-1.4 0-2.5-1.1-2.5-2.5V2" />
20
+ <path d="M8.5 2h7" />
21
+ {/* Half-filled level indicator */}
22
+ <line x1="10.5" y1="15.5" x2="13.5" y2="15.5" />
23
+ {/* Plus icon - positioned at bottom right */}
24
+ <line x1="17.5" y1="19.5" x2="21.5" y2="19.5" strokeWidth="1.5" />
25
+ <line x1="19.5" y1="17.5" x2="19.5" y2="21.5" strokeWidth="1.5" />
26
+ </svg>
27
+ </>
28
+ )
29
+ }
@@ -0,0 +1,21 @@
1
+ import { forwardRef, HTMLAttributes } from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ export const BaseNode = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement> & { selected?: boolean }>(
6
+ ({ className, selected, ...props }, ref) => (
7
+ <div
8
+ ref={ref}
9
+ className={cn(
10
+ 'relative rounded-md border bg-card p-5 text-card-foreground',
11
+ className,
12
+ selected ? 'border-muted-foreground shadow-lg' : '',
13
+ 'hover:ring-1',
14
+ )}
15
+ tabIndex={0}
16
+ {...props}
17
+ />
18
+ ),
19
+ )
20
+
21
+ BaseNode.displayName = 'BaseNode'
@@ -0,0 +1,73 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { Label } from 'recharts'
5
+ import { ChartConfig, ChartLegend, ChartLegendContent, ChartTooltipContent } from '../ui/chart'
6
+ import { ChartTooltip } from '../ui/chart'
7
+ import { ChartContainer } from '../ui/chart'
8
+ import { Pie, PieChart } from 'recharts'
9
+ import { CardContent, CardHeader, CardTitle } from '../ui/card'
10
+ import { Card, CardDescription } from '../ui/card'
11
+ import { cn } from '@/lib/utils'
12
+
13
+ const PieChartGraph = ({
14
+ chartConfig,
15
+ chartData,
16
+ chartLabelValue,
17
+ chartLabelText,
18
+ chartTitle,
19
+ chartDescription,
20
+ chartValueKey,
21
+ chartNameKey,
22
+ className,
23
+ }: {
24
+ chartConfig: ChartConfig
25
+ chartData: Record<string, unknown>[]
26
+ chartLabelValue: string
27
+ chartLabelText: string
28
+ chartTitle: string
29
+ chartDescription: string
30
+ chartValueKey: string
31
+ chartNameKey: string
32
+ className?: React.ComponentProps<'div'>['className']
33
+ }) => {
34
+ return (
35
+ <Card className={cn('flex flex-col', className)}>
36
+ <CardHeader className="items-center pb-0">
37
+ <CardTitle>{chartTitle}</CardTitle>
38
+ <CardDescription>{chartDescription}</CardDescription>
39
+ </CardHeader>
40
+ <CardContent>
41
+ <ChartContainer config={chartConfig} className="mx-auto aspect-square max-h-[250px]">
42
+ <PieChart>
43
+ <ChartTooltip cursor={false} content={<ChartTooltipContent hideLabel />} />
44
+ <Pie data={chartData} dataKey={chartValueKey} nameKey={chartNameKey} innerRadius={60} strokeWidth={5}>
45
+ <Label
46
+ content={({ viewBox }) => {
47
+ if (viewBox && 'cx' in viewBox && 'cy' in viewBox) {
48
+ return (
49
+ <text x={viewBox.cx} y={viewBox.cy} textAnchor="middle" dominantBaseline="middle">
50
+ <tspan x={viewBox.cx} y={viewBox.cy} className="fill-foreground text-3xl font-bold">
51
+ {chartLabelValue}
52
+ </tspan>
53
+ <tspan x={viewBox.cx} y={(viewBox.cy || 0) + 24} className="fill-muted-foreground">
54
+ {chartLabelText}
55
+ </tspan>
56
+ </text>
57
+ )
58
+ }
59
+ }}
60
+ />
61
+ </Pie>
62
+ <ChartLegend
63
+ content={<ChartLegendContent nameKey={chartNameKey} />}
64
+ className="-translate-y-2 flex-wrap gap-2 [&>*]:basis-1/4 [&>*]:justify-center"
65
+ />
66
+ </PieChart>
67
+ </ChartContainer>
68
+ </CardContent>
69
+ </Card>
70
+ )
71
+ }
72
+
73
+ export default PieChartGraph