@stacksjs/defaults 0.70.206 → 0.70.208
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/TODO.md +21 -0
- package/ai/AGENTS.md +79 -0
- package/ai/README.md +45 -0
- package/ai/claude/launch.json +12 -0
- package/ai/skills/stacks-actions/SKILL.md +128 -0
- package/ai/skills/stacks-ai/SKILL.md +276 -0
- package/ai/skills/stacks-alias/SKILL.md +94 -0
- package/ai/skills/stacks-analytics/SKILL.md +91 -0
- package/ai/skills/stacks-api/SKILL.md +738 -0
- package/ai/skills/stacks-arrays/SKILL.md +277 -0
- package/ai/skills/stacks-auth/SKILL.md +422 -0
- package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
- package/ai/skills/stacks-brandkit/SKILL.md +811 -0
- package/ai/skills/stacks-browse/SKILL.md +127 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
- package/ai/skills/stacks-browser/SKILL.md +145 -0
- package/ai/skills/stacks-buddy/SKILL.md +676 -0
- package/ai/skills/stacks-build/SKILL.md +163 -0
- package/ai/skills/stacks-cache/SKILL.md +125 -0
- package/ai/skills/stacks-calendar/SKILL.md +113 -0
- package/ai/skills/stacks-chat/SKILL.md +371 -0
- package/ai/skills/stacks-cli/SKILL.md +112 -0
- package/ai/skills/stacks-cloud/SKILL.md +192 -0
- package/ai/skills/stacks-cms/SKILL.md +217 -0
- package/ai/skills/stacks-collections/SKILL.md +82 -0
- package/ai/skills/stacks-commerce/SKILL.md +114 -0
- package/ai/skills/stacks-composables/SKILL.md +161 -0
- package/ai/skills/stacks-config/SKILL.md +144 -0
- package/ai/skills/stacks-configuration/SKILL.md +154 -0
- package/ai/skills/stacks-cron/SKILL.md +123 -0
- package/ai/skills/stacks-crosswind/SKILL.md +190 -0
- package/ai/skills/stacks-dashboard/SKILL.md +173 -0
- package/ai/skills/stacks-database/SKILL.md +286 -0
- package/ai/skills/stacks-datetime/SKILL.md +269 -0
- package/ai/skills/stacks-dependencies/SKILL.md +111 -0
- package/ai/skills/stacks-deploy/SKILL.md +102 -0
- package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
- package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
- package/ai/skills/stacks-design-output/SKILL.md +55 -0
- package/ai/skills/stacks-design-soft/SKILL.md +156 -0
- package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
- package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
- package/ai/skills/stacks-desktop/SKILL.md +78 -0
- package/ai/skills/stacks-development/SKILL.md +298 -0
- package/ai/skills/stacks-dns/SKILL.md +149 -0
- package/ai/skills/stacks-docs/SKILL.md +109 -0
- package/ai/skills/stacks-email/SKILL.md +236 -0
- package/ai/skills/stacks-enums/SKILL.md +100 -0
- package/ai/skills/stacks-env/SKILL.md +181 -0
- package/ai/skills/stacks-error-handling/SKILL.md +137 -0
- package/ai/skills/stacks-events/SKILL.md +228 -0
- package/ai/skills/stacks-faker/SKILL.md +158 -0
- package/ai/skills/stacks-git/SKILL.md +158 -0
- package/ai/skills/stacks-guard/SKILL.md +98 -0
- package/ai/skills/stacks-health/SKILL.md +75 -0
- package/ai/skills/stacks-http/SKILL.md +316 -0
- package/ai/skills/stacks-i18n/SKILL.md +198 -0
- package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
- package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
- package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
- package/ai/skills/stacks-investigate/SKILL.md +119 -0
- package/ai/skills/stacks-jobs/SKILL.md +136 -0
- package/ai/skills/stacks-lint/SKILL.md +184 -0
- package/ai/skills/stacks-listeners/SKILL.md +99 -0
- package/ai/skills/stacks-logging/SKILL.md +78 -0
- package/ai/skills/stacks-mail/SKILL.md +120 -0
- package/ai/skills/stacks-middleware/SKILL.md +249 -0
- package/ai/skills/stacks-migrations/SKILL.md +105 -0
- package/ai/skills/stacks-models/SKILL.md +267 -0
- package/ai/skills/stacks-new-feature/SKILL.md +206 -0
- package/ai/skills/stacks-notifications/SKILL.md +210 -0
- package/ai/skills/stacks-objects/SKILL.md +205 -0
- package/ai/skills/stacks-office-hours/SKILL.md +134 -0
- package/ai/skills/stacks-orm/SKILL.md +342 -0
- package/ai/skills/stacks-path/SKILL.md +118 -0
- package/ai/skills/stacks-payments/SKILL.md +373 -0
- package/ai/skills/stacks-plan-review/SKILL.md +152 -0
- package/ai/skills/stacks-plugins/SKILL.md +149 -0
- package/ai/skills/stacks-push/SKILL.md +376 -0
- package/ai/skills/stacks-query-builder/SKILL.md +128 -0
- package/ai/skills/stacks-queue/SKILL.md +559 -0
- package/ai/skills/stacks-realtime/SKILL.md +442 -0
- package/ai/skills/stacks-redesign/SKILL.md +182 -0
- package/ai/skills/stacks-registry/SKILL.md +58 -0
- package/ai/skills/stacks-repl/SKILL.md +80 -0
- package/ai/skills/stacks-retro/SKILL.md +122 -0
- package/ai/skills/stacks-review/SKILL.md +135 -0
- package/ai/skills/stacks-router/SKILL.md +231 -0
- package/ai/skills/stacks-routes/SKILL.md +105 -0
- package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
- package/ai/skills/stacks-scheduler/SKILL.md +363 -0
- package/ai/skills/stacks-search-engine/SKILL.md +112 -0
- package/ai/skills/stacks-security/SKILL.md +129 -0
- package/ai/skills/stacks-security-audit/SKILL.md +128 -0
- package/ai/skills/stacks-server/SKILL.md +458 -0
- package/ai/skills/stacks-shell/SKILL.md +62 -0
- package/ai/skills/stacks-slug/SKILL.md +87 -0
- package/ai/skills/stacks-sms/SKILL.md +385 -0
- package/ai/skills/stacks-socials/SKILL.md +303 -0
- package/ai/skills/stacks-storage/SKILL.md +576 -0
- package/ai/skills/stacks-strings/SKILL.md +416 -0
- package/ai/skills/stacks-stx/SKILL.md +176 -0
- package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
- package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
- package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
- package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
- package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
- package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
- package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
- package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
- package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
- package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
- package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
- package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
- package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
- package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
- package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
- package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
- package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
- package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
- package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
- package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
- package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
- package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
- package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
- package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
- package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
- package/ai/skills/stacks-testing/SKILL.md +129 -0
- package/ai/skills/stacks-tunnel/SKILL.md +125 -0
- package/ai/skills/stacks-types/SKILL.md +178 -0
- package/ai/skills/stacks-ui/SKILL.md +246 -0
- package/ai/skills/stacks-utils/SKILL.md +444 -0
- package/ai/skills/stacks-validation/SKILL.md +371 -0
- package/ai/skills/stacks-whois/SKILL.md +315 -0
- package/assets/world-map-data.ts +121 -0
- package/bootstrap.ts +114 -0
- package/docs/api-examples.md +46 -0
- package/docs/index.md +24 -0
- package/docs/markdown-examples.md +87 -0
- package/functions/analytics.ts +97 -0
- package/functions/api.ts +143 -0
- package/functions/auth.ts +208 -0
- package/functions/billing/payments.ts +149 -0
- package/functions/blog.ts +120 -0
- package/functions/cms/categorizables.ts +107 -0
- package/functions/cms/pages.ts +108 -0
- package/functions/cms/posts.ts +100 -0
- package/functions/cms/taggables.ts +102 -0
- package/functions/commerce/coupons.ts +128 -0
- package/functions/commerce/customers.ts +128 -0
- package/functions/commerce/gift-cards.ts +119 -0
- package/functions/commerce/orders.ts +112 -0
- package/functions/commerce/payments.ts +119 -0
- package/functions/commerce/products/categories.ts +123 -0
- package/functions/commerce/products/manufacturers.ts +123 -0
- package/functions/commerce/products/products.ts +123 -0
- package/functions/commerce/products/reviews.ts +123 -0
- package/functions/commerce/products/units.ts +123 -0
- package/functions/commerce/products/variants.ts +123 -0
- package/functions/commerce/shippings/delivery-routes.ts +123 -0
- package/functions/commerce/shippings/digital-deliveries.ts +119 -0
- package/functions/commerce/shippings/drivers.ts +123 -0
- package/functions/commerce/shippings/license-keys.ts +123 -0
- package/functions/commerce/shippings/shipping-methods.ts +123 -0
- package/functions/commerce/shippings/shipping-rates.ts +119 -0
- package/functions/commerce/shippings/shipping-zones.ts +119 -0
- package/functions/commerce/taxes.ts +119 -0
- package/functions/commerce/waitlist/products.ts +123 -0
- package/functions/commerce/waitlist/restaurants.ts +123 -0
- package/functions/craft.ts +107 -0
- package/functions/dashboard.ts +153 -0
- package/functions/inbox.ts +95 -0
- package/functions/jobs.ts +86 -0
- package/functions/monitoring/errors.ts +295 -0
- package/functions/queue.ts +111 -0
- package/functions/realtime/websockets.ts +96 -0
- package/functions/realtime.ts +52 -0
- package/functions/releases.ts +49 -0
- package/functions/search.ts +126 -0
- package/functions/toasts.ts +95 -0
- package/functions/uploads.ts +216 -0
- package/ide/.gitignore +4 -0
- package/ide/cursor/rules/auto-imports.mdc +574 -0
- package/ide/cursor/rules/code-style.mdc +12 -0
- package/ide/cursor/rules/documentation.mdc +9 -0
- package/ide/cursor/rules/error-handling-validation.mdc +11 -0
- package/ide/cursor/rules/key-conventions.mdc +11 -0
- package/ide/cursor/rules/project-structure.mdc +169 -0
- package/ide/cursor/rules/readme.mdc +318 -0
- package/ide/cursor/rules/syntax-formatting.mdc +9 -0
- package/ide/cursor/rules/testing.mdc +10 -0
- package/ide/cursor/rules/typescript.mdc +9 -0
- package/ide/cursor/rules/ui-styling.mdc +0 -0
- package/ide/dictionary.txt +397 -0
- package/ide/jetbrains/.fleet/settings.json +4 -0
- package/ide/jetbrains/.idea/.gitignore +5 -0
- package/ide/jetbrains/.idea/.name +1 -0
- package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
- package/ide/jetbrains/.idea/modules.xml +8 -0
- package/ide/jetbrains/.idea/stacks.iml +22 -0
- package/ide/jetbrains/.idea/vcs.xml +6 -0
- package/ide/jetbrains/.idea/webResources.xml +14 -0
- package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
- package/ide/jetbrains/installed.txt +4 -0
- package/ide/jetbrains/options/github-copilot.xml +5 -0
- package/ide/jetbrains/options/nodejs.xml +7 -0
- package/ide/jetbrains/options/templates.xml +124 -0
- package/ide/jetbrains/templates/JavaScript.xml +6 -0
- package/ide/jetbrains/templates/Stacks.xml +8 -0
- package/ide/vscode/.vscode/README.md +23 -0
- package/ide/vscode/.vscode/extensions.json +5 -0
- package/ide/vscode/.vscode/settings.json +176 -0
- package/ide/vscode/.vscode/stacks.code-snippets +181 -0
- package/ide/vscode/LICENSE.md +21 -0
- package/ide/vscode/README.md +36 -0
- package/ide/vscode/logo.png +0 -0
- package/ide/vscode/package.json +79 -0
- package/ide/zed/.zed/settings.json +139 -0
- package/lang/README.md +28 -0
- package/lang/de.yml +14 -0
- package/lang/en.yml +15 -0
- package/package.json +19 -3
- package/project/bootstrap +161 -0
- package/project/buddy +175 -0
- package/project/storage/framework/tsconfig.app.json +50 -0
- package/project/storage/framework/tsconfig.base.json +58 -0
- package/routes/core.ts +78 -0
- package/routes/dashboard-api.ts +233 -0
- package/routes/dashboard.ts +739 -0
- package/routes/email.ts +129 -0
- package/stores/[name].stx +16 -0
- package/stores/git.ts +71 -0
- package/stores/payment.ts +474 -0
- package/stores/queue.ts +43 -0
- package/stores/user.ts +29 -0
- package/stx-components-plugin.ts +25 -0
- package/styles/design-tokens.css +597 -0
- package/types/dashboard.ts +70 -0
- package/types/defaults.ts +438 -0
- package/vcs/github/CODE_OF_CONDUCT.md +83 -0
- package/vcs/github/CONTRIBUTING.md +187 -0
- package/vcs/github/EXPLANATIONS.md +41 -0
- package/vcs/github/FUNDING.yml +1 -0
- package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
- package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
- package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
- package/vcs/github/SECURITY.md +70 -0
- package/vcs/github/renovate.json +5 -0
- package/vcs/github/stale.yml +14 -0
- package/vcs/github/workflows/README.md +16 -0
- package/vcs/github/workflows/ci.yml +114 -0
- package/vcs/github/workflows/export-size.yml +25 -0
- package/vcs/github/workflows/labeler.yml +13 -0
- package/vcs/github/workflows/release.yml +219 -0
- package/views/[...all].stx +8 -0
- package/views/about.md +3 -0
- package/views/auth/login.stx +1 -0
- package/views/auth/signup.stx +85 -0
- package/views/dashboard/.discovered-models.json +542 -0
- package/views/dashboard/AUDIT.md +904 -0
- package/views/dashboard/[...all].stx +89 -0
- package/views/dashboard/access-tokens/index.stx +177 -0
- package/views/dashboard/actions/index.stx +129 -0
- package/views/dashboard/analytics/blog/index.stx +356 -0
- package/views/dashboard/analytics/browsers/index.stx +263 -0
- package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
- package/views/dashboard/analytics/commerce/web/index.stx +379 -0
- package/views/dashboard/analytics/countries/index.stx +289 -0
- package/views/dashboard/analytics/devices/index.stx +305 -0
- package/views/dashboard/analytics/events/index.stx +536 -0
- package/views/dashboard/analytics/index.stx +88 -0
- package/views/dashboard/analytics/marketing/index.stx +315 -0
- package/views/dashboard/analytics/pages/index.stx +271 -0
- package/views/dashboard/analytics/referrers/index.stx +319 -0
- package/views/dashboard/analytics/web/index.stx +356 -0
- package/views/dashboard/buddy/index.stx +198 -0
- package/views/dashboard/ci/index.stx +462 -0
- package/views/dashboard/cloud/index.stx +452 -0
- package/views/dashboard/commands/index.stx +295 -0
- package/views/dashboard/commerce/categories/index.stx +406 -0
- package/views/dashboard/commerce/coupons/index.stx +485 -0
- package/views/dashboard/commerce/customers/index.stx +410 -0
- package/views/dashboard/commerce/dashboard/index.stx +287 -0
- package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
- package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
- package/views/dashboard/commerce/delivery/drivers.stx +397 -0
- package/views/dashboard/commerce/delivery/index.stx +18 -0
- package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
- package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
- package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
- package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
- package/views/dashboard/commerce/delivery/tabs.ts +25 -0
- package/views/dashboard/commerce/gift-cards/index.stx +561 -0
- package/views/dashboard/commerce/manufacturers/index.stx +308 -0
- package/views/dashboard/commerce/orders/index.stx +247 -0
- package/views/dashboard/commerce/payments/index.stx +535 -0
- package/views/dashboard/commerce/pos/index.stx +653 -0
- package/views/dashboard/commerce/printers/devices/index.stx +273 -0
- package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
- package/views/dashboard/commerce/products/detail.stx +563 -0
- package/views/dashboard/commerce/products/index.stx +370 -0
- package/views/dashboard/commerce/reviews/index.stx +656 -0
- package/views/dashboard/commerce/reviews/index.ts +0 -0
- package/views/dashboard/commerce/taxes/index.stx +377 -0
- package/views/dashboard/commerce/units/index.stx +317 -0
- package/views/dashboard/commerce/variants/index.stx +319 -0
- package/views/dashboard/commerce/waitlist/products.stx +942 -0
- package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
- package/views/dashboard/components/index.stx +330 -0
- package/views/dashboard/composables/index.ts +19 -0
- package/views/dashboard/composables/useChart.ts +77 -0
- package/views/dashboard/composables/useNavigation.ts +99 -0
- package/views/dashboard/composables/useRole.ts +58 -0
- package/views/dashboard/composables/useTheme.ts +74 -0
- package/views/dashboard/content/authors/index.stx +171 -0
- package/views/dashboard/content/blog/index.stx +493 -0
- package/views/dashboard/content/categories/index.stx +169 -0
- package/views/dashboard/content/comments/index.stx +189 -0
- package/views/dashboard/content/dashboard.stx +383 -0
- package/views/dashboard/content/files/index.stx +706 -0
- package/views/dashboard/content/pages/index.stx +174 -0
- package/views/dashboard/content/posts/index.stx +269 -0
- package/views/dashboard/content/seo/index.stx +240 -0
- package/views/dashboard/content/tags/index.stx +167 -0
- package/views/dashboard/data/activity/index.stx +261 -0
- package/views/dashboard/data/dashboard/index.stx +116 -0
- package/views/dashboard/data/subscribers.stx +270 -0
- package/views/dashboard/data/teams.stx +275 -0
- package/views/dashboard/data/users.stx +279 -0
- package/views/dashboard/dependencies/index.stx +178 -0
- package/views/dashboard/deployments/[id].stx +234 -0
- package/views/dashboard/deployments/index.stx +9 -0
- package/views/dashboard/dns/index.stx +163 -0
- package/views/dashboard/environment/index.stx +283 -0
- package/views/dashboard/errors/index.stx +274 -0
- package/views/dashboard/forgot-password.stx +57 -0
- package/views/dashboard/functions/index.stx +159 -0
- package/views/dashboard/health/index.stx +248 -0
- package/views/dashboard/inbox/activity.stx +350 -0
- package/views/dashboard/inbox/index.stx +452 -0
- package/views/dashboard/inbox/settings.stx +290 -0
- package/views/dashboard/index.stx +252 -0
- package/views/dashboard/insights/index.stx +529 -0
- package/views/dashboard/jobs/[id].stx +430 -0
- package/views/dashboard/jobs/history.stx +222 -0
- package/views/dashboard/jobs/index.stx +214 -0
- package/views/dashboard/kanban/[id].stx +899 -0
- package/views/dashboard/kanban/index.stx +260 -0
- package/views/dashboard/layouts/default.stx +565 -0
- package/views/dashboard/layouts/guest.stx +10 -0
- package/views/dashboard/login.stx +48 -0
- package/views/dashboard/logs/index.stx +540 -0
- package/views/dashboard/mailboxes/index.stx +149 -0
- package/views/dashboard/management/permissions/index.stx +490 -0
- package/views/dashboard/marketing/campaigns/index.stx +604 -0
- package/views/dashboard/marketing/lists/index.stx +514 -0
- package/views/dashboard/marketing/reviews/index.stx +475 -0
- package/views/dashboard/marketing/social-posts/index.stx +560 -0
- package/views/dashboard/models/[model].stx +195 -0
- package/views/dashboard/models/index.stx +159 -0
- package/views/dashboard/monitoring/errors/index.stx +415 -0
- package/views/dashboard/notifications/dashboard.stx +383 -0
- package/views/dashboard/notifications/email.stx +336 -0
- package/views/dashboard/notifications/history.stx +373 -0
- package/views/dashboard/notifications/sms.stx +332 -0
- package/views/dashboard/packages/index.stx +195 -0
- package/views/dashboard/queries/[id].stx +381 -0
- package/views/dashboard/queries/history.stx +227 -0
- package/views/dashboard/queries/index.stx +335 -0
- package/views/dashboard/queries/slow.stx +318 -0
- package/views/dashboard/queue/index.stx +427 -0
- package/views/dashboard/realtime/index.stx +429 -0
- package/views/dashboard/register.stx +46 -0
- package/views/dashboard/releases/index.stx +389 -0
- package/views/dashboard/requests/index.stx +462 -0
- package/views/dashboard/serverless/index.stx +475 -0
- package/views/dashboard/servers/[id].stx +299 -0
- package/views/dashboard/servers/index.stx +483 -0
- package/views/dashboard/settings/billing.stx +50 -0
- package/views/dashboard/settings/index.stx +256 -0
- package/views/dashboard/settings/mail.stx +252 -0
- package/views/dashboard/stores/auth.ts +123 -0
- package/views/dashboard/stores/ci.ts +342 -0
- package/views/dashboard/stores/index.ts +129 -0
- package/views/dashboard/stores/kanban.ts +723 -0
- package/views/dashboard/stores/rbac.ts +350 -0
- package/views/dashboard/stx.config.ts +34 -0
- package/views/dashboard/teams/[id].stx +170 -0
- package/views/forum/category.stx +92 -0
- package/views/forum/index.stx +209 -0
- package/views/forum/new-topic.stx +113 -0
- package/views/forum/profile.stx +1 -0
- package/views/forum/topic.stx +143 -0
- package/views/hello-world/[name].stx +47 -0
- package/views/index.stx +21 -0
- package/views/system-tray/index.stx +147 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Error Tracking')
|
|
5
|
+
<div class="p-6 space-y-6">
|
|
6
|
+
|
|
7
|
+
<PageHeader title="Error Tracking" description="Monitor and manage application errors. Similar errors are grouped together." />
|
|
8
|
+
|
|
9
|
+
<div :show="hasStats" class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mb-6">
|
|
10
|
+
<StatsCard title="Total Errors" :value="totalErrorsLabel" icon="i-hugeicons-bug-01" iconBg="primary" />
|
|
11
|
+
<StatsCard title="Unresolved" :value="unresolvedLabel" icon="i-hugeicons-alert-02" iconBg="danger" />
|
|
12
|
+
<StatsCard title="Last 24 Hours" :value="last24hLabel" :trend="trendValue" trendLabel="vs previous period" icon="i-hugeicons-time-02" iconBg="warning" />
|
|
13
|
+
<StatsCard title="Resolved" :value="resolvedStatsLabel" icon="i-hugeicons-checkmark-circle-02" iconBg="success" />
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<Card>
|
|
17
|
+
<template #header>
|
|
18
|
+
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
19
|
+
<h2 class="font-semibold text-lg text-neutral-900 dark:text-white">Issues</h2>
|
|
20
|
+
<div class="flex flex-col gap-3 sm:flex-row">
|
|
21
|
+
<div class="w-full sm:w-64">
|
|
22
|
+
<Input :value="searchQuery" placeholder="Search errors..." size="sm">
|
|
23
|
+
<template #iconLeft>
|
|
24
|
+
<div class="h-4 w-4 i-hugeicons-search-01"></div>
|
|
25
|
+
</template>
|
|
26
|
+
</Input>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="w-full sm:w-40">
|
|
29
|
+
<Select :value="statusFilter" :options="statusOptions" placeholder="Status" size="sm" />
|
|
30
|
+
</div>
|
|
31
|
+
<div class="w-full sm:w-40">
|
|
32
|
+
<Select :value="typeFilter" :options="typeOptions" placeholder="Type" size="sm" />
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<Table :columns="columns" :data="paginatedErrors" rowKey="id" hoverable :emptyTitle="emptyTitle" :emptyDescription="emptyDescription" @sort="handleSort" @row-click="viewError">
|
|
39
|
+
<template #cell-type="{ value }">
|
|
40
|
+
<span class="inline-flex items-center px-2 py-0.5 font-medium text-neutral-700 text-xs dark:text-neutral-200 bg-neutral-100 dark:bg-neutral-700 rounded">{{ value }}</span>
|
|
41
|
+
</template>
|
|
42
|
+
<template #cell-message="{ value }">
|
|
43
|
+
<span class="line-clamp-1 text-neutral-700 dark:text-neutral-200">{{ value }}</span>
|
|
44
|
+
</template>
|
|
45
|
+
<template #cell-count="{ value }">
|
|
46
|
+
<span class="inline-flex items-center justify-center px-2 py-0.5 min-w-[2rem] font-semibold text-neutral-700 text-xs dark:text-neutral-200 bg-neutral-100 dark:bg-neutral-700 rounded-full">{{ value }}</span>
|
|
47
|
+
</template>
|
|
48
|
+
<template #cell-status="{ value }">
|
|
49
|
+
<Badge :variant="getStatusVariant(value)" size="sm">{{ value }}</Badge>
|
|
50
|
+
</template>
|
|
51
|
+
<template #cell-last_seen="{ value }">
|
|
52
|
+
<span class="text-neutral-500 text-sm dark:text-neutral-400">{{ formatRelativeTime(value) }}</span>
|
|
53
|
+
</template>
|
|
54
|
+
<template #actions="{ row }">
|
|
55
|
+
<div class="flex gap-1 items-center">
|
|
56
|
+
<Button :show="{{ row.status === 'unresolved' ? 'true' : 'false' }}" variant="ghost" size="sm" title="Resolve" @click.stop="handleResolveError(row)">
|
|
57
|
+
<div class="h-4 w-4 text-green-600 i-hugeicons-checkmark-circle-02"></div>
|
|
58
|
+
</Button>
|
|
59
|
+
<Button :show="{{ row.status === 'unresolved' ? 'true' : 'false' }}" variant="ghost" size="sm" title="Ignore" @click.stop="handleIgnoreError(row)">
|
|
60
|
+
<div class="h-4 w-4 text-amber-600 i-hugeicons-eye-off"></div>
|
|
61
|
+
</Button>
|
|
62
|
+
<Button :show="{{ row.status !== 'unresolved' ? 'true' : 'false' }}" variant="ghost" size="sm" title="Unresolve" @click.stop="handleUnresolveError(row)">
|
|
63
|
+
<div class="h-4 w-4 text-blue-600 i-hugeicons-refresh"></div>
|
|
64
|
+
</Button>
|
|
65
|
+
<Button variant="ghost" size="sm" title="Delete" @click.stop="openDeleteModal(row)">
|
|
66
|
+
<div class="h-4 w-4 text-red-600 i-hugeicons-delete-02"></div>
|
|
67
|
+
</Button>
|
|
68
|
+
</div>
|
|
69
|
+
</template>
|
|
70
|
+
</Table>
|
|
71
|
+
|
|
72
|
+
<template #footer>
|
|
73
|
+
<Pagination :value="currentPage" :totalPages="totalPages" :totalItems="totalFiltered" :itemsPerPage="itemsPerPage" showTotalItems />
|
|
74
|
+
</template>
|
|
75
|
+
</Card>
|
|
76
|
+
|
|
77
|
+
<Modal :value="isDetailModalOpen" :title="detailTitle" size="lg">
|
|
78
|
+
<div :show="hasSelectedError" class="space-y-6">
|
|
79
|
+
<div>
|
|
80
|
+
<h4 class="mb-2 font-medium text-neutral-500 text-sm dark:text-neutral-400">Message</h4>
|
|
81
|
+
<p class="p-3 text-neutral-900 dark:text-white bg-neutral-50 dark:bg-neutral-800 rounded-lg">{{ selectedMessage() }}</p>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div class="grid gap-4 grid-cols-3">
|
|
85
|
+
<div class="p-3 text-center bg-neutral-50 dark:bg-neutral-800 rounded-lg">
|
|
86
|
+
<div class="font-semibold text-2xl text-neutral-900 dark:text-white">{{ selectedCount() }}</div>
|
|
87
|
+
<div class="text-neutral-500 text-sm dark:text-neutral-400">Occurrences</div>
|
|
88
|
+
</div>
|
|
89
|
+
<div class="p-3 text-center bg-neutral-50 dark:bg-neutral-800 rounded-lg">
|
|
90
|
+
<div class="font-medium text-neutral-900 text-sm dark:text-white">{{ selectedFirstSeen() }}</div>
|
|
91
|
+
<div class="text-neutral-500 text-sm dark:text-neutral-400">First Seen</div>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="p-3 text-center bg-neutral-50 dark:bg-neutral-800 rounded-lg">
|
|
94
|
+
<div class="font-medium text-neutral-900 text-sm dark:text-white">{{ selectedLastSeen() }}</div>
|
|
95
|
+
<div class="text-neutral-500 text-sm dark:text-neutral-400">Last Seen</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div :show="hasStackTrace">
|
|
100
|
+
<h4 class="mb-2 font-medium text-neutral-500 text-sm dark:text-neutral-400">Stack Trace</h4>
|
|
101
|
+
<pre class="overflow-x-auto p-4 max-h-64 text-neutral-700 text-xs dark:text-neutral-300 bg-neutral-900 dark:bg-black rounded-lg">{{ selectedStackTrace() }}</pre>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="flex gap-2 items-center">
|
|
105
|
+
<span class="text-neutral-500 text-sm dark:text-neutral-400">Status:</span>
|
|
106
|
+
<Badge :variant="getStatusVariant(selectedStatus())">{{ selectedStatus() }}</Badge>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<template #footer="{ close }">
|
|
111
|
+
<div class="flex items-center justify-between w-full">
|
|
112
|
+
<div class="flex gap-2 items-center">
|
|
113
|
+
<Button :show="selectedIsUnresolved" variant="primary" size="sm" @click="resolveSelected()">
|
|
114
|
+
<template #iconLeft>
|
|
115
|
+
<div class="h-4 w-4 i-hugeicons-checkmark-circle-02"></div>
|
|
116
|
+
</template>
|
|
117
|
+
Resolve
|
|
118
|
+
</Button>
|
|
119
|
+
<Button :show="selectedIsUnresolved" variant="outline" size="sm" @click="ignoreSelected()">
|
|
120
|
+
<template #iconLeft>
|
|
121
|
+
<div class="h-4 w-4 i-hugeicons-eye-off"></div>
|
|
122
|
+
</template>
|
|
123
|
+
Ignore
|
|
124
|
+
</Button>
|
|
125
|
+
<Button :show="selectedIsResolvedOrIgnored" variant="outline" size="sm" @click="unresolveSelected()">
|
|
126
|
+
<template #iconLeft>
|
|
127
|
+
<div class="h-4 w-4 i-hugeicons-refresh"></div>
|
|
128
|
+
</template>
|
|
129
|
+
Unresolve
|
|
130
|
+
</Button>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="flex gap-2 items-center">
|
|
133
|
+
<Button variant="danger" size="sm" @click="deleteSelected()">
|
|
134
|
+
<template #iconLeft>
|
|
135
|
+
<div class="h-4 w-4 i-hugeicons-delete-02"></div>
|
|
136
|
+
</template>
|
|
137
|
+
Delete
|
|
138
|
+
</Button>
|
|
139
|
+
<Button variant="ghost" size="sm" @click="close">Close</Button>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</template>
|
|
143
|
+
</Modal>
|
|
144
|
+
|
|
145
|
+
<Modal :value="showDeleteModal" title="Delete Error Group" size="sm">
|
|
146
|
+
<div class="text-center">
|
|
147
|
+
<div class="flex items-center justify-center mb-4 mx-auto h-12 w-12 bg-red-100 dark:bg-red-900/30 rounded-full">
|
|
148
|
+
<div class="h-6 w-6 text-red-600 dark:text-red-400 i-hugeicons-alert-02"></div>
|
|
149
|
+
</div>
|
|
150
|
+
<p class="text-neutral-600 text-sm dark:text-neutral-300">
|
|
151
|
+
Are you sure you want to delete all <strong>{{ deleteCount() }}</strong> occurrences of this error? This action cannot be undone.
|
|
152
|
+
</p>
|
|
153
|
+
<p class="mt-2 font-medium text-neutral-900 text-sm dark:text-white">{{ deleteMessage() }}</p>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<template #footer>
|
|
157
|
+
<div class="flex gap-3 items-center justify-end w-full">
|
|
158
|
+
<Button variant="ghost" @click="closeDeleteModal()">Cancel</Button>
|
|
159
|
+
<Button variant="danger" @click="confirmDelete()">Delete All</Button>
|
|
160
|
+
</div>
|
|
161
|
+
</template>
|
|
162
|
+
</Modal>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<script client>
|
|
166
|
+
import { useErrors } from '../../../../functions/monitoring/errors'
|
|
167
|
+
|
|
168
|
+
interface ErrorGroup {
|
|
169
|
+
id?: string | number
|
|
170
|
+
type: string
|
|
171
|
+
message: string
|
|
172
|
+
count: number
|
|
173
|
+
status: 'unresolved' | 'resolved' | 'ignored'
|
|
174
|
+
first_seen: string
|
|
175
|
+
last_seen: string
|
|
176
|
+
stack_trace?: string
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const { groupedErrors, errorStats, fetchGroupedErrors, fetchErrorStats, resolveErrorGroup, ignoreErrorGroup, unresolveErrorGroup, deleteErrorGroup } = useErrors()
|
|
180
|
+
|
|
181
|
+
const searchQuery = state('')
|
|
182
|
+
const statusFilter = state<string | null>(null)
|
|
183
|
+
const typeFilter = state<string | null>(null)
|
|
184
|
+
const sortBy = state('last_seen')
|
|
185
|
+
const sortOrder = state<'asc' | 'desc'>('desc')
|
|
186
|
+
const currentPage = state(1)
|
|
187
|
+
const itemsPerPage = state(10)
|
|
188
|
+
|
|
189
|
+
const selectedError = state<ErrorGroup | null>(null)
|
|
190
|
+
const isDetailModalOpen = state(false)
|
|
191
|
+
const showDeleteModal = state(false)
|
|
192
|
+
const errorToDelete = state<ErrorGroup | null>(null)
|
|
193
|
+
|
|
194
|
+
const statusOptions = [
|
|
195
|
+
{ value: '', label: 'All Statuses' },
|
|
196
|
+
{ value: 'unresolved', label: 'Unresolved' },
|
|
197
|
+
{ value: 'resolved', label: 'Resolved' },
|
|
198
|
+
{ value: 'ignored', label: 'Ignored' },
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
const columns = [
|
|
202
|
+
{ key: 'type', label: 'Type', sortable: true },
|
|
203
|
+
{ key: 'message', label: 'Message', sortable: false },
|
|
204
|
+
{ key: 'count', label: 'Events', sortable: true, align: 'center' },
|
|
205
|
+
{ key: 'status', label: 'Status', sortable: false, align: 'center' },
|
|
206
|
+
{ key: 'last_seen', label: 'Last Seen', sortable: true, align: 'right' },
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
function errorList(): ErrorGroup[] {
|
|
210
|
+
return (groupedErrors.value as ErrorGroup[]) || []
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function statsValue(): { total?: number, unresolved?: number, last_24h?: number, resolved?: number, trend?: number } | null {
|
|
214
|
+
return (errorStats.value as { total?: number, unresolved?: number, last_24h?: number, resolved?: number, trend?: number } | null) || null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const hasStats = derived(() => statsValue() !== null)
|
|
218
|
+
const totalErrorsLabel = derived(() => String(statsValue()?.total ?? 0))
|
|
219
|
+
const unresolvedLabel = derived(() => String(statsValue()?.unresolved ?? 0))
|
|
220
|
+
const last24hLabel = derived(() => String(statsValue()?.last_24h ?? 0))
|
|
221
|
+
const resolvedStatsLabel = derived(() => String(statsValue()?.resolved ?? 0))
|
|
222
|
+
const trendValue = derived(() => statsValue()?.trend ?? 0)
|
|
223
|
+
|
|
224
|
+
const typeOptions = derived(() => {
|
|
225
|
+
const types = new Set(errorList().map(e => e.type))
|
|
226
|
+
return [
|
|
227
|
+
{ value: '', label: 'All Types' },
|
|
228
|
+
...Array.from(types).map(type => ({ value: type, label: type })),
|
|
229
|
+
]
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
const filteredErrors = derived(() => {
|
|
233
|
+
const list = errorList()
|
|
234
|
+
const q = searchQuery().toLowerCase()
|
|
235
|
+
const status = statusFilter()
|
|
236
|
+
const type = typeFilter()
|
|
237
|
+
const sb = sortBy()
|
|
238
|
+
const so = sortOrder()
|
|
239
|
+
return list
|
|
240
|
+
.filter((error) => {
|
|
241
|
+
const matchesSearch = !q
|
|
242
|
+
|| error.type.toLowerCase().includes(q)
|
|
243
|
+
|| error.message.toLowerCase().includes(q)
|
|
244
|
+
const matchesStatus = !status || error.status === status
|
|
245
|
+
const matchesType = !type || error.type === type
|
|
246
|
+
return matchesSearch && matchesStatus && matchesType
|
|
247
|
+
})
|
|
248
|
+
.sort((a, b) => {
|
|
249
|
+
let comparison = 0
|
|
250
|
+
if (sb === 'type')
|
|
251
|
+
comparison = a.type.localeCompare(b.type)
|
|
252
|
+
else if (sb === 'count')
|
|
253
|
+
comparison = a.count - b.count
|
|
254
|
+
else if (sb === 'last_seen')
|
|
255
|
+
comparison = new Date(a.last_seen).getTime() - new Date(b.last_seen).getTime()
|
|
256
|
+
else if (sb === 'first_seen')
|
|
257
|
+
comparison = new Date(a.first_seen).getTime() - new Date(b.first_seen).getTime()
|
|
258
|
+
return so === 'asc' ? comparison : -comparison
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const paginatedErrors = derived(() => {
|
|
263
|
+
const start = (currentPage() - 1) * itemsPerPage()
|
|
264
|
+
return filteredErrors().slice(start, start + itemsPerPage())
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const totalFiltered = derived(() => filteredErrors().length)
|
|
268
|
+
const totalPages = derived(() => Math.max(1, Math.ceil(filteredErrors().length / itemsPerPage())))
|
|
269
|
+
|
|
270
|
+
const hasFilters = derived(() => searchQuery() !== '' || (statusFilter() ?? '') !== '' || (typeFilter() ?? '') !== '')
|
|
271
|
+
const emptyTitle = derived(() => hasFilters() ? 'No matching errors' : 'No errors found')
|
|
272
|
+
const emptyDescription = derived(() => hasFilters() ? 'Try adjusting your filters' : 'Your application is running smoothly!')
|
|
273
|
+
|
|
274
|
+
const hasSelectedError = derived(() => selectedError() !== null)
|
|
275
|
+
const selectedIsUnresolved = derived(() => selectedError()?.status === 'unresolved')
|
|
276
|
+
const selectedIsResolvedOrIgnored = derived(() => {
|
|
277
|
+
const s = selectedError()?.status
|
|
278
|
+
return s !== undefined && s !== 'unresolved'
|
|
279
|
+
})
|
|
280
|
+
const hasStackTrace = derived(() => Boolean(selectedError()?.stack_trace))
|
|
281
|
+
const detailTitle = derived(() => selectedError()?.type ?? 'Error Details')
|
|
282
|
+
|
|
283
|
+
function selectedMessage(): string { return selectedError()?.message ?? '' }
|
|
284
|
+
function selectedCount(): number { return selectedError()?.count ?? 0 }
|
|
285
|
+
function selectedStatus(): string { return selectedError()?.status ?? '' }
|
|
286
|
+
function selectedFirstSeen(): string { return formatDate(selectedError()?.first_seen ?? '') }
|
|
287
|
+
function selectedLastSeen(): string { return formatDate(selectedError()?.last_seen ?? '') }
|
|
288
|
+
function selectedStackTrace(): string { return selectedError()?.stack_trace ?? '' }
|
|
289
|
+
|
|
290
|
+
function deleteCount(): number { return errorToDelete()?.count ?? 0 }
|
|
291
|
+
function deleteMessage(): string { return errorToDelete()?.message ?? '' }
|
|
292
|
+
|
|
293
|
+
function handleSort(column: string, direction: 'asc' | 'desc'): void {
|
|
294
|
+
sortBy.set(column)
|
|
295
|
+
sortOrder.set(direction)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function viewError(error: ErrorGroup): void {
|
|
299
|
+
selectedError.set(error)
|
|
300
|
+
isDetailModalOpen.set(true)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function closeDetailModal(): void {
|
|
304
|
+
isDetailModalOpen.set(false)
|
|
305
|
+
selectedError.set(null)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
async function handleResolveError(error: ErrorGroup): Promise<void> {
|
|
309
|
+
await resolveErrorGroup(error.type, error.message)
|
|
310
|
+
await fetchErrorStats()
|
|
311
|
+
if (isDetailModalOpen() && selectedError())
|
|
312
|
+
selectedError.update(e => e ? { ...e, status: 'resolved' } : e)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function handleIgnoreError(error: ErrorGroup): Promise<void> {
|
|
316
|
+
await ignoreErrorGroup(error.type, error.message)
|
|
317
|
+
await fetchErrorStats()
|
|
318
|
+
if (isDetailModalOpen() && selectedError())
|
|
319
|
+
selectedError.update(e => e ? { ...e, status: 'ignored' } : e)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function handleUnresolveError(error: ErrorGroup): Promise<void> {
|
|
323
|
+
await unresolveErrorGroup(error.type, error.message)
|
|
324
|
+
await fetchErrorStats()
|
|
325
|
+
if (isDetailModalOpen() && selectedError())
|
|
326
|
+
selectedError.update(e => e ? { ...e, status: 'unresolved' } : e)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function resolveSelected(): Promise<void> {
|
|
330
|
+
const target = selectedError()
|
|
331
|
+
if (target)
|
|
332
|
+
await handleResolveError(target)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function ignoreSelected(): Promise<void> {
|
|
336
|
+
const target = selectedError()
|
|
337
|
+
if (target)
|
|
338
|
+
await handleIgnoreError(target)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function unresolveSelected(): Promise<void> {
|
|
342
|
+
const target = selectedError()
|
|
343
|
+
if (target)
|
|
344
|
+
await handleUnresolveError(target)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function deleteSelected(): void {
|
|
348
|
+
const target = selectedError()
|
|
349
|
+
if (target)
|
|
350
|
+
openDeleteModal(target)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function openDeleteModal(error: ErrorGroup): void {
|
|
354
|
+
errorToDelete.set(error)
|
|
355
|
+
showDeleteModal.set(true)
|
|
356
|
+
if (isDetailModalOpen())
|
|
357
|
+
isDetailModalOpen.set(false)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function closeDeleteModal(): void {
|
|
361
|
+
showDeleteModal.set(false)
|
|
362
|
+
errorToDelete.set(null)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async function confirmDelete(): Promise<void> {
|
|
366
|
+
const target = errorToDelete()
|
|
367
|
+
if (!target)
|
|
368
|
+
return
|
|
369
|
+
await deleteErrorGroup(target.type, target.message)
|
|
370
|
+
await fetchErrorStats()
|
|
371
|
+
closeDeleteModal()
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function getStatusVariant(status: string): string {
|
|
375
|
+
const variants: Record<string, string> = {
|
|
376
|
+
unresolved: 'danger',
|
|
377
|
+
resolved: 'success',
|
|
378
|
+
ignored: 'warning',
|
|
379
|
+
}
|
|
380
|
+
return variants[status] || 'default'
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function formatDate(date: string): string {
|
|
384
|
+
if (!date)
|
|
385
|
+
return ''
|
|
386
|
+
return new Date(date).toLocaleString()
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function formatRelativeTime(date: string): string {
|
|
390
|
+
if (!date)
|
|
391
|
+
return ''
|
|
392
|
+
const now = new Date()
|
|
393
|
+
const errorDate = new Date(date)
|
|
394
|
+
const diffMs = now.getTime() - errorDate.getTime()
|
|
395
|
+
const diffMins = Math.floor(diffMs / 60000)
|
|
396
|
+
const diffHours = Math.floor(diffMins / 60)
|
|
397
|
+
const diffDays = Math.floor(diffHours / 24)
|
|
398
|
+
|
|
399
|
+
if (diffMins < 1)
|
|
400
|
+
return 'Just now'
|
|
401
|
+
if (diffMins < 60)
|
|
402
|
+
return `${diffMins}m ago`
|
|
403
|
+
if (diffHours < 24)
|
|
404
|
+
return `${diffHours}h ago`
|
|
405
|
+
if (diffDays < 7)
|
|
406
|
+
return `${diffDays}d ago`
|
|
407
|
+
return errorDate.toLocaleDateString()
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
onMount(async () => {
|
|
411
|
+
await Promise.all([fetchGroupedErrors(), fetchErrorStats()])
|
|
412
|
+
})
|
|
413
|
+
</script>
|
|
414
|
+
|
|
415
|
+
@endsection
|