create-appraisejs 0.1.7 → 0.1.8
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.
- package/README.md +45 -45
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/copy-template.d.ts.map +1 -1
- package/dist/copy-template.js.map +1 -1
- package/package.json +69 -67
- package/templates/default/.vscode/settings.json +5 -0
- package/templates/default/appraisejs.config.json +1 -1
- package/templates/default/components.json +24 -24
- package/templates/default/cucumber.mjs +16 -0
- package/templates/default/eslint.config.mjs +15 -15
- package/templates/default/next.config.ts +13 -7
- package/templates/default/package-lock.json +13732 -14321
- package/templates/default/package.json +11 -9
- package/templates/default/postcss.config.mjs +8 -8
- package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
- package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
- package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
- package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
- package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
- package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
- package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
- package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
- package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
- package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
- package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
- package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
- package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
- package/templates/default/prisma/schema.prisma +554 -554
- package/templates/default/scripts/regenerate-features.ts +94 -94
- package/templates/default/scripts/setup-env.ts +19 -19
- package/templates/default/scripts/sync-all.ts +341 -341
- package/templates/default/scripts/sync-appraise-base-template.ts +52 -2
- package/templates/default/scripts/sync-environments.ts +323 -323
- package/templates/default/scripts/sync-locator-groups.ts +413 -413
- package/templates/default/scripts/sync-locators.ts +402 -402
- package/templates/default/scripts/sync-modules.ts +349 -349
- package/templates/default/scripts/sync-tags.ts +292 -292
- package/templates/default/scripts/sync-template-step-groups.ts +399 -399
- package/templates/default/scripts/sync-template-steps.ts +806 -806
- package/templates/default/scripts/sync-test-cases.ts +905 -905
- package/templates/default/scripts/sync-test-suites.ts +411 -411
- package/templates/default/src/actions/conflict/conflict.action.ts +33 -33
- package/templates/default/src/actions/dashboard/dashboard-actions.ts +240 -240
- package/templates/default/src/actions/environments/environment-actions.ts +205 -205
- package/templates/default/src/actions/locator/locator-actions.ts +547 -547
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -344
- package/templates/default/src/actions/modules/module-actions.ts +133 -133
- package/templates/default/src/actions/reports/report-actions.ts +613 -613
- package/templates/default/src/actions/review/review-actions.ts +147 -147
- package/templates/default/src/actions/tags/tag-actions.ts +104 -104
- package/templates/default/src/actions/template-step/template-step-actions.ts +332 -332
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -278
- package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -238
- package/templates/default/src/actions/test-case/test-case-actions.ts +419 -419
- package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -1185
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -253
- package/templates/default/src/actions/user/user-actions.ts +13 -13
- package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
- package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -219
- package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
- package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -24
- package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/environments/page.tsx +59 -59
- package/templates/default/src/app/(base)/layout.tsx +10 -10
- package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
- package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
- package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
- package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
- package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/locator-groups/page.tsx +61 -61
- package/templates/default/src/app/(base)/locators/create/page.tsx +38 -38
- package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
- package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -90
- package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
- package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -45
- package/templates/default/src/app/(base)/locators/page.tsx +65 -65
- package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -66
- package/templates/default/src/app/(base)/modules/create/page.tsx +34 -34
- package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/modules/module-form.tsx +126 -126
- package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -85
- package/templates/default/src/app/(base)/modules/module-table.tsx +24 -24
- package/templates/default/src/app/(base)/modules/page.tsx +59 -59
- package/templates/default/src/app/(base)/reports/[id]/page.tsx +517 -517
- package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
- package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -78
- package/templates/default/src/app/(base)/reports/overview-chart.tsx +46 -46
- package/templates/default/src/app/(base)/reports/page.tsx +98 -98
- package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -16
- package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
- package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
- package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +131 -131
- package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -82
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -42
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
- package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
- package/templates/default/src/app/(base)/reports/view-logs-button.tsx +60 -60
- package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -15
- package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -11
- package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -9
- package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -9
- package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -15
- package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
- package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
- package/templates/default/src/app/(base)/tags/page.tsx +58 -58
- package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -147
- package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
- package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
- package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
- package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -45
- package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -167
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -32
- package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -37
- package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -49
- package/templates/default/src/app/(base)/template-steps/page.tsx +59 -59
- package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -213
- package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -384
- package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -158
- package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -24
- package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
- package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
- package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -84
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -262
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
- package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -76
- package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -96
- package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -38
- package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -73
- package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
- package/templates/default/src/app/(base)/test-cases/page.tsx +60 -60
- package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -82
- package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -395
- package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +90 -90
- package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -35
- package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -56
- package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -47
- package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
- package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +508 -512
- package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
- package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
- package/templates/default/src/app/(base)/test-suites/create/page.tsx +45 -45
- package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -55
- package/templates/default/src/app/(base)/test-suites/page.tsx +82 -82
- package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -269
- package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -97
- package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -29
- package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
- package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
- package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
- package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
- package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
- package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
- package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +133 -133
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -420
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -146
- package/templates/default/src/app/globals.css +147 -147
- package/templates/default/src/app/layout.tsx +171 -171
- package/templates/default/src/app/page.tsx +64 -64
- package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
- package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
- package/templates/default/src/components/base-node.tsx +21 -21
- package/templates/default/src/components/chart/pie-chart.tsx +73 -73
- package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -460
- package/templates/default/src/components/data-state/empty-state.tsx +40 -40
- package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
- package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
- package/templates/default/src/components/devtools/providers.tsx +19 -13
- package/templates/default/src/components/diagram/button-edge.tsx +54 -54
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -438
- package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
- package/templates/default/src/components/diagram/flow-diagram.tsx +470 -470
- package/templates/default/src/components/diagram/node-form.tsx +262 -262
- package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
- package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
- package/templates/default/src/components/form/error-message.tsx +7 -7
- package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
- package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
- package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
- package/templates/default/src/components/logo.tsx +15 -15
- package/templates/default/src/components/navigation/command-badge.tsx +34 -34
- package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
- package/templates/default/src/components/navigation/entity-search-command.tsx +116 -116
- package/templates/default/src/components/navigation/nav-card.tsx +31 -31
- package/templates/default/src/components/navigation/nav-command.tsx +508 -508
- package/templates/default/src/components/navigation/nav-link.tsx +60 -60
- package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
- package/templates/default/src/components/node-header.tsx +159 -159
- package/templates/default/src/components/reports/test-case-logs-modal.tsx +253 -253
- package/templates/default/src/components/table/table-actions.tsx +172 -172
- package/templates/default/src/components/test-run/download-logs-button.tsx +99 -99
- package/templates/default/src/components/test-run/log-viewer.tsx +445 -445
- package/templates/default/src/components/test-run/test-run-details.tsx +611 -611
- package/templates/default/src/components/test-run/test-run-header.tsx +149 -149
- package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
- package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
- package/templates/default/src/components/theme/theme-provider.tsx +8 -8
- package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
- package/templates/default/src/components/typography/page-header.tsx +7 -7
- package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
- package/templates/default/src/components/ui/alert.tsx +43 -43
- package/templates/default/src/components/ui/avatar.tsx +40 -40
- package/templates/default/src/components/ui/badge.tsx +29 -29
- package/templates/default/src/components/ui/button.tsx +47 -47
- package/templates/default/src/components/ui/calendar.tsx +158 -158
- package/templates/default/src/components/ui/card.tsx +43 -43
- package/templates/default/src/components/ui/checkbox.tsx +28 -28
- package/templates/default/src/components/ui/command.tsx +135 -135
- package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
- package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
- package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
- package/templates/default/src/components/ui/data-table.tsx +267 -267
- package/templates/default/src/components/ui/dialog.tsx +97 -97
- package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
- package/templates/default/src/components/ui/input.tsx +22 -22
- package/templates/default/src/components/ui/kbd.tsx +28 -28
- package/templates/default/src/components/ui/label.tsx +19 -19
- package/templates/default/src/components/ui/loading.tsx +12 -12
- package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
- package/templates/default/src/components/ui/multi-select.tsx +142 -142
- package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
- package/templates/default/src/components/ui/popover.tsx +33 -33
- package/templates/default/src/components/ui/progress.tsx +25 -25
- package/templates/default/src/components/ui/radio-group.tsx +44 -44
- package/templates/default/src/components/ui/scroll-area.tsx +40 -40
- package/templates/default/src/components/ui/select.tsx +151 -144
- package/templates/default/src/components/ui/separator.tsx +22 -22
- package/templates/default/src/components/ui/skeleton.tsx +7 -7
- package/templates/default/src/components/ui/table.tsx +76 -76
- package/templates/default/src/components/ui/tabs.tsx +55 -55
- package/templates/default/src/components/ui/textarea.tsx +21 -21
- package/templates/default/src/components/ui/toast.tsx +113 -113
- package/templates/default/src/components/ui/toaster.tsx +26 -26
- package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -87
- package/templates/default/src/config/db-config.ts +10 -10
- package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
- package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
- package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -20
- package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
- package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
- package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -23
- package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
- package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
- package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
- package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
- package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
- package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
- package/templates/default/src/constants/form-opts/test-run-form-opts.ts +31 -31
- package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
- package/templates/default/src/hooks/use-toast.ts +187 -187
- package/templates/default/src/lib/bidirectional-sync.ts +432 -432
- package/templates/default/src/lib/database-sync.ts +531 -531
- package/templates/default/src/lib/environment-file-utils.ts +221 -221
- package/templates/default/src/lib/feature-file-generator.ts +411 -411
- package/templates/default/src/lib/gherkin-parser.ts +259 -259
- package/templates/default/src/lib/locator-group-file-utils.ts +370 -370
- package/templates/default/src/lib/metrics/metric-calculator.ts +613 -613
- package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
- package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
- package/templates/default/src/lib/test-case-utils.ts +6 -6
- package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
- package/templates/default/src/lib/test-run/process-manager.ts +191 -191
- package/templates/default/src/lib/test-run/report-parser.ts +316 -316
- package/templates/default/src/lib/test-run/test-run-executor.ts +144 -144
- package/templates/default/src/lib/test-run/winston-logger.ts +95 -95
- package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
- package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
- package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
- package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
- package/templates/default/src/lib/utils/template-step-file-generator.ts +167 -167
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -723
- package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
- package/templates/default/src/lib/utils.ts +31 -31
- package/templates/default/src/tests/config/executor/world.ts +41 -41
- package/templates/default/src/tests/executor.ts +80 -80
- package/templates/default/src/tests/hooks/hooks.ts +99 -99
- package/templates/default/src/tests/mapping/locator-map.json +1 -1
- package/templates/default/src/tests/steps/actions/click.step.ts +62 -62
- package/templates/default/src/tests/steps/actions/navigation.step.ts +73 -72
- package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -34
- package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +24 -23
- package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -111
- package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -30
- package/templates/default/src/tests/support/parameter-types.ts +12 -12
- package/templates/default/src/tests/utils/cache.util.ts +260 -260
- package/templates/default/src/tests/utils/cli.util.ts +177 -177
- package/templates/default/src/tests/utils/environment.util.ts +65 -65
- package/templates/default/src/tests/utils/locator.util.ts +248 -248
- package/templates/default/src/tests/utils/random-data.util.ts +44 -44
- package/templates/default/src/tests/utils/spawner.util.ts +617 -617
- package/templates/default/src/types/diagram/diagram.ts +34 -34
- package/templates/default/src/types/diagram/template-step.ts +11 -11
- package/templates/default/src/types/executor/browser.type.ts +1 -1
- package/templates/default/src/types/form/actionHandler.ts +6 -6
- package/templates/default/src/types/locator/locator.type.ts +11 -11
- package/templates/default/src/types/step/step.type.ts +1 -1
- package/templates/default/src/types/table/data-table.ts +6 -6
- package/templates/default/tailwind.config.ts +62 -62
- package/templates/default/.env +0 -2
- package/templates/default/next-env.d.ts +0 -6
- package/templates/default/prisma/prisma/dev.db +0 -0
- package/templates/default/src/tests/config/environments/environments.json +0 -14
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
-
import { getTestRunByIdAction } from '@/actions/test-run/test-run-actions'
|
|
5
|
-
import PageHeader from '@/components/typography/page-header'
|
|
6
|
-
import HeaderSubtitle from '@/components/typography/page-header-subtitle'
|
|
7
|
-
import { ViewReportButton } from '@/components/test-run/view-report-button'
|
|
8
|
-
import { TestRun, TestRunTestCase, Tag, Environment, TestRunStatus, Report } from '@prisma/client'
|
|
9
|
-
|
|
10
|
-
interface TestRunHeaderProps {
|
|
11
|
-
initialTestRun: TestRun & {
|
|
12
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
13
|
-
tags: Tag[]
|
|
14
|
-
environment: Environment
|
|
15
|
-
reports: Report[]
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function TestRunHeader({ initialTestRun }: TestRunHeaderProps) {
|
|
20
|
-
const [testRun, setTestRun] = useState(initialTestRun)
|
|
21
|
-
|
|
22
|
-
// Poll for status updates while test run is running or queued
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
// Only poll if test run is not completed/cancelled
|
|
25
|
-
if (testRun.status === TestRunStatus.COMPLETED || testRun.status === TestRunStatus.CANCELLED) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const pollInterval = setInterval(async () => {
|
|
30
|
-
try {
|
|
31
|
-
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
32
|
-
if (error || !updatedTestRun) {
|
|
33
|
-
console.error('Error polling test run status:', error)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const typedTestRun = updatedTestRun as TestRun & {
|
|
38
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
39
|
-
tags: Tag[]
|
|
40
|
-
environment: Environment
|
|
41
|
-
reports: Report[]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Update state with latest test run data
|
|
45
|
-
setTestRun(typedTestRun)
|
|
46
|
-
|
|
47
|
-
// Stop polling if test run is completed or cancelled
|
|
48
|
-
if (typedTestRun.status === TestRunStatus.COMPLETED || typedTestRun.status === TestRunStatus.CANCELLED) {
|
|
49
|
-
clearInterval(pollInterval)
|
|
50
|
-
}
|
|
51
|
-
} catch (error) {
|
|
52
|
-
console.error('Error polling test run status:', error)
|
|
53
|
-
}
|
|
54
|
-
}, 2000) // Poll every 2 seconds
|
|
55
|
-
|
|
56
|
-
return () => clearInterval(pollInterval)
|
|
57
|
-
}, [testRun.id, testRun.status])
|
|
58
|
-
|
|
59
|
-
// Listen for SSE exit events from LogViewer as a backup signal
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const handleTestRunExit = (event: CustomEvent<{ testRunId: string }>) => {
|
|
62
|
-
// Only handle events for this test run
|
|
63
|
-
if (event.detail.testRunId === testRun.runId) {
|
|
64
|
-
// Trigger a status refresh
|
|
65
|
-
getTestRunByIdAction(testRun.id)
|
|
66
|
-
.then(response => {
|
|
67
|
-
if (response.data && !response.error) {
|
|
68
|
-
const typedTestRun = response.data as TestRun & {
|
|
69
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
70
|
-
tags: Tag[]
|
|
71
|
-
environment: Environment
|
|
72
|
-
reports: Report[]
|
|
73
|
-
}
|
|
74
|
-
setTestRun(typedTestRun)
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
.catch(error => {
|
|
78
|
-
console.error('Error refreshing test run status after exit event:', error)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Listen for custom event dispatched by LogViewer
|
|
84
|
-
window.addEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
85
|
-
|
|
86
|
-
return () => {
|
|
87
|
-
window.removeEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
88
|
-
}
|
|
89
|
-
}, [testRun.id, testRun.runId])
|
|
90
|
-
|
|
91
|
-
// Poll for report updates after test run completes
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
// Only poll if test run is completed (not cancelled) but no report exists yet
|
|
94
|
-
// Cancelled runs won't generate reports, so we don't poll for them
|
|
95
|
-
const shouldPoll = testRun.status === TestRunStatus.COMPLETED && testRun.reports.length === 0
|
|
96
|
-
|
|
97
|
-
if (!shouldPoll) {
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Poll for reports (they might be created asynchronously after test run completes)
|
|
102
|
-
const pollInterval = setInterval(async () => {
|
|
103
|
-
try {
|
|
104
|
-
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
105
|
-
if (error || !updatedTestRun) {
|
|
106
|
-
console.error('Error polling for report:', error)
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const typedTestRun = updatedTestRun as TestRun & {
|
|
111
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
112
|
-
tags: Tag[]
|
|
113
|
-
environment: Environment
|
|
114
|
-
reports: Report[]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Update if reports are now available
|
|
118
|
-
if (typedTestRun.reports.length > 0) {
|
|
119
|
-
setTestRun(typedTestRun)
|
|
120
|
-
clearInterval(pollInterval)
|
|
121
|
-
}
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Error polling for report:', error)
|
|
124
|
-
}
|
|
125
|
-
}, 2000) // Poll every 2 seconds
|
|
126
|
-
|
|
127
|
-
// Stop polling after 30 seconds to avoid infinite polling
|
|
128
|
-
const timeout = setTimeout(() => {
|
|
129
|
-
clearInterval(pollInterval)
|
|
130
|
-
}, 30000)
|
|
131
|
-
|
|
132
|
-
return () => {
|
|
133
|
-
clearInterval(pollInterval)
|
|
134
|
-
clearTimeout(timeout)
|
|
135
|
-
}
|
|
136
|
-
}, [testRun.id, testRun.status, testRun.reports.length])
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div className="mb-8">
|
|
140
|
-
<div className="flex items-start justify-between gap-4">
|
|
141
|
-
<div className="flex-1">
|
|
142
|
-
<PageHeader>Test Run Details</PageHeader>
|
|
143
|
-
<HeaderSubtitle>View test run execution details and live logs</HeaderSubtitle>
|
|
144
|
-
</div>
|
|
145
|
-
<ViewReportButton testRunStatus={testRun.status} reports={testRun.reports} className="mt-2" />
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react'
|
|
4
|
+
import { getTestRunByIdAction } from '@/actions/test-run/test-run-actions'
|
|
5
|
+
import PageHeader from '@/components/typography/page-header'
|
|
6
|
+
import HeaderSubtitle from '@/components/typography/page-header-subtitle'
|
|
7
|
+
import { ViewReportButton } from '@/components/test-run/view-report-button'
|
|
8
|
+
import { TestRun, TestRunTestCase, Tag, Environment, TestRunStatus, Report } from '@prisma/client'
|
|
9
|
+
|
|
10
|
+
interface TestRunHeaderProps {
|
|
11
|
+
initialTestRun: TestRun & {
|
|
12
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
13
|
+
tags: Tag[]
|
|
14
|
+
environment: Environment
|
|
15
|
+
reports: Report[]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function TestRunHeader({ initialTestRun }: TestRunHeaderProps) {
|
|
20
|
+
const [testRun, setTestRun] = useState(initialTestRun)
|
|
21
|
+
|
|
22
|
+
// Poll for status updates while test run is running or queued
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
// Only poll if test run is not completed/cancelled
|
|
25
|
+
if (testRun.status === TestRunStatus.COMPLETED || testRun.status === TestRunStatus.CANCELLED) {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const pollInterval = setInterval(async () => {
|
|
30
|
+
try {
|
|
31
|
+
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
32
|
+
if (error || !updatedTestRun) {
|
|
33
|
+
console.error('Error polling test run status:', error)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const typedTestRun = updatedTestRun as TestRun & {
|
|
38
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
39
|
+
tags: Tag[]
|
|
40
|
+
environment: Environment
|
|
41
|
+
reports: Report[]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Update state with latest test run data
|
|
45
|
+
setTestRun(typedTestRun)
|
|
46
|
+
|
|
47
|
+
// Stop polling if test run is completed or cancelled
|
|
48
|
+
if (typedTestRun.status === TestRunStatus.COMPLETED || typedTestRun.status === TestRunStatus.CANCELLED) {
|
|
49
|
+
clearInterval(pollInterval)
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Error polling test run status:', error)
|
|
53
|
+
}
|
|
54
|
+
}, 2000) // Poll every 2 seconds
|
|
55
|
+
|
|
56
|
+
return () => clearInterval(pollInterval)
|
|
57
|
+
}, [testRun.id, testRun.status])
|
|
58
|
+
|
|
59
|
+
// Listen for SSE exit events from LogViewer as a backup signal
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const handleTestRunExit = (event: CustomEvent<{ testRunId: string }>) => {
|
|
62
|
+
// Only handle events for this test run
|
|
63
|
+
if (event.detail.testRunId === testRun.runId) {
|
|
64
|
+
// Trigger a status refresh
|
|
65
|
+
getTestRunByIdAction(testRun.id)
|
|
66
|
+
.then(response => {
|
|
67
|
+
if (response.data && !response.error) {
|
|
68
|
+
const typedTestRun = response.data as TestRun & {
|
|
69
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
70
|
+
tags: Tag[]
|
|
71
|
+
environment: Environment
|
|
72
|
+
reports: Report[]
|
|
73
|
+
}
|
|
74
|
+
setTestRun(typedTestRun)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.catch(error => {
|
|
78
|
+
console.error('Error refreshing test run status after exit event:', error)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Listen for custom event dispatched by LogViewer
|
|
84
|
+
window.addEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
85
|
+
|
|
86
|
+
return () => {
|
|
87
|
+
window.removeEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
88
|
+
}
|
|
89
|
+
}, [testRun.id, testRun.runId])
|
|
90
|
+
|
|
91
|
+
// Poll for report updates after test run completes
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
// Only poll if test run is completed (not cancelled) but no report exists yet
|
|
94
|
+
// Cancelled runs won't generate reports, so we don't poll for them
|
|
95
|
+
const shouldPoll = testRun.status === TestRunStatus.COMPLETED && testRun.reports.length === 0
|
|
96
|
+
|
|
97
|
+
if (!shouldPoll) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Poll for reports (they might be created asynchronously after test run completes)
|
|
102
|
+
const pollInterval = setInterval(async () => {
|
|
103
|
+
try {
|
|
104
|
+
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
105
|
+
if (error || !updatedTestRun) {
|
|
106
|
+
console.error('Error polling for report:', error)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const typedTestRun = updatedTestRun as TestRun & {
|
|
111
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
112
|
+
tags: Tag[]
|
|
113
|
+
environment: Environment
|
|
114
|
+
reports: Report[]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Update if reports are now available
|
|
118
|
+
if (typedTestRun.reports.length > 0) {
|
|
119
|
+
setTestRun(typedTestRun)
|
|
120
|
+
clearInterval(pollInterval)
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('Error polling for report:', error)
|
|
124
|
+
}
|
|
125
|
+
}, 2000) // Poll every 2 seconds
|
|
126
|
+
|
|
127
|
+
// Stop polling after 30 seconds to avoid infinite polling
|
|
128
|
+
const timeout = setTimeout(() => {
|
|
129
|
+
clearInterval(pollInterval)
|
|
130
|
+
}, 30000)
|
|
131
|
+
|
|
132
|
+
return () => {
|
|
133
|
+
clearInterval(pollInterval)
|
|
134
|
+
clearTimeout(timeout)
|
|
135
|
+
}
|
|
136
|
+
}, [testRun.id, testRun.status, testRun.reports.length])
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div className="mb-8">
|
|
140
|
+
<div className="flex items-start justify-between gap-4">
|
|
141
|
+
<div className="flex-1">
|
|
142
|
+
<PageHeader>Test Run Details</PageHeader>
|
|
143
|
+
<HeaderSubtitle>View test run execution details and live logs</HeaderSubtitle>
|
|
144
|
+
</div>
|
|
145
|
+
<ViewReportButton testRunStatus={testRun.status} reports={testRun.reports} className="mt-2" />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { TestRunStatus, Report } from '@prisma/client'
|
|
4
|
-
import { Button } from '@/components/ui/button'
|
|
5
|
-
import { FileText, LoaderCircle, XCircle } from 'lucide-react'
|
|
6
|
-
import { AnimatePresence, motion } from 'motion/react'
|
|
7
|
-
import Link from 'next/link'
|
|
8
|
-
|
|
9
|
-
interface ViewReportButtonProps {
|
|
10
|
-
testRunStatus: TestRunStatus
|
|
11
|
-
reports: Report[]
|
|
12
|
-
className?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function ViewReportButton({ testRunStatus, reports, className }: ViewReportButtonProps) {
|
|
16
|
-
// Button should only be visible when test run is completed/cancelled AND a report exists
|
|
17
|
-
const shouldShowReportButton =
|
|
18
|
-
(testRunStatus === TestRunStatus.COMPLETED || testRunStatus === TestRunStatus.CANCELLED) && reports.length > 0
|
|
19
|
-
|
|
20
|
-
// Show cancelled status if test run is cancelled and no report exists
|
|
21
|
-
if (testRunStatus === TestRunStatus.CANCELLED && reports.length === 0) {
|
|
22
|
-
return (
|
|
23
|
-
<AnimatePresence mode="wait">
|
|
24
|
-
<motion.div
|
|
25
|
-
initial={{ opacity: 0, y: -10 }}
|
|
26
|
-
animate={{ opacity: 1, y: 0 }}
|
|
27
|
-
exit={{ opacity: 0, y: -10 }}
|
|
28
|
-
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
29
|
-
>
|
|
30
|
-
<Button variant="outline" size="sm" className={className} disabled>
|
|
31
|
-
<motion.div
|
|
32
|
-
initial={{ opacity: 0, scale: 0.9 }}
|
|
33
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
34
|
-
transition={{ duration: 0.2, delay: 0.1 }}
|
|
35
|
-
className="flex items-center gap-2"
|
|
36
|
-
>
|
|
37
|
-
<XCircle className="h-4 w-4" />
|
|
38
|
-
Report Not Available
|
|
39
|
-
</motion.div>
|
|
40
|
-
</Button>
|
|
41
|
-
</motion.div>
|
|
42
|
-
</AnimatePresence>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Show generating report message only for completed (not cancelled) runs without reports
|
|
47
|
-
if (testRunStatus === TestRunStatus.COMPLETED && reports.length === 0) {
|
|
48
|
-
return (
|
|
49
|
-
<AnimatePresence mode="wait">
|
|
50
|
-
<motion.div
|
|
51
|
-
initial={{ opacity: 0, y: -10 }}
|
|
52
|
-
animate={{ opacity: 1, y: 0 }}
|
|
53
|
-
exit={{ opacity: 0, y: -10 }}
|
|
54
|
-
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
55
|
-
>
|
|
56
|
-
<Button variant="outline" size="sm" className={className}>
|
|
57
|
-
<motion.div
|
|
58
|
-
initial={{ opacity: 0, scale: 0.9 }}
|
|
59
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
60
|
-
transition={{ duration: 0.2, delay: 0.1 }}
|
|
61
|
-
className="flex items-center gap-2"
|
|
62
|
-
>
|
|
63
|
-
<LoaderCircle className="h-4 w-4 animate-spin" />
|
|
64
|
-
Generating Report...
|
|
65
|
-
</motion.div>
|
|
66
|
-
</Button>
|
|
67
|
-
</motion.div>
|
|
68
|
-
</AnimatePresence>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (!shouldShowReportButton) {
|
|
73
|
-
return null
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const reportId = reports[0].id
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<AnimatePresence mode="wait">
|
|
80
|
-
<motion.div
|
|
81
|
-
initial={{ opacity: 0, y: -10 }}
|
|
82
|
-
animate={{ opacity: 1, y: 0 }}
|
|
83
|
-
exit={{ opacity: 0, y: -10 }}
|
|
84
|
-
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
85
|
-
>
|
|
86
|
-
<Link href={`/reports/${reportId}`}>
|
|
87
|
-
<Button variant="outline" size="sm" className={className}>
|
|
88
|
-
<motion.div
|
|
89
|
-
initial={{ opacity: 0, scale: 0.9 }}
|
|
90
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
91
|
-
transition={{ duration: 0.2, delay: 0.1 }}
|
|
92
|
-
className="flex items-center gap-2"
|
|
93
|
-
>
|
|
94
|
-
<FileText className="h-4 w-4" />
|
|
95
|
-
View Report
|
|
96
|
-
</motion.div>
|
|
97
|
-
</Button>
|
|
98
|
-
</Link>
|
|
99
|
-
</motion.div>
|
|
100
|
-
</AnimatePresence>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { TestRunStatus, Report } from '@prisma/client'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { FileText, LoaderCircle, XCircle } from 'lucide-react'
|
|
6
|
+
import { AnimatePresence, motion } from 'motion/react'
|
|
7
|
+
import Link from 'next/link'
|
|
8
|
+
|
|
9
|
+
interface ViewReportButtonProps {
|
|
10
|
+
testRunStatus: TestRunStatus
|
|
11
|
+
reports: Report[]
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ViewReportButton({ testRunStatus, reports, className }: ViewReportButtonProps) {
|
|
16
|
+
// Button should only be visible when test run is completed/cancelled AND a report exists
|
|
17
|
+
const shouldShowReportButton =
|
|
18
|
+
(testRunStatus === TestRunStatus.COMPLETED || testRunStatus === TestRunStatus.CANCELLED) && reports.length > 0
|
|
19
|
+
|
|
20
|
+
// Show cancelled status if test run is cancelled and no report exists
|
|
21
|
+
if (testRunStatus === TestRunStatus.CANCELLED && reports.length === 0) {
|
|
22
|
+
return (
|
|
23
|
+
<AnimatePresence mode="wait">
|
|
24
|
+
<motion.div
|
|
25
|
+
initial={{ opacity: 0, y: -10 }}
|
|
26
|
+
animate={{ opacity: 1, y: 0 }}
|
|
27
|
+
exit={{ opacity: 0, y: -10 }}
|
|
28
|
+
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
29
|
+
>
|
|
30
|
+
<Button variant="outline" size="sm" className={className} disabled>
|
|
31
|
+
<motion.div
|
|
32
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
33
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
34
|
+
transition={{ duration: 0.2, delay: 0.1 }}
|
|
35
|
+
className="flex items-center gap-2"
|
|
36
|
+
>
|
|
37
|
+
<XCircle className="h-4 w-4" />
|
|
38
|
+
Report Not Available
|
|
39
|
+
</motion.div>
|
|
40
|
+
</Button>
|
|
41
|
+
</motion.div>
|
|
42
|
+
</AnimatePresence>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Show generating report message only for completed (not cancelled) runs without reports
|
|
47
|
+
if (testRunStatus === TestRunStatus.COMPLETED && reports.length === 0) {
|
|
48
|
+
return (
|
|
49
|
+
<AnimatePresence mode="wait">
|
|
50
|
+
<motion.div
|
|
51
|
+
initial={{ opacity: 0, y: -10 }}
|
|
52
|
+
animate={{ opacity: 1, y: 0 }}
|
|
53
|
+
exit={{ opacity: 0, y: -10 }}
|
|
54
|
+
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
55
|
+
>
|
|
56
|
+
<Button variant="outline" size="sm" className={className}>
|
|
57
|
+
<motion.div
|
|
58
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
59
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
60
|
+
transition={{ duration: 0.2, delay: 0.1 }}
|
|
61
|
+
className="flex items-center gap-2"
|
|
62
|
+
>
|
|
63
|
+
<LoaderCircle className="h-4 w-4 animate-spin" />
|
|
64
|
+
Generating Report...
|
|
65
|
+
</motion.div>
|
|
66
|
+
</Button>
|
|
67
|
+
</motion.div>
|
|
68
|
+
</AnimatePresence>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!shouldShowReportButton) {
|
|
73
|
+
return null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const reportId = reports[0].id
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<AnimatePresence mode="wait">
|
|
80
|
+
<motion.div
|
|
81
|
+
initial={{ opacity: 0, y: -10 }}
|
|
82
|
+
animate={{ opacity: 1, y: 0 }}
|
|
83
|
+
exit={{ opacity: 0, y: -10 }}
|
|
84
|
+
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
85
|
+
>
|
|
86
|
+
<Link href={`/reports/${reportId}`}>
|
|
87
|
+
<Button variant="outline" size="sm" className={className}>
|
|
88
|
+
<motion.div
|
|
89
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
90
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
91
|
+
transition={{ duration: 0.2, delay: 0.1 }}
|
|
92
|
+
className="flex items-center gap-2"
|
|
93
|
+
>
|
|
94
|
+
<FileText className="h-4 w-4" />
|
|
95
|
+
View Report
|
|
96
|
+
</motion.div>
|
|
97
|
+
</Button>
|
|
98
|
+
</Link>
|
|
99
|
+
</motion.div>
|
|
100
|
+
</AnimatePresence>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { Moon, Sun } from 'lucide-react'
|
|
5
|
-
import { useTheme } from 'next-themes'
|
|
6
|
-
|
|
7
|
-
import { Button } from '@/components/ui/button'
|
|
8
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
|
|
9
|
-
import { cn } from '@/lib/utils'
|
|
10
|
-
|
|
11
|
-
export function ModeToggle() {
|
|
12
|
-
const { setTheme, theme } = useTheme()
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<DropdownMenu>
|
|
16
|
-
<DropdownMenuTrigger asChild className="fixed right-4 top-4">
|
|
17
|
-
<Button variant="outline" size="icon">
|
|
18
|
-
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
19
|
-
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
20
|
-
<span className="sr-only">Toggle theme</span>
|
|
21
|
-
</Button>
|
|
22
|
-
</DropdownMenuTrigger>
|
|
23
|
-
<DropdownMenuContent align="end">
|
|
24
|
-
<DropdownMenuItem
|
|
25
|
-
onClick={() => setTheme('light')}
|
|
26
|
-
className={cn(
|
|
27
|
-
'active:bg-accent active:text-accent-foreground',
|
|
28
|
-
theme === 'light' && 'bg-accent text-accent-foreground',
|
|
29
|
-
)}
|
|
30
|
-
>
|
|
31
|
-
Light
|
|
32
|
-
</DropdownMenuItem>
|
|
33
|
-
<DropdownMenuItem
|
|
34
|
-
onClick={() => setTheme('dark')}
|
|
35
|
-
className={cn(
|
|
36
|
-
'active:bg-accent active:text-accent-foreground',
|
|
37
|
-
theme === 'dark' && 'bg-accent text-accent-foreground',
|
|
38
|
-
)}
|
|
39
|
-
>
|
|
40
|
-
Dark
|
|
41
|
-
</DropdownMenuItem>
|
|
42
|
-
<DropdownMenuItem
|
|
43
|
-
onClick={() => setTheme('system')}
|
|
44
|
-
className={cn(
|
|
45
|
-
'active:bg-accent active:text-accent-foreground',
|
|
46
|
-
theme === 'system' && 'bg-accent text-accent-foreground',
|
|
47
|
-
)}
|
|
48
|
-
>
|
|
49
|
-
System
|
|
50
|
-
</DropdownMenuItem>
|
|
51
|
-
</DropdownMenuContent>
|
|
52
|
-
</DropdownMenu>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Moon, Sun } from 'lucide-react'
|
|
5
|
+
import { useTheme } from 'next-themes'
|
|
6
|
+
|
|
7
|
+
import { Button } from '@/components/ui/button'
|
|
8
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
|
|
9
|
+
import { cn } from '@/lib/utils'
|
|
10
|
+
|
|
11
|
+
export function ModeToggle() {
|
|
12
|
+
const { setTheme, theme } = useTheme()
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<DropdownMenu>
|
|
16
|
+
<DropdownMenuTrigger asChild className="fixed right-4 top-4">
|
|
17
|
+
<Button variant="outline" size="icon">
|
|
18
|
+
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
19
|
+
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
20
|
+
<span className="sr-only">Toggle theme</span>
|
|
21
|
+
</Button>
|
|
22
|
+
</DropdownMenuTrigger>
|
|
23
|
+
<DropdownMenuContent align="end">
|
|
24
|
+
<DropdownMenuItem
|
|
25
|
+
onClick={() => setTheme('light')}
|
|
26
|
+
className={cn(
|
|
27
|
+
'active:bg-accent active:text-accent-foreground',
|
|
28
|
+
theme === 'light' && 'bg-accent text-accent-foreground',
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
Light
|
|
32
|
+
</DropdownMenuItem>
|
|
33
|
+
<DropdownMenuItem
|
|
34
|
+
onClick={() => setTheme('dark')}
|
|
35
|
+
className={cn(
|
|
36
|
+
'active:bg-accent active:text-accent-foreground',
|
|
37
|
+
theme === 'dark' && 'bg-accent text-accent-foreground',
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
Dark
|
|
41
|
+
</DropdownMenuItem>
|
|
42
|
+
<DropdownMenuItem
|
|
43
|
+
onClick={() => setTheme('system')}
|
|
44
|
+
className={cn(
|
|
45
|
+
'active:bg-accent active:text-accent-foreground',
|
|
46
|
+
theme === 'system' && 'bg-accent text-accent-foreground',
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
System
|
|
50
|
+
</DropdownMenuItem>
|
|
51
|
+
</DropdownMenuContent>
|
|
52
|
+
</DropdownMenu>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
5
|
-
|
|
6
|
-
export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) {
|
|
7
|
-
return <NextThemesProvider defaultTheme="system" attribute="class" enableSystem={false} {...props}>{children}</NextThemesProvider>
|
|
8
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
5
|
+
|
|
6
|
+
export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) {
|
|
7
|
+
return <NextThemesProvider defaultTheme="system" attribute="class" enableSystem={false} {...props}>{children}</NextThemesProvider>
|
|
8
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
const HeaderSubtitle = ({ children }: { children: React.ReactNode }) => {
|
|
4
|
-
return <div className="text-sm font-medium text-muted-foreground">{children}</div>
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export default HeaderSubtitle
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
const HeaderSubtitle = ({ children }: { children: React.ReactNode }) => {
|
|
4
|
+
return <div className="text-sm font-medium text-muted-foreground">{children}</div>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default HeaderSubtitle
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { cn } from '@/lib/utils'
|
|
2
|
-
|
|
3
|
-
const PageHeader = ({ className, children }: { className?: string; children: React.ReactNode }) => {
|
|
4
|
-
return <div className={cn('text-4xl font-bold text-primary', className)}>{children}</div>
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export default PageHeader
|
|
1
|
+
import { cn } from '@/lib/utils'
|
|
2
|
+
|
|
3
|
+
const PageHeader = ({ className, children }: { className?: string; children: React.ReactNode }) => {
|
|
4
|
+
return <div className={cn('text-4xl font-bold text-primary', className)}>{children}</div>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default PageHeader
|