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,547 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
|
|
3
|
+
import prisma from '@/config/db-config'
|
|
4
|
+
import { locatorSchema } from '@/constants/form-opts/locator-form-opts'
|
|
5
|
+
import { ActionResponse } from '@/types/form/actionHandler'
|
|
6
|
+
import { revalidatePath } from 'next/cache'
|
|
7
|
+
import { z } from 'zod'
|
|
8
|
+
import { createOrUpdateLocatorGroupFile, getLocatorGroupFilePath } from '@/lib/locator-group-file-utils'
|
|
9
|
+
import { promises as fs } from 'fs'
|
|
10
|
+
import path from 'path'
|
|
11
|
+
import { glob } from 'glob'
|
|
12
|
+
import { buildModuleHierarchy } from '@/lib/module-hierarchy-builder'
|
|
13
|
+
|
|
14
|
+
// Helper function to update locator group JSON file when locators change
|
|
15
|
+
async function updateLocatorGroupFile(locatorGroupId: string | null): Promise<void> {
|
|
16
|
+
if (!locatorGroupId) return
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await createOrUpdateLocatorGroupFile(locatorGroupId)
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('Error updating locator group file:', error)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getAllLocatorsAction(): Promise<ActionResponse> {
|
|
26
|
+
try {
|
|
27
|
+
const locators = await prisma.locator.findMany({
|
|
28
|
+
include: {
|
|
29
|
+
locatorGroup: {
|
|
30
|
+
select: {
|
|
31
|
+
name: true,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
conflicts: {
|
|
35
|
+
where: {
|
|
36
|
+
resolved: false,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
return {
|
|
42
|
+
status: 200,
|
|
43
|
+
data: locators,
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return {
|
|
47
|
+
status: 500,
|
|
48
|
+
error: `Server error occurred: ${error}`,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function deleteLocatorAction(ids: string[]): Promise<ActionResponse> {
|
|
54
|
+
try {
|
|
55
|
+
// Get locator group IDs before deletion to update files
|
|
56
|
+
const locatorsToDelete = await prisma.locator.findMany({
|
|
57
|
+
where: { id: { in: ids } },
|
|
58
|
+
select: { locatorGroupId: true },
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const locatorGroupIds = [...new Set(locatorsToDelete.map(l => l.locatorGroupId).filter(Boolean))]
|
|
62
|
+
|
|
63
|
+
const locator = await prisma.locator.deleteMany({
|
|
64
|
+
where: { id: { in: ids } },
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Update JSON files for affected locator groups in parallel
|
|
68
|
+
await Promise.all(locatorGroupIds.filter(Boolean).map(groupId => updateLocatorGroupFile(groupId)))
|
|
69
|
+
|
|
70
|
+
revalidatePath('/locators')
|
|
71
|
+
return {
|
|
72
|
+
status: 200,
|
|
73
|
+
data: locator,
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return {
|
|
77
|
+
status: 500,
|
|
78
|
+
error: `Server error occurred: ${error}`,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function createLocatorAction(
|
|
84
|
+
_prev: unknown,
|
|
85
|
+
value: z.infer<typeof locatorSchema>,
|
|
86
|
+
): Promise<ActionResponse> {
|
|
87
|
+
try {
|
|
88
|
+
locatorSchema.parse(value)
|
|
89
|
+
|
|
90
|
+
const newLocator = await prisma.locator.create({
|
|
91
|
+
data: {
|
|
92
|
+
name: value.name,
|
|
93
|
+
value: value.value,
|
|
94
|
+
locatorGroupId: value.locatorGroupId,
|
|
95
|
+
},
|
|
96
|
+
include: {
|
|
97
|
+
locatorGroup: {
|
|
98
|
+
select: {
|
|
99
|
+
name: true,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Update the locator group JSON file
|
|
106
|
+
if (value.locatorGroupId) {
|
|
107
|
+
await updateLocatorGroupFile(value.locatorGroupId)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
revalidatePath('/locators')
|
|
111
|
+
return {
|
|
112
|
+
status: 200,
|
|
113
|
+
data: newLocator,
|
|
114
|
+
message: 'Locator created successfully',
|
|
115
|
+
}
|
|
116
|
+
} catch (e) {
|
|
117
|
+
return {
|
|
118
|
+
status: 500,
|
|
119
|
+
error: `Server error occurred: ${e}`,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function updateLocatorAction(
|
|
125
|
+
_prev: unknown,
|
|
126
|
+
value: z.infer<typeof locatorSchema>,
|
|
127
|
+
id?: string,
|
|
128
|
+
): Promise<ActionResponse> {
|
|
129
|
+
try {
|
|
130
|
+
// Get the current locator to check if locatorGroupId changed
|
|
131
|
+
const currentLocator = await prisma.locator.findUnique({
|
|
132
|
+
where: { id },
|
|
133
|
+
select: { locatorGroupId: true },
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const updatedLocator = await prisma.locator.update({
|
|
137
|
+
where: { id },
|
|
138
|
+
data: {
|
|
139
|
+
name: value.name,
|
|
140
|
+
value: value.value,
|
|
141
|
+
locatorGroupId: value.locatorGroupId,
|
|
142
|
+
},
|
|
143
|
+
include: {
|
|
144
|
+
locatorGroup: {
|
|
145
|
+
select: {
|
|
146
|
+
name: true,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// Update JSON files for affected locator groups
|
|
153
|
+
const groupsToUpdate = new Set<string>()
|
|
154
|
+
|
|
155
|
+
if (currentLocator?.locatorGroupId !== value.locatorGroupId) {
|
|
156
|
+
// Group changed - update both old and new groups
|
|
157
|
+
if (currentLocator?.locatorGroupId) {
|
|
158
|
+
groupsToUpdate.add(currentLocator.locatorGroupId)
|
|
159
|
+
}
|
|
160
|
+
if (value.locatorGroupId) {
|
|
161
|
+
groupsToUpdate.add(value.locatorGroupId)
|
|
162
|
+
}
|
|
163
|
+
} else if (value.locatorGroupId) {
|
|
164
|
+
// Same group - just update the current group
|
|
165
|
+
groupsToUpdate.add(value.locatorGroupId)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Update all affected groups in parallel
|
|
169
|
+
await Promise.all(Array.from(groupsToUpdate).map(groupId => updateLocatorGroupFile(groupId)))
|
|
170
|
+
|
|
171
|
+
revalidatePath('/locators')
|
|
172
|
+
return {
|
|
173
|
+
status: 200,
|
|
174
|
+
data: updatedLocator,
|
|
175
|
+
message: 'Locator updated successfully',
|
|
176
|
+
}
|
|
177
|
+
} catch (e) {
|
|
178
|
+
return {
|
|
179
|
+
status: 500,
|
|
180
|
+
error: `Server error occurred: ${e}`,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export async function getLocatorByIdAction(id: string): Promise<ActionResponse> {
|
|
186
|
+
try {
|
|
187
|
+
const locator = await prisma.locator.findUnique({
|
|
188
|
+
where: { id },
|
|
189
|
+
include: {
|
|
190
|
+
locatorGroup: {
|
|
191
|
+
select: {
|
|
192
|
+
name: true,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
})
|
|
197
|
+
return {
|
|
198
|
+
status: 200,
|
|
199
|
+
data: locator,
|
|
200
|
+
}
|
|
201
|
+
} catch (e) {
|
|
202
|
+
return {
|
|
203
|
+
status: 500,
|
|
204
|
+
error: `Server error occurred: ${e}`,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function getUngroupedLocatorsAction(): Promise<ActionResponse> {
|
|
210
|
+
try {
|
|
211
|
+
const locators = await prisma.locator.findMany({
|
|
212
|
+
where: {
|
|
213
|
+
locatorGroupId: null,
|
|
214
|
+
},
|
|
215
|
+
select: {
|
|
216
|
+
id: true,
|
|
217
|
+
name: true,
|
|
218
|
+
value: true,
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
return {
|
|
222
|
+
status: 200,
|
|
223
|
+
data: locators,
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
return {
|
|
227
|
+
status: 500,
|
|
228
|
+
error: `Server error occurred: ${error}`,
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Extracts module path from locator file path
|
|
235
|
+
*/
|
|
236
|
+
function extractModulePathFromLocatorFile(filePath: string): string {
|
|
237
|
+
const testsDir = path.join(process.cwd(), 'src', 'tests')
|
|
238
|
+
const relativePath = path.relative(testsDir, filePath)
|
|
239
|
+
const pathParts = relativePath.split(/[/\\]/).filter(p => p && p !== 'locators')
|
|
240
|
+
const moduleParts = pathParts.slice(0, -1) // Remove filename
|
|
241
|
+
return moduleParts.length > 0 ? '/' + moduleParts.join('/') : '/'
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Extracts locator group name from file path
|
|
246
|
+
* The group name is just the filename without extension
|
|
247
|
+
*/
|
|
248
|
+
function extractLocatorGroupName(filePath: string): string {
|
|
249
|
+
const fileName = path.basename(filePath, '.json')
|
|
250
|
+
return fileName
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Detects and creates conflict resolution entries for locators
|
|
255
|
+
*/
|
|
256
|
+
async function detectAndCreateConflicts(
|
|
257
|
+
locatorId: string,
|
|
258
|
+
locatorName: string,
|
|
259
|
+
locatorValue: string,
|
|
260
|
+
locatorGroupId: string,
|
|
261
|
+
): Promise<number> {
|
|
262
|
+
let conflictCount = 0
|
|
263
|
+
|
|
264
|
+
// Find existing locators in the same group
|
|
265
|
+
const existingLocators = await prisma.locator.findMany({
|
|
266
|
+
where: {
|
|
267
|
+
locatorGroupId,
|
|
268
|
+
id: { not: locatorId },
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
for (const existingLocator of existingLocators) {
|
|
273
|
+
// Check for duplicate name conflict
|
|
274
|
+
if (existingLocator.name === locatorName) {
|
|
275
|
+
// Check if conflict already exists for this locator
|
|
276
|
+
const existingConflict = await prisma.conflictResolution.findFirst({
|
|
277
|
+
where: {
|
|
278
|
+
entityType: 'LOCATOR',
|
|
279
|
+
entityId: locatorId,
|
|
280
|
+
conflictType: 'DUPLICATE_NAME',
|
|
281
|
+
conflictingEntityId: existingLocator.id,
|
|
282
|
+
resolved: false,
|
|
283
|
+
},
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
if (!existingConflict) {
|
|
287
|
+
// Create conflict for both locators
|
|
288
|
+
await prisma.conflictResolution.create({
|
|
289
|
+
data: {
|
|
290
|
+
entityType: 'LOCATOR',
|
|
291
|
+
entityId: locatorId,
|
|
292
|
+
conflictType: 'DUPLICATE_NAME',
|
|
293
|
+
conflictingEntityId: existingLocator.id,
|
|
294
|
+
resolved: false,
|
|
295
|
+
},
|
|
296
|
+
})
|
|
297
|
+
await prisma.conflictResolution.create({
|
|
298
|
+
data: {
|
|
299
|
+
entityType: 'LOCATOR',
|
|
300
|
+
entityId: existingLocator.id,
|
|
301
|
+
conflictType: 'DUPLICATE_NAME',
|
|
302
|
+
conflictingEntityId: locatorId,
|
|
303
|
+
resolved: false,
|
|
304
|
+
},
|
|
305
|
+
})
|
|
306
|
+
conflictCount++
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Check for duplicate value conflict (different name)
|
|
310
|
+
else if (existingLocator.value === locatorValue && existingLocator.name !== locatorName) {
|
|
311
|
+
// Check if conflict already exists for this locator
|
|
312
|
+
const existingConflict = await prisma.conflictResolution.findFirst({
|
|
313
|
+
where: {
|
|
314
|
+
entityType: 'LOCATOR',
|
|
315
|
+
entityId: locatorId,
|
|
316
|
+
conflictType: 'DUPLICATE_VALUE',
|
|
317
|
+
conflictingEntityId: existingLocator.id,
|
|
318
|
+
resolved: false,
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
if (!existingConflict) {
|
|
323
|
+
// Create conflict for both locators
|
|
324
|
+
await prisma.conflictResolution.create({
|
|
325
|
+
data: {
|
|
326
|
+
entityType: 'LOCATOR',
|
|
327
|
+
entityId: locatorId,
|
|
328
|
+
conflictType: 'DUPLICATE_VALUE',
|
|
329
|
+
conflictingEntityId: existingLocator.id,
|
|
330
|
+
resolved: false,
|
|
331
|
+
},
|
|
332
|
+
})
|
|
333
|
+
await prisma.conflictResolution.create({
|
|
334
|
+
data: {
|
|
335
|
+
entityType: 'LOCATOR',
|
|
336
|
+
entityId: existingLocator.id,
|
|
337
|
+
conflictType: 'DUPLICATE_VALUE',
|
|
338
|
+
conflictingEntityId: locatorId,
|
|
339
|
+
resolved: false,
|
|
340
|
+
},
|
|
341
|
+
})
|
|
342
|
+
conflictCount++
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return conflictCount
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Syncs locators from JSON files to database
|
|
352
|
+
*/
|
|
353
|
+
export async function syncLocatorsFromFilesAction(): Promise<ActionResponse> {
|
|
354
|
+
try {
|
|
355
|
+
// Use relative pattern with forward slashes for cross-platform compatibility
|
|
356
|
+
// glob library requires forward slashes in patterns on all platforms
|
|
357
|
+
const pattern = 'src/tests/locators/**/*.json'
|
|
358
|
+
const relativeFiles = await glob(pattern, {
|
|
359
|
+
cwd: process.cwd(),
|
|
360
|
+
})
|
|
361
|
+
// Resolve to absolute paths for file operations
|
|
362
|
+
const files = relativeFiles.map(file => path.resolve(process.cwd(), file))
|
|
363
|
+
|
|
364
|
+
let synced = 0
|
|
365
|
+
let totalConflicts = 0
|
|
366
|
+
const errors: string[] = []
|
|
367
|
+
const affectedLocatorGroupIds = new Set<string>()
|
|
368
|
+
|
|
369
|
+
for (const filePath of files) {
|
|
370
|
+
try {
|
|
371
|
+
// Read locator file
|
|
372
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
373
|
+
const locators = JSON.parse(content) as Record<string, string>
|
|
374
|
+
|
|
375
|
+
// Extract module path and group name
|
|
376
|
+
const modulePath = extractModulePathFromLocatorFile(filePath)
|
|
377
|
+
const moduleId = await buildModuleHierarchy(modulePath)
|
|
378
|
+
const groupName = extractLocatorGroupName(filePath)
|
|
379
|
+
|
|
380
|
+
// Find or create locator group
|
|
381
|
+
let locatorGroup = await prisma.locatorGroup.findFirst({
|
|
382
|
+
where: {
|
|
383
|
+
name: groupName,
|
|
384
|
+
moduleId: moduleId,
|
|
385
|
+
},
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
if (!locatorGroup) {
|
|
389
|
+
locatorGroup = await prisma.locatorGroup.create({
|
|
390
|
+
data: {
|
|
391
|
+
name: groupName,
|
|
392
|
+
route: `/${groupName}`,
|
|
393
|
+
moduleId: moduleId,
|
|
394
|
+
},
|
|
395
|
+
})
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Track this locator group as affected
|
|
399
|
+
affectedLocatorGroupIds.add(locatorGroup.id)
|
|
400
|
+
|
|
401
|
+
// Sync locators FROM FILE TO DATABASE
|
|
402
|
+
for (const [locatorName, locatorValue] of Object.entries(locators)) {
|
|
403
|
+
// Check if locator already exists
|
|
404
|
+
const existingLocator = await prisma.locator.findFirst({
|
|
405
|
+
where: {
|
|
406
|
+
name: locatorName,
|
|
407
|
+
locatorGroupId: locatorGroup.id,
|
|
408
|
+
},
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
let locatorId: string
|
|
412
|
+
|
|
413
|
+
if (existingLocator) {
|
|
414
|
+
// Update existing locator value if different (file takes precedence)
|
|
415
|
+
if (existingLocator.value !== locatorValue) {
|
|
416
|
+
await prisma.locator.update({
|
|
417
|
+
where: { id: existingLocator.id },
|
|
418
|
+
data: { value: locatorValue },
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
locatorId = existingLocator.id
|
|
422
|
+
} else {
|
|
423
|
+
// Create new locator from file
|
|
424
|
+
const newLocator = await prisma.locator.create({
|
|
425
|
+
data: {
|
|
426
|
+
name: locatorName,
|
|
427
|
+
value: locatorValue,
|
|
428
|
+
locatorGroupId: locatorGroup.id,
|
|
429
|
+
},
|
|
430
|
+
})
|
|
431
|
+
locatorId = newLocator.id
|
|
432
|
+
synced++
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Detect and create conflicts
|
|
436
|
+
const conflictCount = await detectAndCreateConflicts(locatorId, locatorName, locatorValue, locatorGroup.id)
|
|
437
|
+
totalConflicts += conflictCount
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Sync locators FROM DATABASE TO FILE (bidirectional sync)
|
|
441
|
+
// Get all locators from database for this group
|
|
442
|
+
const dbLocators = await prisma.locator.findMany({
|
|
443
|
+
where: { locatorGroupId: locatorGroup.id },
|
|
444
|
+
select: { name: true, value: true },
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
// Merge: file values take precedence, but add DB locators that aren't in file
|
|
448
|
+
const mergedLocators: Record<string, string> = { ...locators }
|
|
449
|
+
for (const dbLocator of dbLocators) {
|
|
450
|
+
// Only add if not already in file (file values take precedence)
|
|
451
|
+
if (!(dbLocator.name in mergedLocators)) {
|
|
452
|
+
mergedLocators[dbLocator.name] = dbLocator.value
|
|
453
|
+
synced++
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Write merged content back to file
|
|
458
|
+
await fs.writeFile(filePath, JSON.stringify(mergedLocators, null, 2) + '\n', 'utf-8')
|
|
459
|
+
} catch (error) {
|
|
460
|
+
const errorMessage = `Error syncing locator file ${filePath}: ${error}`
|
|
461
|
+
console.error(errorMessage)
|
|
462
|
+
errors.push(errorMessage)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Handle locator groups that exist in DB but don't have files yet
|
|
467
|
+
// Create files for these groups with their DB locators
|
|
468
|
+
try {
|
|
469
|
+
const allLocatorGroups = await prisma.locatorGroup.findMany({
|
|
470
|
+
include: {
|
|
471
|
+
locators: {
|
|
472
|
+
select: { name: true, value: true },
|
|
473
|
+
},
|
|
474
|
+
module: true,
|
|
475
|
+
},
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
for (const locatorGroup of allLocatorGroups) {
|
|
479
|
+
// Skip if we already processed this group (it has a file)
|
|
480
|
+
if (affectedLocatorGroupIds.has(locatorGroup.id)) {
|
|
481
|
+
continue
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
try {
|
|
485
|
+
// Get the file path for this locator group
|
|
486
|
+
const relativeFilePath = await getLocatorGroupFilePath(locatorGroup.id)
|
|
487
|
+
if (!relativeFilePath) {
|
|
488
|
+
// If we can't determine the path, skip this group
|
|
489
|
+
continue
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const fullPath = path.join(process.cwd(), relativeFilePath)
|
|
493
|
+
|
|
494
|
+
// Check if file exists
|
|
495
|
+
try {
|
|
496
|
+
await fs.access(fullPath)
|
|
497
|
+
// File exists, merge DB locators into it
|
|
498
|
+
const fileContent = await fs.readFile(fullPath, 'utf-8')
|
|
499
|
+
const fileLocators = JSON.parse(fileContent) as Record<string, string>
|
|
500
|
+
|
|
501
|
+
// Merge: file values take precedence, but add DB locators that aren't in file
|
|
502
|
+
const mergedLocators: Record<string, string> = { ...fileLocators }
|
|
503
|
+
for (const dbLocator of locatorGroup.locators) {
|
|
504
|
+
if (!(dbLocator.name in mergedLocators)) {
|
|
505
|
+
mergedLocators[dbLocator.name] = dbLocator.value
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
await fs.writeFile(fullPath, JSON.stringify(mergedLocators, null, 2) + '\n', 'utf-8')
|
|
510
|
+
} catch {
|
|
511
|
+
// File doesn't exist, create it with DB locators
|
|
512
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true })
|
|
513
|
+
const dbLocators: Record<string, string> = Object.fromEntries(
|
|
514
|
+
locatorGroup.locators.map(loc => [loc.name, loc.value]),
|
|
515
|
+
)
|
|
516
|
+
await fs.writeFile(fullPath, JSON.stringify(dbLocators, null, 2) + '\n', 'utf-8')
|
|
517
|
+
}
|
|
518
|
+
} catch (error) {
|
|
519
|
+
const errorMessage = `Error syncing locator group ${locatorGroup.id} to file: ${error}`
|
|
520
|
+
console.error(errorMessage)
|
|
521
|
+
errors.push(errorMessage)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} catch (error) {
|
|
525
|
+
const errorMessage = `Error syncing database locators to files: ${error}`
|
|
526
|
+
console.error(errorMessage)
|
|
527
|
+
errors.push(errorMessage)
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
revalidatePath('/locators')
|
|
531
|
+
|
|
532
|
+
return {
|
|
533
|
+
status: 200,
|
|
534
|
+
data: {
|
|
535
|
+
synced,
|
|
536
|
+
conflicts: totalConflicts,
|
|
537
|
+
errors,
|
|
538
|
+
},
|
|
539
|
+
message: `Synced ${synced} locators, ${totalConflicts} conflicts detected`,
|
|
540
|
+
}
|
|
541
|
+
} catch (error) {
|
|
542
|
+
return {
|
|
543
|
+
status: 500,
|
|
544
|
+
error: `Server error occurred: ${error}`,
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|