@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,373 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Notification History')
|
|
5
|
+
<div class="py-4 lg:py-8 min-h-screen dark:bg-neutral-800">
|
|
6
|
+
<div class="px-4 sm:px-6 lg:px-8">
|
|
7
|
+
<div class="sm:flex sm:items-center">
|
|
8
|
+
<div class="sm:flex-auto">
|
|
9
|
+
<h1 class="font-semibold leading-6 text-base text-gray-900 dark:text-neutral-100">Notification History</h1>
|
|
10
|
+
<p class="mt-2 text-gray-700 text-sm dark:text-neutral-300">A complete history of all notifications sent through the system</p>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="sm:flex-none mt-4 sm:ml-16 sm:mt-0">
|
|
13
|
+
<button @click="toggleFilters()" type="button" class="inline-flex items-center px-3 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-100 bg-white dark:bg-neutral-600 hover:bg-gray-50 dark:hover:bg-neutral-500 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">
|
|
14
|
+
<div class="mr-2 h-5 w-5 i-hugeicons-filter"></div>
|
|
15
|
+
{{ filtersToggleLabel() }}
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div :show="showFilters" class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 mt-4">
|
|
21
|
+
<div class="flex-1 min-w-0">
|
|
22
|
+
<label for="search" class="sr-only">Search notifications</label>
|
|
23
|
+
<div class="relative rounded-md shadow-sm">
|
|
24
|
+
<div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
|
|
25
|
+
<div class="h-5 w-5 text-gray-400 i-hugeicons-search-01"></div>
|
|
26
|
+
</div>
|
|
27
|
+
<input x-model="searchQuery" type="search" name="search" id="search" placeholder="Search notifications..." class="block pl-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-neutral-100 placeholder:text-gray-400 dark:bg-neutral-600 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600 focus:ring-inset" />
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div>
|
|
32
|
+
<select x-model="selectedType" class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-neutral-100 dark:bg-neutral-600 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600">
|
|
33
|
+
<option value="all">All Types</option>
|
|
34
|
+
<option value="email">Email</option>
|
|
35
|
+
<option value="sms">Sms</option>
|
|
36
|
+
<option value="push">Push</option>
|
|
37
|
+
<option value="discord">Discord</option>
|
|
38
|
+
<option value="slack">Slack</option>
|
|
39
|
+
</select>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div>
|
|
43
|
+
<select x-model="selectedStatus" class="block pl-3 pr-10 py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm dark:text-neutral-100 dark:bg-neutral-600 border-0 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 focus:ring-2 focus:ring-blue-600">
|
|
44
|
+
<option value="all">All Statuses</option>
|
|
45
|
+
<option value="sent">Sent</option>
|
|
46
|
+
<option value="delivered">Delivered</option>
|
|
47
|
+
<option value="failed">Failed</option>
|
|
48
|
+
<option value="pending">Pending</option>
|
|
49
|
+
</select>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="flex items-end">
|
|
53
|
+
<button @click="resetFilters()" type="button" class="px-3 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-100 bg-white dark:bg-neutral-600 hover:bg-gray-50 dark:hover:bg-neutral-500 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 shadow-sm">Reset Filters</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="flow-root mt-8">
|
|
58
|
+
<div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
|
|
59
|
+
<div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
|
|
60
|
+
<div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg dark:ring-opacity-20 shadow">
|
|
61
|
+
<table class="min-w-full divide-gray-300 divide-y dark:divide-neutral-600">
|
|
62
|
+
<thead class="bg-gray-50 dark:bg-neutral-600">
|
|
63
|
+
<tr>
|
|
64
|
+
<th scope="col" class="pl-4 pr-3 py-3.5 sm:pl-6 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Type</th>
|
|
65
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Recipient</th>
|
|
66
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Subject</th>
|
|
67
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-left text-sm dark:text-neutral-100">Status</th>
|
|
68
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-right text-sm dark:text-neutral-100 cursor-pointer" @click="toggleSort('sent_at')">
|
|
69
|
+
<div class="flex items-center justify-end">
|
|
70
|
+
Sent
|
|
71
|
+
<div :show="isSortedBy('sent_at')" class="ml-2">
|
|
72
|
+
<div :show="sortDirection() === 'desc'" class="h-4 w-4 i-hugeicons-chevron-down"></div>
|
|
73
|
+
<div :show="sortDirection() === 'asc'" class="h-4 w-4 i-hugeicons-chevron-up"></div>
|
|
74
|
+
</div>
|
|
75
|
+
<div :show="isUnsorted('sent_at')" class="ml-2">
|
|
76
|
+
<div class="h-4 w-4 text-gray-400 i-hugeicons-arrows-up-down"></div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</th>
|
|
80
|
+
<th scope="col" class="px-3 py-3.5 font-semibold text-gray-900 text-right text-sm dark:text-neutral-100 cursor-pointer" @click="toggleSort('delivered_at')">
|
|
81
|
+
<div class="flex items-center justify-end">
|
|
82
|
+
Delivered
|
|
83
|
+
<div :show="isSortedBy('delivered_at')" class="ml-2">
|
|
84
|
+
<div :show="sortDirection() === 'desc'" class="h-4 w-4 i-hugeicons-chevron-down"></div>
|
|
85
|
+
<div :show="sortDirection() === 'asc'" class="h-4 w-4 i-hugeicons-chevron-up"></div>
|
|
86
|
+
</div>
|
|
87
|
+
<div :show="isUnsorted('delivered_at')" class="ml-2">
|
|
88
|
+
<div class="h-4 w-4 text-gray-400 i-hugeicons-arrows-up-down"></div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</th>
|
|
92
|
+
<th scope="col" class="relative pl-3 pr-4 py-3.5 sm:pr-6"><span class="sr-only">Actions</span></th>
|
|
93
|
+
</tr>
|
|
94
|
+
</thead>
|
|
95
|
+
<tbody class="bg-white dark:bg-neutral-700 divide-gray-200 divide-y dark:divide-neutral-600">
|
|
96
|
+
<tr :show="isLoading">
|
|
97
|
+
<td colspan="7" class="px-3 py-4 text-center text-gray-500 text-sm dark:text-neutral-400">
|
|
98
|
+
<div class="flex justify-center">
|
|
99
|
+
<div class="h-8 w-8 border-b-2 border-blue-500 rounded-full animate-spin"></div>
|
|
100
|
+
</div>
|
|
101
|
+
</td>
|
|
102
|
+
</tr>
|
|
103
|
+
<tr :show="hasNoNotifications">
|
|
104
|
+
<td colspan="7" class="px-3 py-4 text-center text-gray-500 text-sm dark:text-neutral-400">No notifications found matching your criteria</td>
|
|
105
|
+
</tr>
|
|
106
|
+
<template :for="notification in paginatedNotifications">
|
|
107
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-neutral-600/50">
|
|
108
|
+
<td class="pl-4 pr-3 py-4 sm:pl-6 text-sm whitespace-nowrap">
|
|
109
|
+
<div class="flex items-center">
|
|
110
|
+
<div class="mr-2 h-5 w-5 {{ getChannelIcon(notification.type) }}"></div>
|
|
111
|
+
<span class="capitalize font-medium text-gray-900 dark:text-neutral-100">{{ notification.type }}</span>
|
|
112
|
+
</div>
|
|
113
|
+
</td>
|
|
114
|
+
<td class="px-3 py-4 text-gray-500 text-sm whitespace-nowrap dark:text-neutral-400">{{ notification.recipient }}</td>
|
|
115
|
+
<td class="px-3 py-4 text-gray-500 text-sm dark:text-neutral-400">
|
|
116
|
+
<div class="max-w-xs truncate">{{ notification.subject }}</div>
|
|
117
|
+
</td>
|
|
118
|
+
<td class="px-3 py-4 text-sm whitespace-nowrap">
|
|
119
|
+
<NotificationStatusBadge :status="notification.status" />
|
|
120
|
+
</td>
|
|
121
|
+
<td class="px-3 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-400">{{ formatDate(notification.sent_at) }}</td>
|
|
122
|
+
<td class="px-3 py-4 text-gray-500 text-right text-sm whitespace-nowrap dark:text-neutral-400">{{ notification.delivered_at ? formatDate(notification.delivered_at) : '-' }}</td>
|
|
123
|
+
<td class="relative pl-3 pr-4 py-4 sm:pr-6 font-medium text-right text-sm whitespace-nowrap">
|
|
124
|
+
<div class="flex justify-end space-x-2">
|
|
125
|
+
<button :show="{{ notification.status === 'failed' ? 'true' : 'false' }}" @click="handleRetry('{{ notification.id }}')" type="button" class="text-blue-600 hover:text-blue-900 dark:hover:text-blue-400">Retry</button>
|
|
126
|
+
<button @click="openErrorModal('{{ notification.id }}')" type="button" class="text-gray-600 dark:text-neutral-400 hover:text-gray-900 dark:hover:text-gray-200">View Logs</button>
|
|
127
|
+
</div>
|
|
128
|
+
</td>
|
|
129
|
+
</tr>
|
|
130
|
+
</template>
|
|
131
|
+
</tbody>
|
|
132
|
+
</table>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="flex items-center justify-between mt-4">
|
|
139
|
+
<div class="flex items-center">
|
|
140
|
+
<p class="text-gray-700 text-sm dark:text-neutral-300">
|
|
141
|
+
Showing <span class="font-medium">{{ rangeStart() }}</span> to <span class="font-medium">{{ rangeEnd() }}</span> of <span class="font-medium">{{ totalFiltered() }}</span> results
|
|
142
|
+
</p>
|
|
143
|
+
</div>
|
|
144
|
+
<div class="flex items-center space-x-2">
|
|
145
|
+
<button :show="canGoBack" type="button" class="inline-flex relative focus:z-10 items-center px-3 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-100 bg-white dark:bg-neutral-600 hover:bg-gray-50 dark:hover:bg-neutral-500 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600" @click="previousPage()">Previous</button>
|
|
146
|
+
<button type="button" class="inline-flex relative focus:z-10 items-center px-3 py-2 font-semibold text-gray-900 text-sm dark:text-neutral-100 bg-white dark:bg-neutral-600 hover:bg-gray-50 dark:hover:bg-neutral-500 ring-1 ring-gray-300 ring-inset rounded-md dark:ring-neutral-600 disabled:opacity-50" :disabled="isLastPage" @click="nextPage()">Next</button>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<NotificationErrorModal
|
|
152
|
+
:isOpen="isErrorModalOpen"
|
|
153
|
+
:notificationId="errorModalId"
|
|
154
|
+
:notificationType="errorModalType"
|
|
155
|
+
:errorMessage="errorModalMessage"
|
|
156
|
+
:sentAt="errorModalSentAt"
|
|
157
|
+
@close="closeErrorModal"
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<script client>
|
|
162
|
+
interface NotificationEntry {
|
|
163
|
+
id: string
|
|
164
|
+
type: 'email' | 'sms' | 'push' | 'discord' | 'slack'
|
|
165
|
+
recipient: string
|
|
166
|
+
subject: string
|
|
167
|
+
content: string
|
|
168
|
+
status: 'sent' | 'delivered' | 'failed' | 'pending'
|
|
169
|
+
sent_at: string
|
|
170
|
+
delivered_at?: string
|
|
171
|
+
error?: string
|
|
172
|
+
metadata?: Record<string, unknown>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const notifications = state<NotificationEntry[]>([])
|
|
176
|
+
const currentPage = state(1)
|
|
177
|
+
const perPage = state(10)
|
|
178
|
+
const isLoading = state(true)
|
|
179
|
+
const searchQuery = state('')
|
|
180
|
+
const selectedType = state('all')
|
|
181
|
+
const selectedStatus = state('all')
|
|
182
|
+
const showFilters = state(false)
|
|
183
|
+
const sortField = state<string | null>(null)
|
|
184
|
+
const sortDirection = state<'asc' | 'desc'>('desc')
|
|
185
|
+
|
|
186
|
+
const isErrorModalOpen = state(false)
|
|
187
|
+
const errorModalId = state('')
|
|
188
|
+
const errorModalType = state<'email' | 'sms' | 'push' | 'discord' | 'slack'>('email')
|
|
189
|
+
const errorModalMessage = state('')
|
|
190
|
+
const errorModalSentAt = state('')
|
|
191
|
+
|
|
192
|
+
function getChannelIcon(type: string): string {
|
|
193
|
+
switch (type) {
|
|
194
|
+
case 'email': return 'i-hugeicons-mail-01'
|
|
195
|
+
case 'sms': return 'i-hugeicons-smart-phone-01'
|
|
196
|
+
case 'push': return 'i-hugeicons-notification-01'
|
|
197
|
+
case 'discord': return 'i-hugeicons-discord'
|
|
198
|
+
case 'slack': return 'i-hugeicons-slack'
|
|
199
|
+
default: return 'i-hugeicons-notification-03'
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function generateMockNotifications(): NotificationEntry[] {
|
|
204
|
+
const types: Array<NotificationEntry['type']> = ['email', 'sms', 'push', 'discord', 'slack']
|
|
205
|
+
const statuses: Array<NotificationEntry['status']> = ['sent', 'delivered', 'failed', 'pending']
|
|
206
|
+
const subjects = [
|
|
207
|
+
'Welcome to our platform',
|
|
208
|
+
'Your account has been updated',
|
|
209
|
+
'Security alert',
|
|
210
|
+
'Password reset request',
|
|
211
|
+
'New login detected',
|
|
212
|
+
'Subscription renewed',
|
|
213
|
+
'Payment processed',
|
|
214
|
+
'Order confirmation',
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
return Array.from({ length: 100 }, (_, i) => {
|
|
218
|
+
const type = types[Math.floor(Math.random() * types.length)] as NotificationEntry['type']
|
|
219
|
+
const status = statuses[Math.floor(Math.random() * statuses.length)] as NotificationEntry['status']
|
|
220
|
+
const subject = subjects[Math.floor(Math.random() * subjects.length)] || 'System Notification'
|
|
221
|
+
const sent_at = new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
222
|
+
const delivered_at = status === 'delivered' ? new Date(new Date(sent_at).getTime() + Math.random() * 60000).toISOString() : undefined
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
id: `${i + 1}`,
|
|
226
|
+
type,
|
|
227
|
+
recipient: type === 'email'
|
|
228
|
+
? 'user@example.com'
|
|
229
|
+
: type === 'sms'
|
|
230
|
+
? '+1234567890'
|
|
231
|
+
: type === 'push'
|
|
232
|
+
? 'device-token-123'
|
|
233
|
+
: type === 'discord' ? 'Channel #announcements' : '#general',
|
|
234
|
+
subject,
|
|
235
|
+
content: 'Notification content goes here...',
|
|
236
|
+
status,
|
|
237
|
+
sent_at,
|
|
238
|
+
delivered_at,
|
|
239
|
+
error: status === 'failed' ? 'Failed to deliver notification' : undefined,
|
|
240
|
+
metadata: {
|
|
241
|
+
device: type === 'push' ? 'iOS' : undefined,
|
|
242
|
+
browser: type === 'push' ? 'Safari' : undefined,
|
|
243
|
+
},
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const filteredNotifications = derived(() => {
|
|
249
|
+
const list = notifications()
|
|
250
|
+
const type = selectedType()
|
|
251
|
+
const status = selectedStatus()
|
|
252
|
+
const q = searchQuery().toLowerCase()
|
|
253
|
+
return list.filter((n) => {
|
|
254
|
+
if (type !== 'all' && n.type !== type)
|
|
255
|
+
return false
|
|
256
|
+
if (status !== 'all' && n.status !== status)
|
|
257
|
+
return false
|
|
258
|
+
if (q) {
|
|
259
|
+
return n.subject.toLowerCase().includes(q)
|
|
260
|
+
|| n.recipient.toLowerCase().includes(q)
|
|
261
|
+
|| n.content.toLowerCase().includes(q)
|
|
262
|
+
}
|
|
263
|
+
return true
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const sortedNotifications = derived(() => {
|
|
268
|
+
const field = sortField()
|
|
269
|
+
if (!field)
|
|
270
|
+
return filteredNotifications()
|
|
271
|
+
const dir = sortDirection()
|
|
272
|
+
return [...filteredNotifications()].sort((a, b) => {
|
|
273
|
+
const aValue = (a as Record<string, unknown>)[field] as string | undefined
|
|
274
|
+
const bValue = (b as Record<string, unknown>)[field] as string | undefined
|
|
275
|
+
if (!aValue && !bValue)
|
|
276
|
+
return 0
|
|
277
|
+
if (!aValue)
|
|
278
|
+
return 1
|
|
279
|
+
if (!bValue)
|
|
280
|
+
return -1
|
|
281
|
+
const comparison = new Date(aValue).getTime() - new Date(bValue).getTime()
|
|
282
|
+
return dir === 'asc' ? comparison : -comparison
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
const paginatedNotifications = derived(() => {
|
|
287
|
+
const start = (currentPage() - 1) * perPage()
|
|
288
|
+
return sortedNotifications().slice(start, start + perPage())
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
const totalPages = derived(() => Math.max(1, Math.ceil(filteredNotifications().length / perPage())))
|
|
292
|
+
const totalFiltered = derived(() => filteredNotifications().length)
|
|
293
|
+
const rangeStart = derived(() => totalFiltered() === 0 ? 0 : (currentPage() - 1) * perPage() + 1)
|
|
294
|
+
const rangeEnd = derived(() => Math.min(currentPage() * perPage(), totalFiltered()))
|
|
295
|
+
const hasNoNotifications = derived(() => !isLoading() && paginatedNotifications().length === 0)
|
|
296
|
+
const canGoBack = derived(() => currentPage() > 1)
|
|
297
|
+
const isLastPage = derived(() => currentPage() >= totalPages())
|
|
298
|
+
|
|
299
|
+
function isSortedBy(field: string): boolean { return sortField() === field }
|
|
300
|
+
function isUnsorted(field: string): boolean { return sortField() !== field }
|
|
301
|
+
function filtersToggleLabel(): string { return showFilters() ? 'Hide Filters' : 'Show Filters' }
|
|
302
|
+
|
|
303
|
+
function toggleFilters(): void {
|
|
304
|
+
showFilters.update(v => !v)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function previousPage(): void {
|
|
308
|
+
if (currentPage() > 1)
|
|
309
|
+
currentPage.update(p => p - 1)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function nextPage(): void {
|
|
313
|
+
if (currentPage() < totalPages())
|
|
314
|
+
currentPage.update(p => p + 1)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function resetFilters(): void {
|
|
318
|
+
selectedType.set('all')
|
|
319
|
+
selectedStatus.set('all')
|
|
320
|
+
searchQuery.set('')
|
|
321
|
+
currentPage.set(1)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function formatDate(date: string): string {
|
|
325
|
+
return new Date(date).toLocaleString()
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function toggleSort(field: string): void {
|
|
329
|
+
if (sortField() === field)
|
|
330
|
+
sortDirection.set(sortDirection() === 'asc' ? 'desc' : 'asc')
|
|
331
|
+
else {
|
|
332
|
+
sortField.set(field)
|
|
333
|
+
sortDirection.set('desc')
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function handleRetry(id: string): void {
|
|
338
|
+
// eslint-disable-next-line no-console
|
|
339
|
+
console.log('Retrying notification:', id)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function openErrorModal(id: string): void {
|
|
343
|
+
const target = notifications().find(n => n.id === id)
|
|
344
|
+
if (!target)
|
|
345
|
+
return
|
|
346
|
+
errorModalId.set(target.id)
|
|
347
|
+
errorModalType.set(target.type)
|
|
348
|
+
errorModalMessage.set(target.error || 'No error information available')
|
|
349
|
+
errorModalSentAt.set(target.sent_at)
|
|
350
|
+
isErrorModalOpen.set(true)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function closeErrorModal(): void {
|
|
354
|
+
isErrorModalOpen.set(false)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
onMount(async () => {
|
|
358
|
+
isLoading.set(true)
|
|
359
|
+
try {
|
|
360
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
361
|
+
notifications.set(generateMockNotifications())
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
// eslint-disable-next-line no-console
|
|
365
|
+
console.error('Failed to load notifications:', error)
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
isLoading.set(false)
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
</script>
|
|
372
|
+
|
|
373
|
+
@endsection
|