create-appraisejs 0.1.10-alpha.8 → 0.2.0-alpha.1

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 (414) hide show
  1. package/README.md +52 -52
  2. package/dist/cli.e2e.test.d.ts +2 -0
  3. package/dist/cli.e2e.test.d.ts.map +1 -0
  4. package/dist/cli.e2e.test.js +73 -0
  5. package/dist/cli.e2e.test.js.map +1 -0
  6. package/dist/config.test.d.ts +2 -0
  7. package/dist/config.test.d.ts.map +1 -0
  8. package/dist/config.test.js +65 -0
  9. package/dist/config.test.js.map +1 -0
  10. package/dist/copy-template.test.d.ts +2 -0
  11. package/dist/copy-template.test.d.ts.map +1 -0
  12. package/dist/copy-template.test.js +71 -0
  13. package/dist/copy-template.test.js.map +1 -0
  14. package/dist/download-repo.test.d.ts +2 -0
  15. package/dist/download-repo.test.d.ts.map +1 -0
  16. package/dist/download-repo.test.js +14 -0
  17. package/dist/download-repo.test.js.map +1 -0
  18. package/dist/install.test.d.ts +2 -0
  19. package/dist/install.test.d.ts.map +1 -0
  20. package/dist/install.test.js +119 -0
  21. package/dist/install.test.js.map +1 -0
  22. package/dist/prepare-template-utils.d.ts.map +1 -1
  23. package/dist/prepare-template-utils.js +5 -0
  24. package/dist/prepare-template-utils.js.map +1 -1
  25. package/dist/prompts.test.d.ts +2 -0
  26. package/dist/prompts.test.d.ts.map +1 -0
  27. package/dist/prompts.test.js +58 -0
  28. package/dist/prompts.test.js.map +1 -0
  29. package/dist/scaffold-gitignore.d.ts +1 -0
  30. package/dist/scaffold-gitignore.d.ts.map +1 -1
  31. package/dist/scaffold-gitignore.js +3 -0
  32. package/dist/scaffold-gitignore.js.map +1 -1
  33. package/package.json +3 -2
  34. package/templates/default/.appraise-template-meta.json +2 -2
  35. package/templates/default/.env.example +2 -2
  36. package/templates/default/.vscode/settings.json +2 -1
  37. package/templates/default/README.md +53 -53
  38. package/templates/default/automation/mapping/locator-map.json +1 -14
  39. package/templates/default/automation/steps/actions/click.step.ts +58 -58
  40. package/templates/default/automation/steps/actions/hover.step.ts +27 -27
  41. package/templates/default/automation/steps/actions/input.step.ts +84 -84
  42. package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
  43. package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
  44. package/templates/default/automation/steps/actions/store.step.ts +86 -86
  45. package/templates/default/automation/steps/actions/wait.step.ts +90 -90
  46. package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
  47. package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
  48. package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
  49. package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
  50. package/templates/default/components.json +24 -24
  51. package/templates/default/cucumber.mjs +16 -16
  52. package/templates/default/eslint.config.mjs +16 -16
  53. package/templates/default/gitignore +3 -0
  54. package/templates/default/next-env.d.ts +6 -6
  55. package/templates/default/next.config.ts +11 -11
  56. package/templates/default/package-lock.json +146 -75
  57. package/templates/default/package.json +2 -1
  58. package/templates/default/packages/cucumber-runtime/package.json +13 -13
  59. package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
  60. package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
  61. package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
  62. package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
  63. package/templates/default/packages/cucumber-runtime/src/hooks.ts +25 -3
  64. package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
  65. package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
  66. package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
  67. package/templates/default/packages/cucumber-runtime/src/paths.ts +66 -1
  68. package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
  69. package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
  70. package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
  71. package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
  72. package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +1 -0
  73. package/templates/default/packages/locator-picker-companion/dist/cli.js +302 -0
  74. package/templates/default/packages/locator-picker-companion/dist/index.d.ts +3 -0
  75. package/templates/default/packages/locator-picker-companion/dist/index.js +3 -0
  76. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +1 -0
  77. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +615 -0
  78. package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +11 -0
  79. package/templates/default/packages/locator-picker-companion/dist/launcher.js +59 -0
  80. package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +3 -0
  81. package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +257 -0
  82. package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +22 -0
  83. package/templates/default/packages/locator-picker-companion/dist/session-file.js +150 -0
  84. package/templates/default/packages/locator-picker-companion/dist/types.d.ts +31 -0
  85. package/templates/default/packages/locator-picker-companion/dist/types.js +1 -0
  86. package/templates/default/packages/locator-picker-companion/package.json +17 -0
  87. package/templates/default/packages/locator-picker-companion/src/cli.ts +428 -0
  88. package/templates/default/packages/locator-picker-companion/src/index.ts +3 -0
  89. package/templates/default/packages/locator-picker-companion/src/injected-picker-script.ts +771 -0
  90. package/templates/default/packages/locator-picker-companion/src/launcher.ts +77 -0
  91. package/templates/default/packages/locator-picker-companion/src/selector-generator.ts +339 -0
  92. package/templates/default/packages/locator-picker-companion/src/session-file.ts +226 -0
  93. package/templates/default/packages/locator-picker-companion/src/types.ts +42 -0
  94. package/templates/default/packages/locator-picker-companion/tsconfig.json +14 -0
  95. package/templates/default/postcss.config.mjs +8 -8
  96. package/templates/default/prisma/dev.db +0 -0
  97. package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  98. package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  99. package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  100. package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  101. package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  102. package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  103. package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  104. package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  105. package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  106. package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  107. package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  108. package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  109. package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  110. package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -0
  111. package/templates/default/prisma/migrations/20260318120000_add_test_suite_context_to_test_run_test_case/migration.sql +20 -0
  112. package/templates/default/prisma/migrations/20260318173512_add_support_of_test_suite_level_runs/migration.sql +2 -0
  113. package/templates/default/prisma/schema.prisma +4 -0
  114. package/templates/default/scripts/install-playwright.ts +20 -0
  115. package/templates/default/scripts/protect-seeded-files.ts +38 -38
  116. package/templates/default/scripts/regenerate-features.ts +94 -94
  117. package/templates/default/scripts/setup-env.ts +19 -19
  118. package/templates/default/scripts/sync-all.ts +22 -66
  119. package/templates/default/scripts/sync-appraise-base-template.ts +57 -19
  120. package/templates/default/scripts/sync-environments.ts +40 -21
  121. package/templates/default/scripts/sync-locator-groups.ts +410 -410
  122. package/templates/default/scripts/sync-locators.ts +398 -398
  123. package/templates/default/scripts/sync-modules.ts +341 -341
  124. package/templates/default/scripts/sync-tags.ts +2 -3
  125. package/templates/default/scripts/sync-template-step-groups.ts +0 -3
  126. package/templates/default/scripts/sync-template-steps.ts +37 -11
  127. package/templates/default/scripts/sync-test-cases.ts +68 -16
  128. package/templates/default/scripts/sync-test-suites.ts +7 -5
  129. package/templates/default/src/actions/conflict/conflict.action.ts +33 -33
  130. package/templates/default/src/actions/dashboard/dashboard-actions.ts +240 -240
  131. package/templates/default/src/actions/environments/environment-actions.ts +188 -188
  132. package/templates/default/src/actions/locator/locator-actions.ts +490 -490
  133. package/templates/default/src/actions/locator-groups/locator-group-actions.ts +6 -3
  134. package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +243 -0
  135. package/templates/default/src/actions/modules/module-actions.ts +135 -135
  136. package/templates/default/src/actions/reports/report-actions.ts +51 -49
  137. package/templates/default/src/actions/review/review-actions.ts +147 -147
  138. package/templates/default/src/actions/settings/sync-actions.ts +46 -0
  139. package/templates/default/src/actions/tags/tag-actions.ts +107 -107
  140. package/templates/default/src/actions/template-step/template-step-actions.ts +38 -4
  141. package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +10 -3
  142. package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -238
  143. package/templates/default/src/actions/test-case/test-case-actions.ts +356 -356
  144. package/templates/default/src/actions/test-run/test-run-actions.ts +222 -129
  145. package/templates/default/src/actions/test-suite/test-suite-actions.ts +95 -17
  146. package/templates/default/src/actions/user/user-actions.ts +13 -13
  147. package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
  148. package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -219
  149. package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
  150. package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -24
  151. package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -46
  152. package/templates/default/src/app/(base)/environments/page.tsx +59 -59
  153. package/templates/default/src/app/(base)/layout.tsx +10 -10
  154. package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
  155. package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
  156. package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
  157. package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
  158. package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
  159. package/templates/default/src/app/(base)/locator-groups/page.tsx +20 -8
  160. package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +542 -0
  161. package/templates/default/src/app/(base)/locators/create/page.tsx +32 -19
  162. package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
  163. package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -73
  164. package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
  165. package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +56 -27
  166. package/templates/default/src/app/(base)/locators/page.tsx +13 -13
  167. package/templates/default/src/app/(base)/locators/picker/page.tsx +7 -0
  168. package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -66
  169. package/templates/default/src/app/(base)/modules/create/page.tsx +34 -34
  170. package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -46
  171. package/templates/default/src/app/(base)/modules/module-form.tsx +126 -126
  172. package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -85
  173. package/templates/default/src/app/(base)/modules/module-table.tsx +24 -24
  174. package/templates/default/src/app/(base)/modules/page.tsx +59 -59
  175. package/templates/default/src/app/(base)/reports/[id]/page.tsx +40 -33
  176. package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
  177. package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -78
  178. package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -46
  179. package/templates/default/src/app/(base)/reports/page.tsx +98 -98
  180. package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -16
  181. package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
  182. package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
  183. package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +12 -1
  184. package/templates/default/src/app/(base)/reports/report-view-table.tsx +1 -0
  185. package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -42
  186. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
  187. package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
  188. package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
  189. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
  190. package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
  191. package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -60
  192. package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -26
  193. package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -15
  194. package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -26
  195. package/templates/default/src/app/(base)/reviews/page.tsx +26 -26
  196. package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -26
  197. package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -11
  198. package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -9
  199. package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -9
  200. package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -15
  201. package/templates/default/src/app/(base)/settings/page.tsx +30 -0
  202. package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +261 -0
  203. package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
  204. package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
  205. package/templates/default/src/app/(base)/tags/page.tsx +58 -58
  206. package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -147
  207. package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
  208. package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
  209. package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
  210. package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -45
  211. package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
  212. package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -167
  213. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
  214. package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -32
  215. package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -37
  216. package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -49
  217. package/templates/default/src/app/(base)/template-steps/page.tsx +58 -58
  218. package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -213
  219. package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -384
  220. package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -158
  221. package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -24
  222. package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
  223. package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
  224. package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
  225. package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -84
  226. package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -262
  227. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
  228. package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
  229. package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -76
  230. package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -96
  231. package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -38
  232. package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -73
  233. package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
  234. package/templates/default/src/app/(base)/test-cases/page.tsx +2 -2
  235. package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -82
  236. package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -395
  237. package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +6 -71
  238. package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +2 -2
  239. package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +4 -1
  240. package/templates/default/src/app/(base)/test-runs/create/page.tsx +11 -9
  241. package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
  242. package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +37 -44
  243. package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
  244. package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
  245. package/templates/default/src/app/(base)/test-suites/create/page.tsx +3 -2
  246. package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +2 -1
  247. package/templates/default/src/app/(base)/test-suites/page.tsx +57 -21
  248. package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +16 -17
  249. package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +2 -1
  250. package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -29
  251. package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
  252. package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
  253. package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
  254. package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
  255. package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
  256. package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
  257. package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -0
  258. package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +97 -34
  259. package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +4 -1
  260. package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -147
  261. package/templates/default/src/app/globals.css +147 -147
  262. package/templates/default/src/app/layout.tsx +4 -0
  263. package/templates/default/src/app/page.tsx +2 -0
  264. package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
  265. package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
  266. package/templates/default/src/components/base-node.tsx +21 -21
  267. package/templates/default/src/components/chart/pie-chart.tsx +73 -73
  268. package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -460
  269. package/templates/default/src/components/data-state/empty-state.tsx +40 -40
  270. package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
  271. package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
  272. package/templates/default/src/components/diagram/button-edge.tsx +54 -54
  273. package/templates/default/src/components/diagram/dynamic-parameters.tsx +474 -474
  274. package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
  275. package/templates/default/src/components/diagram/flow-diagram.tsx +470 -470
  276. package/templates/default/src/components/diagram/node-form.tsx +262 -262
  277. package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
  278. package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
  279. package/templates/default/src/components/form/error-message.tsx +7 -7
  280. package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
  281. package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
  282. package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
  283. package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
  284. package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
  285. package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
  286. package/templates/default/src/components/logo.tsx +15 -15
  287. package/templates/default/src/components/navigation/command-badge.tsx +34 -34
  288. package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
  289. package/templates/default/src/components/navigation/entity-search-command.tsx +116 -116
  290. package/templates/default/src/components/navigation/nav-card.tsx +31 -31
  291. package/templates/default/src/components/navigation/nav-command.tsx +13 -0
  292. package/templates/default/src/components/navigation/nav-link.tsx +60 -60
  293. package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
  294. package/templates/default/src/components/node-header.tsx +159 -159
  295. package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -253
  296. package/templates/default/src/components/table/table-actions.tsx +172 -172
  297. package/templates/default/src/components/test-case/test-case-columns.tsx +76 -0
  298. package/templates/default/src/components/test-case/test-case-picker.tsx +244 -0
  299. package/templates/default/src/components/test-run/download-logs-button.tsx +92 -99
  300. package/templates/default/src/components/test-run/log-viewer.tsx +1 -14
  301. package/templates/default/src/components/test-run/test-run-details.tsx +15 -2
  302. package/templates/default/src/components/test-run/test-run-header.tsx +149 -149
  303. package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
  304. package/templates/default/src/components/test-suite/test-suite-picker.tsx +444 -0
  305. package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
  306. package/templates/default/src/components/theme/theme-provider.tsx +8 -8
  307. package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
  308. package/templates/default/src/components/typography/page-header.tsx +7 -7
  309. package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
  310. package/templates/default/src/components/ui/alert.tsx +43 -43
  311. package/templates/default/src/components/ui/avatar.tsx +40 -40
  312. package/templates/default/src/components/ui/badge.tsx +29 -29
  313. package/templates/default/src/components/ui/button.tsx +47 -47
  314. package/templates/default/src/components/ui/calendar.tsx +158 -158
  315. package/templates/default/src/components/ui/card.tsx +43 -43
  316. package/templates/default/src/components/ui/checkbox.tsx +28 -28
  317. package/templates/default/src/components/ui/command.tsx +135 -135
  318. package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
  319. package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
  320. package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
  321. package/templates/default/src/components/ui/data-table.tsx +261 -261
  322. package/templates/default/src/components/ui/dialog.tsx +97 -97
  323. package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
  324. package/templates/default/src/components/ui/input.tsx +22 -22
  325. package/templates/default/src/components/ui/kbd.tsx +28 -28
  326. package/templates/default/src/components/ui/label.tsx +19 -19
  327. package/templates/default/src/components/ui/loading.tsx +12 -12
  328. package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
  329. package/templates/default/src/components/ui/multi-select.tsx +142 -142
  330. package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
  331. package/templates/default/src/components/ui/popover.tsx +33 -33
  332. package/templates/default/src/components/ui/progress.tsx +25 -25
  333. package/templates/default/src/components/ui/radio-group.tsx +44 -44
  334. package/templates/default/src/components/ui/scroll-area.tsx +40 -40
  335. package/templates/default/src/components/ui/select.tsx +151 -151
  336. package/templates/default/src/components/ui/separator.tsx +22 -22
  337. package/templates/default/src/components/ui/skeleton.tsx +7 -7
  338. package/templates/default/src/components/ui/table.tsx +76 -76
  339. package/templates/default/src/components/ui/tabs.tsx +55 -55
  340. package/templates/default/src/components/ui/textarea.tsx +21 -21
  341. package/templates/default/src/components/ui/toast.tsx +113 -113
  342. package/templates/default/src/components/ui/toaster.tsx +26 -26
  343. package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -87
  344. package/templates/default/src/config/db-config.ts +10 -10
  345. package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
  346. package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
  347. package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -20
  348. package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
  349. package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
  350. package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -23
  351. package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
  352. package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
  353. package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
  354. package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
  355. package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
  356. package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
  357. package/templates/default/src/constants/form-opts/test-run-form-opts.ts +5 -3
  358. package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
  359. package/templates/default/src/hooks/use-toast.ts +187 -187
  360. package/templates/default/src/lib/automation/paths.ts +42 -12
  361. package/templates/default/src/lib/automation/projection-service.ts +2 -1
  362. package/templates/default/src/lib/bidirectional-sync.ts +432 -432
  363. package/templates/default/src/lib/database-sync.ts +2 -7
  364. package/templates/default/src/lib/environment-file-utils.ts +184 -184
  365. package/templates/default/src/lib/executor/local-executor-adapter.ts +24 -25
  366. package/templates/default/src/lib/executor/types.ts +2 -2
  367. package/templates/default/src/lib/feature-file-generator.ts +5 -66
  368. package/templates/default/src/lib/gherkin-parser.ts +259 -259
  369. package/templates/default/src/lib/locator-group-file-utils.ts +307 -307
  370. package/templates/default/src/lib/locator-picker/session-manager.ts +452 -0
  371. package/templates/default/src/lib/locator-picker/suggestions.ts +124 -0
  372. package/templates/default/src/lib/metrics/metric-calculator.ts +5 -0
  373. package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
  374. package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
  375. package/templates/default/src/lib/process/task-spawner.ts +39 -2
  376. package/templates/default/src/lib/sync/projected-feature-utils.ts +113 -0
  377. package/templates/default/src/lib/sync/sync-executor.ts +130 -0
  378. package/templates/default/src/lib/sync/sync-pending-counts.test.ts +239 -0
  379. package/templates/default/src/lib/sync/sync-pending-counts.ts +1358 -0
  380. package/templates/default/src/lib/sync/sync-registry.ts +149 -0
  381. package/templates/default/src/lib/tag-utils.ts +28 -0
  382. package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
  383. package/templates/default/src/lib/template-sync-utils.js +46 -46
  384. package/templates/default/src/lib/template-sync-utils.ts +63 -63
  385. package/templates/default/src/lib/test-case-utils.ts +6 -6
  386. package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
  387. package/templates/default/src/lib/test-run/matching.ts +117 -0
  388. package/templates/default/src/lib/test-run/process-manager.ts +2 -0
  389. package/templates/default/src/lib/test-run/report-parser.ts +352 -316
  390. package/templates/default/src/lib/test-run/test-run-executor.ts +13 -15
  391. package/templates/default/src/lib/test-run/winston-logger.ts +64 -66
  392. package/templates/default/src/lib/test-suite-identifier-service.ts +76 -0
  393. package/templates/default/src/lib/test-suite-utils.ts +6 -0
  394. package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
  395. package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
  396. package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
  397. package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
  398. package/templates/default/src/lib/utils/template-step-file-generator.ts +104 -104
  399. package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +0 -8
  400. package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
  401. package/templates/default/src/lib/utils.ts +31 -31
  402. package/templates/default/src/types/diagram/diagram.ts +34 -34
  403. package/templates/default/src/types/diagram/template-step.ts +11 -11
  404. package/templates/default/src/types/executor/browser.type.ts +1 -1
  405. package/templates/default/src/types/form/actionHandler.ts +6 -6
  406. package/templates/default/src/types/locator/locator.type.ts +11 -11
  407. package/templates/default/src/types/locator-picker.ts +65 -0
  408. package/templates/default/src/types/step/step.type.ts +1 -1
  409. package/templates/default/src/types/table/data-table.ts +6 -6
  410. package/templates/default/src/types/test-case-picker.ts +6 -0
  411. package/templates/default/src/types/test-suite-picker.ts +18 -0
  412. package/templates/default/tailwind.config.ts +62 -62
  413. package/templates/default/tsconfig.json +4 -1
  414. package/templates/default/appraisejs.config.json +0 -1
