create-appraise 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/package.json +63 -0
- package/templates/default/.env.example +2 -0
- package/templates/default/README.md +51 -0
- package/templates/default/appraise.config.json +4 -0
- package/templates/default/components.json +24 -0
- package/templates/default/eslint.config.mjs +15 -0
- package/templates/default/next-env.d.ts +6 -0
- package/templates/default/next.config.ts +7 -0
- package/templates/default/package-lock.json +14321 -0
- package/templates/default/package.json +124 -0
- package/templates/default/postcss.config.mjs +8 -0
- package/templates/default/prisma/migrations/20251026202316_migrate_back_to_sqlite/migration.sql +257 -0
- package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -0
- package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -0
- package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -0
- package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -0
- package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -0
- package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -0
- package/templates/default/prisma/migrations/20251130190737_add_trace_path_to_test_run_test_case/migration.sql +2 -0
- package/templates/default/prisma/migrations/20251213074835_add_log_path_to_test_run/migration.sql +2 -0
- package/templates/default/prisma/migrations/20251213183952_add_name_property_for_the_test_run_entities/migration.sql +30 -0
- package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -0
- package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -0
- package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -0
- package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -0
- package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -0
- package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -0
- package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -0
- package/templates/default/prisma/migrations/migration_lock.toml +3 -0
- package/templates/default/prisma/schema.prisma +554 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/file.svg +1 -0
- package/templates/default/public/globe.svg +1 -0
- package/templates/default/public/next.svg +1 -0
- package/templates/default/public/vercel.svg +1 -0
- package/templates/default/public/window.svg +1 -0
- package/templates/default/scripts/regenerate-features.ts +94 -0
- package/templates/default/scripts/setup-env.ts +19 -0
- package/templates/default/scripts/sync-all.ts +341 -0
- package/templates/default/scripts/sync-environments.ts +323 -0
- package/templates/default/scripts/sync-locator-groups.ts +413 -0
- package/templates/default/scripts/sync-locators.ts +402 -0
- package/templates/default/scripts/sync-modules.ts +349 -0
- package/templates/default/scripts/sync-tags.ts +292 -0
- package/templates/default/scripts/sync-template-step-groups.ts +399 -0
- package/templates/default/scripts/sync-template-steps.ts +806 -0
- package/templates/default/scripts/sync-test-cases.ts +905 -0
- package/templates/default/scripts/sync-test-suites.ts +411 -0
- package/templates/default/src/actions/conflict/conflict.action.ts +33 -0
- package/templates/default/src/actions/dashboard/dashboard-actions.ts +241 -0
- package/templates/default/src/actions/environments/environment-actions.ts +205 -0
- package/templates/default/src/actions/locator/locator-actions.ts +547 -0
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -0
- package/templates/default/src/actions/modules/module-actions.ts +133 -0
- package/templates/default/src/actions/reports/report-actions.ts +614 -0
- package/templates/default/src/actions/review/review-actions.ts +147 -0
- package/templates/default/src/actions/tags/tag-actions.ts +104 -0
- package/templates/default/src/actions/template-step/template-step-actions.ts +332 -0
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -0
- package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -0
- package/templates/default/src/actions/test-case/test-case-actions.ts +419 -0
- package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -0
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -0
- package/templates/default/src/actions/user/user-actions.ts +13 -0
- package/templates/default/src/app/(base)/environments/create/page.tsx +28 -0
- package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -0
- package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -0
- package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -0
- package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/environments/page.tsx +59 -0
- package/templates/default/src/app/(base)/layout.tsx +10 -0
- package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -0
- package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/locator-groups/page.tsx +61 -0
- package/templates/default/src/app/(base)/locators/create/page.tsx +38 -0
- package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -0
- package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +90 -0
- package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -0
- package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -0
- package/templates/default/src/app/(base)/locators/page.tsx +65 -0
- package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -0
- package/templates/default/src/app/(base)/modules/create/page.tsx +34 -0
- package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/modules/module-form.tsx +126 -0
- package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -0
- package/templates/default/src/app/(base)/modules/module-table.tsx +24 -0
- package/templates/default/src/app/(base)/modules/page.tsx +59 -0
- package/templates/default/src/app/(base)/reports/[id]/page.tsx +517 -0
- package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -0
- package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -0
- package/templates/default/src/app/(base)/reports/overview-chart.tsx +46 -0
- package/templates/default/src/app/(base)/reports/page.tsx +98 -0
- package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -0
- package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -0
- package/templates/default/src/app/(base)/reports/report-table.tsx +72 -0
- package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +131 -0
- package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -0
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -0
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -0
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -0
- package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -0
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -0
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -0
- package/templates/default/src/app/(base)/reports/view-logs-button.tsx +60 -0
- package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -0
- package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -0
- package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -0
- package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -0
- package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -0
- package/templates/default/src/app/(base)/tags/create/page.tsx +39 -0
- package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -0
- package/templates/default/src/app/(base)/tags/page.tsx +58 -0
- package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -0
- package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -0
- package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -0
- package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -0
- package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -0
- package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -0
- package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -0
- package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -0
- package/templates/default/src/app/(base)/template-steps/page.tsx +59 -0
- package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -0
- package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -0
- package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -0
- package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -0
- package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -0
- package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -0
- package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -0
- package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -0
- package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -0
- package/templates/default/src/app/(base)/test-cases/page.tsx +60 -0
- package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -0
- package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -0
- package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +90 -0
- package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -0
- package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -0
- package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -0
- package/templates/default/src/app/(base)/test-runs/page.tsx +60 -0
- package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +512 -0
- package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -0
- package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -0
- package/templates/default/src/app/(base)/test-suites/create/page.tsx +45 -0
- package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -0
- package/templates/default/src/app/(base)/test-suites/page.tsx +82 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -0
- package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -0
- package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +13 -0
- package/templates/default/src/app/(dashboard-components)/data-card.tsx +27 -0
- package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +57 -0
- package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -0
- package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +45 -0
- package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +133 -0
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -0
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -0
- package/templates/default/src/app/favicon.ico +0 -0
- package/templates/default/src/app/globals.css +147 -0
- package/templates/default/src/app/layout.tsx +171 -0
- package/templates/default/src/app/page.tsx +64 -0
- package/templates/default/src/assets/icons/empty-tube.tsx +23 -0
- package/templates/default/src/assets/icons/tube-plus.tsx +29 -0
- package/templates/default/src/components/base-node.tsx +21 -0
- package/templates/default/src/components/chart/pie-chart.tsx +73 -0
- package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -0
- package/templates/default/src/components/data-state/empty-state.tsx +40 -0
- package/templates/default/src/components/data-visualization/info-card.tsx +70 -0
- package/templates/default/src/components/data-visualization/info-grid.tsx +22 -0
- package/templates/default/src/components/devtools/providers.tsx +13 -0
- package/templates/default/src/components/diagram/button-edge.tsx +54 -0
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -0
- package/templates/default/src/components/diagram/edit-header-option.tsx +36 -0
- package/templates/default/src/components/diagram/flow-diagram.tsx +470 -0
- package/templates/default/src/components/diagram/node-form.tsx +262 -0
- package/templates/default/src/components/diagram/options-header-node.tsx +57 -0
- package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -0
- package/templates/default/src/components/form/error-message.tsx +7 -0
- package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -0
- package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -0
- package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -0
- package/templates/default/src/components/logo.tsx +15 -0
- package/templates/default/src/components/navigation/command-badge.tsx +34 -0
- package/templates/default/src/components/navigation/command-chain-input.tsx +51 -0
- package/templates/default/src/components/navigation/entity-search-command.tsx +116 -0
- package/templates/default/src/components/navigation/nav-card.tsx +31 -0
- package/templates/default/src/components/navigation/nav-command.tsx +508 -0
- package/templates/default/src/components/navigation/nav-link.tsx +60 -0
- package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -0
- package/templates/default/src/components/node-header.tsx +159 -0
- package/templates/default/src/components/reports/test-case-logs-modal.tsx +253 -0
- package/templates/default/src/components/table/table-actions.tsx +172 -0
- package/templates/default/src/components/test-run/download-logs-button.tsx +99 -0
- package/templates/default/src/components/test-run/log-viewer.tsx +445 -0
- package/templates/default/src/components/test-run/test-run-details.tsx +611 -0
- package/templates/default/src/components/test-run/test-run-header.tsx +149 -0
- package/templates/default/src/components/test-run/view-report-button.tsx +102 -0
- package/templates/default/src/components/theme/mode-toggle.tsx +54 -0
- package/templates/default/src/components/theme/theme-provider.tsx +8 -0
- package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -0
- package/templates/default/src/components/typography/page-header.tsx +7 -0
- package/templates/default/src/components/ui/alert-dialog.tsx +106 -0
- package/templates/default/src/components/ui/alert.tsx +43 -0
- package/templates/default/src/components/ui/avatar.tsx +40 -0
- package/templates/default/src/components/ui/badge.tsx +29 -0
- package/templates/default/src/components/ui/button.tsx +47 -0
- package/templates/default/src/components/ui/calendar.tsx +158 -0
- package/templates/default/src/components/ui/card.tsx +43 -0
- package/templates/default/src/components/ui/chart.tsx +369 -0
- package/templates/default/src/components/ui/checkbox.tsx +28 -0
- package/templates/default/src/components/ui/command.tsx +135 -0
- package/templates/default/src/components/ui/data-table-column-header.tsx +61 -0
- package/templates/default/src/components/ui/data-table-pagination.tsx +87 -0
- package/templates/default/src/components/ui/data-table-view-options.tsx +50 -0
- package/templates/default/src/components/ui/data-table.tsx +267 -0
- package/templates/default/src/components/ui/dialog.tsx +97 -0
- package/templates/default/src/components/ui/dropdown-menu.tsx +182 -0
- package/templates/default/src/components/ui/empty.tsx +104 -0
- package/templates/default/src/components/ui/input.tsx +22 -0
- package/templates/default/src/components/ui/kbd.tsx +28 -0
- package/templates/default/src/components/ui/label.tsx +19 -0
- package/templates/default/src/components/ui/loading.tsx +12 -0
- package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -0
- package/templates/default/src/components/ui/multi-select.tsx +142 -0
- package/templates/default/src/components/ui/navigation-menu.tsx +120 -0
- package/templates/default/src/components/ui/popover.tsx +33 -0
- package/templates/default/src/components/ui/progress.tsx +25 -0
- package/templates/default/src/components/ui/radio-group.tsx +44 -0
- package/templates/default/src/components/ui/scroll-area.tsx +40 -0
- package/templates/default/src/components/ui/select.tsx +144 -0
- package/templates/default/src/components/ui/separator.tsx +22 -0
- package/templates/default/src/components/ui/skeleton.tsx +7 -0
- package/templates/default/src/components/ui/table.tsx +76 -0
- package/templates/default/src/components/ui/tabs.tsx +55 -0
- package/templates/default/src/components/ui/textarea.tsx +21 -0
- package/templates/default/src/components/ui/toast.tsx +113 -0
- package/templates/default/src/components/ui/toaster.tsx +26 -0
- package/templates/default/src/components/ui/tooltip.tsx +32 -0
- package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -0
- package/templates/default/src/config/db-config.ts +10 -0
- package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -0
- package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -0
- package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -0
- package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -0
- package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -0
- package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -0
- package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -0
- package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -0
- package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -0
- package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -0
- package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -0
- package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -0
- package/templates/default/src/constants/form-opts/test-run-form-opts.ts +31 -0
- package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -0
- package/templates/default/src/hooks/use-toast.ts +187 -0
- package/templates/default/src/lib/bidirectional-sync.ts +432 -0
- package/templates/default/src/lib/database-sync.ts +531 -0
- package/templates/default/src/lib/environment-file-utils.ts +221 -0
- package/templates/default/src/lib/feature-file-generator.ts +411 -0
- package/templates/default/src/lib/gherkin-parser.ts +259 -0
- package/templates/default/src/lib/locator-group-file-utils.ts +370 -0
- package/templates/default/src/lib/metrics/metric-calculator.ts +613 -0
- package/templates/default/src/lib/module-hierarchy-builder.ts +205 -0
- package/templates/default/src/lib/path-helpers/module-path.ts +71 -0
- package/templates/default/src/lib/test-case-utils.ts +6 -0
- package/templates/default/src/lib/test-run/log-formatter.ts +83 -0
- package/templates/default/src/lib/test-run/process-manager.ts +191 -0
- package/templates/default/src/lib/test-run/report-parser.ts +316 -0
- package/templates/default/src/lib/test-run/test-run-executor.ts +144 -0
- package/templates/default/src/lib/test-run/winston-logger.ts +95 -0
- package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -0
- package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -0
- package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -0
- package/templates/default/src/lib/utils/node-param-validation.ts +81 -0
- package/templates/default/src/lib/utils/template-step-file-generator.ts +167 -0
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -0
- package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -0
- package/templates/default/src/lib/utils.ts +31 -0
- package/templates/default/src/tests/config/environments/environments.json +14 -0
- package/templates/default/src/tests/config/executor/world.ts +41 -0
- package/templates/default/src/tests/executor.ts +80 -0
- package/templates/default/src/tests/hooks/hooks.ts +99 -0
- package/templates/default/src/tests/mapping/locator-map.json +1 -0
- package/templates/default/src/tests/steps/actions/click.step.ts +62 -0
- package/templates/default/src/tests/steps/actions/hover.step.ts +31 -0
- package/templates/default/src/tests/steps/actions/input.step.ts +149 -0
- package/templates/default/src/tests/steps/actions/navigation.step.ts +72 -0
- package/templates/default/src/tests/steps/actions/random_data.step.ts +146 -0
- package/templates/default/src/tests/steps/actions/store.step.ts +90 -0
- package/templates/default/src/tests/steps/actions/wait.step.ts +107 -0
- package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -0
- package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +23 -0
- package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -0
- package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -0
- package/templates/default/src/tests/support/parameter-types.ts +12 -0
- package/templates/default/src/tests/utils/cache.util.ts +260 -0
- package/templates/default/src/tests/utils/cli.util.ts +177 -0
- package/templates/default/src/tests/utils/environment.util.ts +65 -0
- package/templates/default/src/tests/utils/locator.util.ts +248 -0
- package/templates/default/src/tests/utils/random-data.util.ts +45 -0
- package/templates/default/src/tests/utils/spawner.util.ts +617 -0
- package/templates/default/src/types/diagram/diagram.ts +34 -0
- package/templates/default/src/types/diagram/template-step.ts +11 -0
- package/templates/default/src/types/executor/browser.type.ts +1 -0
- package/templates/default/src/types/form/actionHandler.ts +6 -0
- package/templates/default/src/types/locator/locator.type.ts +11 -0
- package/templates/default/src/types/step/step.type.ts +1 -0
- package/templates/default/src/types/table/data-table.ts +6 -0
- package/templates/default/tailwind.config.ts +62 -0
- package/templates/default/tsconfig.json +28 -0
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
import { buttonVariants } from '@/components/ui/button'
|
|
8
|
+
|
|
9
|
+
const AlertDialog = AlertDialogPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
|
14
|
+
|
|
15
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<AlertDialogPrimitive.Overlay
|
|
20
|
+
className={cn(
|
|
21
|
+
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
ref={ref}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
|
29
|
+
|
|
30
|
+
const AlertDialogContent = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<AlertDialogPortal>
|
|
35
|
+
<AlertDialogOverlay />
|
|
36
|
+
<AlertDialogPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
|
40
|
+
className,
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
</AlertDialogPortal>
|
|
45
|
+
))
|
|
46
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
|
47
|
+
|
|
48
|
+
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
49
|
+
<div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
|
|
50
|
+
)
|
|
51
|
+
AlertDialogHeader.displayName = 'AlertDialogHeader'
|
|
52
|
+
|
|
53
|
+
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
54
|
+
<div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} />
|
|
55
|
+
)
|
|
56
|
+
AlertDialogFooter.displayName = 'AlertDialogFooter'
|
|
57
|
+
|
|
58
|
+
const AlertDialogTitle = React.forwardRef<
|
|
59
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
60
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
61
|
+
>(({ className, ...props }, ref) => (
|
|
62
|
+
<AlertDialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold', className)} {...props} />
|
|
63
|
+
))
|
|
64
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
|
65
|
+
|
|
66
|
+
const AlertDialogDescription = React.forwardRef<
|
|
67
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
68
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
69
|
+
>(({ className, ...props }, ref) => (
|
|
70
|
+
<AlertDialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
|
|
71
|
+
))
|
|
72
|
+
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
|
|
73
|
+
|
|
74
|
+
const AlertDialogAction = React.forwardRef<
|
|
75
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
76
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
77
|
+
>(({ className, ...props }, ref) => (
|
|
78
|
+
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
|
|
79
|
+
))
|
|
80
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
|
81
|
+
|
|
82
|
+
const AlertDialogCancel = React.forwardRef<
|
|
83
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
84
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
85
|
+
>(({ className, ...props }, ref) => (
|
|
86
|
+
<AlertDialogPrimitive.Cancel
|
|
87
|
+
ref={ref}
|
|
88
|
+
className={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className)}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
))
|
|
92
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
AlertDialog,
|
|
96
|
+
AlertDialogPortal,
|
|
97
|
+
AlertDialogOverlay,
|
|
98
|
+
AlertDialogTrigger,
|
|
99
|
+
AlertDialogContent,
|
|
100
|
+
AlertDialogHeader,
|
|
101
|
+
AlertDialogFooter,
|
|
102
|
+
AlertDialogTitle,
|
|
103
|
+
AlertDialogDescription,
|
|
104
|
+
AlertDialogAction,
|
|
105
|
+
AlertDialogCancel,
|
|
106
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-background text-foreground',
|
|
12
|
+
destructive: 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
variant: 'default',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const Alert = React.forwardRef<
|
|
22
|
+
HTMLDivElement,
|
|
23
|
+
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
|
24
|
+
>(({ className, variant, ...props }, ref) => (
|
|
25
|
+
<div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props} />
|
|
26
|
+
))
|
|
27
|
+
Alert.displayName = 'Alert'
|
|
28
|
+
|
|
29
|
+
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
30
|
+
({ className, ...props }, ref) => (
|
|
31
|
+
<h5 ref={ref} className={cn('mb-1 font-medium leading-none tracking-tight', className)} {...props} />
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
AlertTitle.displayName = 'AlertTitle'
|
|
35
|
+
|
|
36
|
+
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
37
|
+
({ className, ...props }, ref) => (
|
|
38
|
+
<div ref={ref} className={cn('text-sm [&_p]:leading-relaxed', className)} {...props} />
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
AlertDescription.displayName = 'AlertDescription'
|
|
42
|
+
|
|
43
|
+
export { Alert, AlertTitle, AlertDescription }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as AvatarPrimitive from '@radix-ui/react-avatar'
|
|
5
|
+
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
|
|
8
|
+
const Avatar = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof AvatarPrimitive.Root>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<AvatarPrimitive.Root
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
))
|
|
18
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName
|
|
19
|
+
|
|
20
|
+
const AvatarImage = React.forwardRef<
|
|
21
|
+
React.ElementRef<typeof AvatarPrimitive.Image>,
|
|
22
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<AvatarPrimitive.Image ref={ref} className={cn('aspect-square h-full w-full', className)} {...props} />
|
|
25
|
+
))
|
|
26
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
|
27
|
+
|
|
28
|
+
const AvatarFallback = React.forwardRef<
|
|
29
|
+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
|
30
|
+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
31
|
+
>(({ className, ...props }, ref) => (
|
|
32
|
+
<AvatarPrimitive.Fallback
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn('flex h-full w-full items-center justify-center rounded-full bg-muted', className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
))
|
|
38
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
|
39
|
+
|
|
40
|
+
export { Avatar, AvatarImage, AvatarFallback }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
12
|
+
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
13
|
+
destructive: 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
|
14
|
+
outline: 'text-foreground',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: 'default',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
|
|
24
|
+
|
|
25
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
26
|
+
return <div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot'
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
|
+
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
|
13
|
+
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
|
14
|
+
outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
|
15
|
+
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
|
16
|
+
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
17
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
default: 'h-9 px-4 py-2',
|
|
21
|
+
sm: 'h-8 rounded-md px-3 text-xs',
|
|
22
|
+
lg: 'h-10 rounded-md px-8',
|
|
23
|
+
icon: 'h-9 w-9',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
variant: 'default',
|
|
28
|
+
size: 'default',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export interface ButtonProps
|
|
34
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
35
|
+
VariantProps<typeof buttonVariants> {
|
|
36
|
+
asChild?: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
40
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
41
|
+
const Comp = asChild ? Slot : 'button'
|
|
42
|
+
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
Button.displayName = 'Button'
|
|
46
|
+
|
|
47
|
+
export { Button, buttonVariants }
|