@@ -1,30 +1,30 @@
1
- import React from 'react'
2
- import IconButtonSkeleton from '../form/icon-button-skeleton'
3
- import TextInputSkeleton from '../form/text-input-skeleton'
4
- import ButtonSkeleton from '../form/button-skeleton'
5
- import { Search } from 'lucide-react'
6
- import TableSkeleton from '../visualization/table-skeleton'
7
-
8
- const DataTableSkeleton = () => {
9
- return (
10
- <>
11
- <div className="flex justify-end">
12
- <div className="flex gap-2">
13
- <IconButtonSkeleton />
14
- <IconButtonSkeleton />
15
- <IconButtonSkeleton />
16
- </div>
17
- </div>
18
- <div className="mb-6 mt-4 flex justify-between">
19
- <div className="flex items-center gap-2">
20
- <Search className="mr-2 h-5 w-5" />
21
- <TextInputSkeleton />
22
- </div>
23
- <ButtonSkeleton />
24
- </div>
25
- <TableSkeleton />
26
- </>
27
- )
28
- }
29
-
30
- export default DataTableSkeleton
1
+ import React from 'react'
2
+ import IconButtonSkeleton from '../form/icon-button-skeleton'
3
+ import TextInputSkeleton from '../form/text-input-skeleton'
4
+ import ButtonSkeleton from '../form/button-skeleton'
5
+ import { Search } from 'lucide-react'
6
+ import TableSkeleton from '../visualization/table-skeleton'
7
+
8
+ const DataTableSkeleton = () => {
9
+ return (
10
+ <>
11
+ <div className="flex justify-end">
12
+ <div className="flex gap-2">
13
+ <IconButtonSkeleton />
14
+ <IconButtonSkeleton />
15
+ <IconButtonSkeleton />
16
+ </div>
17
+ </div>
18
+ <div className="mb-6 mt-4 flex justify-between">
19
+ <div className="flex items-center gap-2">
20
+ <Search className="mr-2 h-5 w-5" />
21
+ <TextInputSkeleton />
22
+ </div>
23
+ <ButtonSkeleton />
24
+ </div>
25
+ <TableSkeleton />
26
+ </>
27
+ )
28
+ }
29
+
30
+ export default DataTableSkeleton
@@ -1,8 +1,8 @@
1
- import { Skeleton } from '@/components/ui/skeleton'
2
- import React from 'react'
3
-
4
- const ButtonSkeleton = () => {
5
- return <Skeleton className="h-10 w-24" />
6
- }
7
-
8
- export default ButtonSkeleton
1
+ import { Skeleton } from '@/components/ui/skeleton'
2
+ import React from 'react'
3
+
4
+ const ButtonSkeleton = () => {
5
+ return <Skeleton className="h-10 w-24" />
6
+ }
7
+
8
+ export default ButtonSkeleton
@@ -1,8 +1,8 @@
1
- import { Skeleton } from '@/components/ui/skeleton'
2
- import React from 'react'
3
-
4
- const IconButtonSkeleton = () => {
5
- return <Skeleton className="h-8 w-8 rounded-sm" />
6
- }
7
-
8
- export default IconButtonSkeleton
1
+ import { Skeleton } from '@/components/ui/skeleton'
2
+ import React from 'react'
3
+
4
+ const IconButtonSkeleton = () => {
5
+ return <Skeleton className="h-8 w-8 rounded-sm" />
6
+ }
7
+
8
+ export default IconButtonSkeleton
@@ -1,8 +1,8 @@
1
- import { Skeleton } from '@/components/ui/skeleton'
2
- import React from 'react'
3
-
4
- const TextInputSkeleton = () => {
5
- return <Skeleton className="h-10 w-44" />
6
- }
7
-
8
- export default TextInputSkeleton
1
+ import { Skeleton } from '@/components/ui/skeleton'
2
+ import React from 'react'
3
+
4
+ const TextInputSkeleton = () => {
5
+ return <Skeleton className="h-10 w-44" />
6
+ }
7
+
8
+ export default TextInputSkeleton
@@ -1,14 +1,14 @@
1
- import { Skeleton } from '@/components/ui/skeleton'
2
- import React from 'react'
3
-
4
- const TableSkeleton = () => {
5
- return (
6
- <div className="flex flex-col gap-2">
7
- <Skeleton className="h-10 w-full" />
8
- <Skeleton className="h-10 w-full" />
9
- <Skeleton className="h-10 w-full" />
10
- </div>
11
- )
12
- }
13
-
14
- export default TableSkeleton
1
+ import { Skeleton } from '@/components/ui/skeleton'
2
+ import React from 'react'
3
+
4
+ const TableSkeleton = () => {
5
+ return (
6
+ <div className="flex flex-col gap-2">
7
+ <Skeleton className="h-10 w-full" />
8
+ <Skeleton className="h-10 w-full" />
9
+ <Skeleton className="h-10 w-full" />
10
+ </div>
11
+ )
12
+ }
13
+
14
+ export default TableSkeleton
@@ -1,15 +1,15 @@
1
- import { FlaskConical } from 'lucide-react'
2
-
3
- const Logo = () => {
4
- return (
5
- <div className="m-2 flex items-center">
6
- <FlaskConical size={25} className="mr-2 text-primary" />
7
- <span className="rounded-l-lg bg-gray-800 bg-primary pb-1 pl-1 text-xl tracking-widest text-white underline dark:text-gray-700">
8
- app
9
- </span>
10
- <span className="text-xl tracking-widest text-primary">raise</span>
11
- </div>
12
- )
13
- }
14
-
15
- export default Logo
1
+ import { FlaskConical } from 'lucide-react'
2
+
3
+ const Logo = () => {
4
+ return (
5
+ <div className="m-2 flex items-center">
6
+ <FlaskConical size={25} className="mr-2 text-primary" />
7
+ <span className="rounded-l-lg bg-gray-800 bg-primary pb-1 pl-1 text-xl tracking-widest text-white underline dark:text-gray-700">
8
+ app
9
+ </span>
10
+ <span className="text-xl tracking-widest text-primary">raise</span>
11
+ </div>
12
+ )
13
+ }
14
+
15
+ export default Logo
@@ -1,34 +1,34 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import { X } from 'lucide-react'
5
- import { Badge } from '../ui/badge'
6
- import { cn } from '@/lib/utils'
7
-
8
- export interface CommandBadgeProps {
9
- label: string
10
- onClose: () => void
11
- className?: string
12
- }
13
-
14
- export function CommandBadge({ label, onClose, className }: CommandBadgeProps) {
15
- return (
16
- <Badge
17
- variant="secondary"
18
- className={cn('inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium', className)}
19
- >
20
- <span>{label}</span>
21
- <button
22
- type="button"
23
- onClick={e => {
24
- e.stopPropagation()
25
- onClose()
26
- }}
27
- className="hover:bg-secondary-foreground/20 ml-0.5 rounded-sm focus:outline-none focus:ring-1 focus:ring-ring"
28
- aria-label={`Clear ${label}`}
29
- >
30
- <X className="h-3 w-3" />
31
- </button>
32
- </Badge>
33
- )
34
- }
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { X } from 'lucide-react'
5
+ import { Badge } from '../ui/badge'
6
+ import { cn } from '@/lib/utils'
7
+
8
+ export interface CommandBadgeProps {
9
+ label: string
10
+ onClose: () => void
11
+ className?: string
12
+ }
13
+
14
+ export function CommandBadge({ label, onClose, className }: CommandBadgeProps) {
15
+ return (
16
+ <Badge
17
+ variant="secondary"
18
+ className={cn('inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium', className)}
19
+ >
20
+ <span>{label}</span>
21
+ <button
22
+ type="button"
23
+ onClick={e => {
24
+ e.stopPropagation()
25
+ onClose()
26
+ }}
27
+ className="hover:bg-secondary-foreground/20 ml-0.5 rounded-sm focus:outline-none focus:ring-1 focus:ring-ring"
28
+ aria-label={`Clear ${label}`}
29
+ >
30
+ <X className="h-3 w-3" />
31
+ </button>
32
+ </Badge>
33
+ )
34
+ }
@@ -1,51 +1,51 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import { Command as CommandPrimitive } from 'cmdk'
5
- import { Search } from 'lucide-react'
6
- import { CommandBadge } from './command-badge'
7
- import { cn } from '@/lib/utils'
8
-
9
- export interface CommandChainInputProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> {
10
- badge?: {
11
- label: string
12
- onClose: () => void
13
- }
14
- }
15
-
16
- export const CommandChainInput = React.forwardRef<
17
- React.ElementRef<typeof CommandPrimitive.Input>,
18
- CommandChainInputProps
19
- >(({ badge, className, onKeyDown, ...props }, ref) => {
20
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
21
- // If backspace is pressed and input is empty, clear the badge
22
- if (e.key === 'Backspace' && !(e.target as HTMLInputElement).value && badge) {
23
- e.preventDefault()
24
- badge.onClose()
25
- return
26
- }
27
- onKeyDown?.(e)
28
- }
29
-
30
- return (
31
- <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
32
- <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
33
- {badge && (
34
- <div className="mr-2 flex-shrink-0">
35
- <CommandBadge label={badge.label} onClose={badge.onClose} />
36
- </div>
37
- )}
38
- <CommandPrimitive.Input
39
- ref={ref}
40
- className={cn(
41
- 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
42
- className,
43
- )}
44
- onKeyDown={handleKeyDown}
45
- {...props}
46
- />
47
- </div>
48
- )
49
- })
50
-
51
- CommandChainInput.displayName = 'CommandChainInput'
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Command as CommandPrimitive } from 'cmdk'
5
+ import { Search } from 'lucide-react'
6
+ import { CommandBadge } from './command-badge'
7
+ import { cn } from '@/lib/utils'
8
+
9
+ export interface CommandChainInputProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> {
10
+ badge?: {
11
+ label: string
12
+ onClose: () => void
13
+ }
14
+ }
15
+
16
+ export const CommandChainInput = React.forwardRef<
17
+ React.ElementRef<typeof CommandPrimitive.Input>,
18
+ CommandChainInputProps
19
+ >(({ badge, className, onKeyDown, ...props }, ref) => {
20
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
21
+ // If backspace is pressed and input is empty, clear the badge
22
+ if (e.key === 'Backspace' && !(e.target as HTMLInputElement).value && badge) {
23
+ e.preventDefault()
24
+ badge.onClose()
25
+ return
26
+ }
27
+ onKeyDown?.(e)
28
+ }
29
+
30
+ return (
31
+ <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
32
+ <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
33
+ {badge && (
34
+ <div className="mr-2 flex-shrink-0">
35
+ <CommandBadge label={badge.label} onClose={badge.onClose} />
36
+ </div>
37
+ )}
38
+ <CommandPrimitive.Input
39
+ ref={ref}
40
+ className={cn(
41
+ 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
42
+ className,
43
+ )}
44
+ onKeyDown={handleKeyDown}
45
+ {...props}
46
+ />
47
+ </div>
48
+ )
49
+ })
50
+
51
+ CommandChainInput.displayName = 'CommandChainInput'
@@ -1,116 +1,116 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import { useEffect, useState, useMemo } from 'react'
5
- import { CommandGroup, CommandItem } from '../ui/command'
6
- import { ActionResponse } from '@/types/form/actionHandler'
7
-
8
- export interface EntitySearchCommandProps<T extends { id: string }> {
9
- searchQuery: string
10
- entityName: string
11
- fetchAction: () => Promise<ActionResponse>
12
- searchKey: keyof T
13
- icon?: React.ReactNode
14
- onSelect?: (entity: T) => void
15
- }
16
-
17
- export function EntitySearchCommand<T extends { id: string }>({
18
- searchQuery,
19
- entityName,
20
- fetchAction,
21
- searchKey,
22
- icon,
23
- onSelect,
24
- }: EntitySearchCommandProps<T>) {
25
- const [entities, setEntities] = useState<T[]>([])
26
- const [isLoading, setIsLoading] = useState(true)
27
- const [error, setError] = useState<string | null>(null)
28
-
29
- useEffect(() => {
30
- let isMounted = true
31
-
32
- const fetchEntities = async () => {
33
- setIsLoading(true)
34
- setError(null)
35
- try {
36
- const result = await fetchAction()
37
- if (isMounted) {
38
- if (result.status === 200 && result.data) {
39
- setEntities(result.data as T[])
40
- } else {
41
- setError(result.error || 'Failed to fetch entities')
42
- }
43
- setIsLoading(false)
44
- }
45
- } catch (err) {
46
- if (isMounted) {
47
- setError(err instanceof Error ? err.message : 'An error occurred')
48
- setIsLoading(false)
49
- }
50
- }
51
- }
52
-
53
- fetchEntities()
54
-
55
- return () => {
56
- isMounted = false
57
- }
58
- }, [fetchAction])
59
-
60
- const filteredEntities = useMemo(() => {
61
- if (!searchQuery.trim()) {
62
- return entities
63
- }
64
-
65
- const query = searchQuery.toLowerCase()
66
- return entities.filter(entity => {
67
- const value = entity[searchKey]
68
- if (typeof value === 'string') {
69
- return value.toLowerCase().includes(query)
70
- }
71
- return false
72
- })
73
- }, [entities, searchQuery, searchKey])
74
-
75
- if (isLoading) {
76
- return (
77
- <CommandGroup heading={`Searching ${entityName}...`}>
78
- <CommandItem disabled>Loading...</CommandItem>
79
- </CommandGroup>
80
- )
81
- }
82
-
83
- if (error) {
84
- return (
85
- <CommandGroup heading="Error">
86
- <CommandItem disabled className="text-destructive">
87
- {error}
88
- </CommandItem>
89
- </CommandGroup>
90
- )
91
- }
92
-
93
- if (filteredEntities.length === 0) {
94
- return <></>
95
- }
96
-
97
- return (
98
- <CommandGroup heading={`${entityName} Results`}>
99
- {filteredEntities.map(entity => {
100
- const displayValue = entity[searchKey]
101
- return (
102
- <CommandItem
103
- key={entity.id}
104
- value={typeof displayValue === 'string' ? displayValue : entity.id}
105
- onSelect={() => {
106
- onSelect?.(entity)
107
- }}
108
- >
109
- {icon}
110
- <span>{typeof displayValue === 'string' ? displayValue : entity.id}</span>
111
- </CommandItem>
112
- )
113
- })}
114
- </CommandGroup>
115
- )
116
- }
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { useEffect, useState, useMemo } from 'react'
5
+ import { CommandGroup, CommandItem } from '../ui/command'
6
+ import { ActionResponse } from '@/types/form/actionHandler'
7
+
8
+ export interface EntitySearchCommandProps<T extends { id: string }> {
9
+ searchQuery: string
10
+ entityName: string
11
+ fetchAction: () => Promise<ActionResponse>
12
+ searchKey: keyof T
13
+ icon?: React.ReactNode
14
+ onSelect?: (entity: T) => void
15
+ }
16
+
17
+ export function EntitySearchCommand<T extends { id: string }>({
18
+ searchQuery,
19
+ entityName,
20
+ fetchAction,
21
+ searchKey,
22
+ icon,
23
+ onSelect,
24
+ }: EntitySearchCommandProps<T>) {
25
+ const [entities, setEntities] = useState<T[]>([])
26
+ const [isLoading, setIsLoading] = useState(true)
27
+ const [error, setError] = useState<string | null>(null)
28
+
29
+ useEffect(() => {
30
+ let isMounted = true
31
+
32
+ const fetchEntities = async () => {
33
+ setIsLoading(true)
34
+ setError(null)
35
+ try {
36
+ const result = await fetchAction()
37
+ if (isMounted) {
38
+ if (result.status === 200 && result.data) {
39
+ setEntities(result.data as T[])
40
+ } else {
41
+ setError(result.error || 'Failed to fetch entities')
42
+ }
43
+ setIsLoading(false)
44
+ }
45
+ } catch (err) {
46
+ if (isMounted) {
47
+ setError(err instanceof Error ? err.message : 'An error occurred')
48
+ setIsLoading(false)
49
+ }
50
+ }
51
+ }
52
+
53
+ fetchEntities()
54
+
55
+ return () => {
56
+ isMounted = false
57
+ }
58
+ }, [fetchAction])
59
+
60
+ const filteredEntities = useMemo(() => {
61
+ if (!searchQuery.trim()) {
62
+ return entities
63
+ }
64
+
65
+ const query = searchQuery.toLowerCase()
66
+ return entities.filter(entity => {
67
+ const value = entity[searchKey]
68
+ if (typeof value === 'string') {
69
+ return value.toLowerCase().includes(query)
70
+ }
71
+ return false
72
+ })
73
+ }, [entities, searchQuery, searchKey])
74
+
75
+ if (isLoading) {
76
+ return (
77
+ <CommandGroup heading={`Searching ${entityName}...`}>
78
+ <CommandItem disabled>Loading...</CommandItem>
79
+ </CommandGroup>
80
+ )
81
+ }
82
+
83
+ if (error) {
84
+ return (
85
+ <CommandGroup heading="Error">
86
+ <CommandItem disabled className="text-destructive">
87
+ {error}
88
+ </CommandItem>
89
+ </CommandGroup>
90
+ )
91
+ }
92
+
93
+ if (filteredEntities.length === 0) {
94
+ return <></>
95
+ }
96
+
97
+ return (
98
+ <CommandGroup heading={`${entityName} Results`}>
99
+ {filteredEntities.map(entity => {
100
+ const displayValue = entity[searchKey]
101
+ return (
102
+ <CommandItem
103
+ key={entity.id}
104
+ value={typeof displayValue === 'string' ? displayValue : entity.id}
105
+ onSelect={() => {
106
+ onSelect?.(entity)
107
+ }}
108
+ >
109
+ {icon}
110
+ <span>{typeof displayValue === 'string' ? displayValue : entity.id}</span>
111
+ </CommandItem>
112
+ )
113
+ })}
114
+ </CommandGroup>
115
+ )
116
+ }
@@ -1,31 +1,31 @@
1
- import React from 'react'
2
- import { Card, CardContent } from '../ui/card'
3
- import Link from 'next/link'
4
-
5
- const NavCard = ({
6
- data,
7
- href,
8
- icon,
9
- }: {
10
- data: { title: string; description: string }
11
- href: string
12
- icon: React.ReactNode
13
- }) => {
14
- return (
15
- <Link href={href} className="w-full">
16
- <Card className="h-24 w-full border-none outline-none transition-colors hover:bg-accent hover:text-accent-foreground">
17
- <CardContent className="flex h-full w-full items-center gap-3 p-4">
18
- <div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-md text-accent-foreground">
19
- {icon}
20
- </div>
21
- <div className="flex min-w-0 flex-1 flex-col justify-center">
22
- <span className="truncate text-sm font-medium">{data.title}</span>
23
- <span className="line-clamp-2 text-xs text-muted-foreground">{data.description}</span>
24
- </div>
25
- </CardContent>
26
- </Card>
27
- </Link>
28
- )
29
- }
30
-
31
- export default NavCard
1
+ import React from 'react'
2
+ import { Card, CardContent } from '../ui/card'
3
+ import Link from 'next/link'
4
+
5
+ const NavCard = ({
6
+ data,
7
+ href,
8
+ icon,
9
+ }: {
10
+ data: { title: string; description: string }
11
+ href: string
12
+ icon: React.ReactNode
13
+ }) => {
14
+ return (
15
+ <Link href={href} className="w-full">
16
+ <Card className="h-24 w-full border-none outline-none transition-colors hover:bg-accent hover:text-accent-foreground">
17
+ <CardContent className="flex h-full w-full items-center gap-3 p-4">
18
+ <div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-md text-accent-foreground">
19
+ {icon}
20
+ </div>
21
+ <div className="flex min-w-0 flex-1 flex-col justify-center">
22
+ <span className="truncate text-sm font-medium">{data.title}</span>
23
+ <span className="line-clamp-2 text-xs text-muted-foreground">{data.description}</span>
24
+ </div>
25
+ </CardContent>
26
+ </Card>
27
+ </Link>
28
+ )
29
+ }
30
+
31
+ export default NavCard