@stacksjs/defaults 0.70.207 → 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,540 @@
|
|
|
1
|
+
@extends('layouts/default')
|
|
2
|
+
|
|
3
|
+
@section('content')
|
|
4
|
+
@title('Dashboard - Logs')
|
|
5
|
+
<div class="p-6 space-y-6">
|
|
6
|
+
<PageHeader title="System Logs" description="A list of all system logs. Monitor system activities and events in real-time." />
|
|
7
|
+
|
|
8
|
+
<div class="bg-white dark:bg-neutral-700 rounded-lg shadow">
|
|
9
|
+
<div class="p-6">
|
|
10
|
+
<div class="flex items-center justify-between mb-6">
|
|
11
|
+
<div>
|
|
12
|
+
<h3 class="font-medium text-base text-gray-900 dark:text-neutral-100">Log Volume</h3>
|
|
13
|
+
<p class="mt-1 text-gray-500 text-sm dark:text-neutral-400">Distribution of log types over time</p>
|
|
14
|
+
</div>
|
|
15
|
+
<select x-model="timeRange" class="pl-3 pr-8 py-1.5 h-9 text-gray-900 text-sm dark:text-neutral-100 bg-gray-50 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">
|
|
16
|
+
<option value="day">Last 24 Hours</option>
|
|
17
|
+
<option value="week">Last 7 Days</option>
|
|
18
|
+
<option value="month">Last 30 Days</option>
|
|
19
|
+
<option value="year">Last Year</option>
|
|
20
|
+
</select>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="relative h-[300px]">
|
|
23
|
+
<div :show="isLoading()" class="flex absolute inset-0 z-10 items-center justify-center bg-opacity-75 bg-white dark:bg-neutral-700 dark:bg-opacity-75">
|
|
24
|
+
<div class="h-8 w-8 border-b-2 border-blue-500 rounded-full animate-spin"></div>
|
|
25
|
+
</div>
|
|
26
|
+
<canvas id="logs_volume_chart"></canvas>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="flow-root mt-8">
|
|
32
|
+
<div class="mb-6 space-y-4">
|
|
33
|
+
<div class="flex flex-wrap gap-4 items-center">
|
|
34
|
+
<div class="flex-1 min-w-[200px]">
|
|
35
|
+
<input x-model="searchTerm" type="text" placeholder="Search logs..." class="px-4 py-2 w-full text-gray-900 dark:text-neutral-100 dark:bg-neutral-700 border border-gray-300 rounded-lg dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<select x-model="sourceFilter" class="px-4 py-2 min-w-[140px] text-gray-900 dark:text-neutral-100 bg-white dark:bg-neutral-800 border border-gray-300 rounded-lg dark:border-neutral-600">
|
|
39
|
+
<option value="all">All Sources</option>
|
|
40
|
+
<option value="cli">CLI</option>
|
|
41
|
+
<option value="file">File</option>
|
|
42
|
+
<option value="system">System</option>
|
|
43
|
+
<option value="mail">Mail</option>
|
|
44
|
+
<option value="notification">Notification</option>
|
|
45
|
+
</select>
|
|
46
|
+
|
|
47
|
+
<select x-model="logTypeFilter" class="px-4 py-2 min-w-[140px] text-gray-900 dark:text-neutral-100 bg-white dark:bg-neutral-800 border border-gray-300 rounded-lg dark:border-neutral-600">
|
|
48
|
+
<option value="all">All Types</option>
|
|
49
|
+
<option value="info">Info</option>
|
|
50
|
+
<option value="success">Success</option>
|
|
51
|
+
<option value="warning">Warning</option>
|
|
52
|
+
<option value="error">Error</option>
|
|
53
|
+
<option value="mail">Mail</option>
|
|
54
|
+
</select>
|
|
55
|
+
|
|
56
|
+
<button @click="toggleAutoRefresh()" class="{{ autoRefreshClass() }}">
|
|
57
|
+
<i class="h-4 w-4 i-hugeicons-refresh {{ autoRefresh() ? 'animate-spin' : '' }}" aria-hidden="true"></i>
|
|
58
|
+
{{ autoRefresh() ? 'Auto-refreshing' : 'Auto-refresh' }}
|
|
59
|
+
</button>
|
|
60
|
+
|
|
61
|
+
<button :show="hasActiveFilters()" @click="resetFilters()" class="flex gap-2 items-center px-4 py-2 text-gray-700 dark:text-neutral-200 bg-gray-100 dark:bg-neutral-700 hover:bg-gray-200 dark:hover:bg-neutral-600 rounded-lg">
|
|
62
|
+
<i class="h-4 w-4 i-hugeicons-cancel-01" aria-hidden="true"></i>
|
|
63
|
+
Reset Filters
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="flex flex-wrap gap-2">
|
|
68
|
+
<template :for="project in projectsList">
|
|
69
|
+
<button @click="toggleProject(project.id)" class="{{ projectButtonClassFor(project.id) }}">
|
|
70
|
+
{{ project.name }}
|
|
71
|
+
<span :show="isProjectSelected(project.id)" class="ml-2 text-xs">×</span>
|
|
72
|
+
</button>
|
|
73
|
+
</template>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div class="overflow-x-auto -mx-4 -my-2 sm:-mx-6 lg:-mx-8">
|
|
78
|
+
<div class="inline-block py-2 sm:px-6 lg:px-8 min-w-full align-middle">
|
|
79
|
+
<div class="overflow-hidden ring-1 ring-black ring-opacity-5 sm:rounded-lg shadow">
|
|
80
|
+
<table class="min-w-full divide-gray-200 divide-y dark:divide-neutral-700">
|
|
81
|
+
<thead class="bg-gray-50 dark:bg-neutral-700/50">
|
|
82
|
+
<tr>
|
|
83
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase">Timestamp</th>
|
|
84
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase">Type</th>
|
|
85
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase">Source</th>
|
|
86
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase">Message</th>
|
|
87
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-left text-xs tracking-wider uppercase">Project</th>
|
|
88
|
+
<th class="px-6 py-3 font-medium text-gray-500 text-right text-xs tracking-wider uppercase">Details</th>
|
|
89
|
+
</tr>
|
|
90
|
+
</thead>
|
|
91
|
+
<tbody class="bg-white dark:bg-neutral-800 divide-gray-200 divide-y dark:divide-neutral-700">
|
|
92
|
+
<template :for="log in paginatedLogs">
|
|
93
|
+
<tr @click="selectLog(log.id)" class="{{ logRowClass(log) }}">
|
|
94
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
95
|
+
<div class="text-gray-900 text-sm dark:text-neutral-100">
|
|
96
|
+
<i class="mr-2 h-4 w-4 text-gray-400 i-hugeicons-clock-01" aria-hidden="true"></i>
|
|
97
|
+
{{ formatTime(log.timestamp) }}
|
|
98
|
+
</div>
|
|
99
|
+
</td>
|
|
100
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
101
|
+
<div class="flex items-center">
|
|
102
|
+
<i :class="logIconClass(log.type)" aria-hidden="true"></i>
|
|
103
|
+
</div>
|
|
104
|
+
</td>
|
|
105
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
106
|
+
<span class="inline-flex px-2 font-semibold leading-5 text-blue-800 text-xs dark:text-blue-100 bg-blue-100 dark:bg-blue-900 rounded-full">{{ log.source }}</span>
|
|
107
|
+
</td>
|
|
108
|
+
<td class="px-6 py-4">
|
|
109
|
+
<div class="text-gray-900 text-sm dark:text-neutral-100">{{ log.message }}</div>
|
|
110
|
+
<div :if="log.email" class="mt-1 text-gray-500 text-xs truncate dark:text-neutral-400">{{ log.email?.subject }}</div>
|
|
111
|
+
</td>
|
|
112
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
113
|
+
<span :if="log.project" :class="projectBadgeClassFor(log.project)">{{ projectName(log.project) }}</span>
|
|
114
|
+
</td>
|
|
115
|
+
<td class="px-6 py-4 text-right whitespace-nowrap">
|
|
116
|
+
<button class="text-gray-400 hover:text-blue-500 duration-150 transition-colors">
|
|
117
|
+
<i class="h-5 w-5 i-hugeicons-view" aria-hidden="true"></i>
|
|
118
|
+
</button>
|
|
119
|
+
</td>
|
|
120
|
+
</tr>
|
|
121
|
+
</template>
|
|
122
|
+
<tr :show="paginatedLogs().length === 0">
|
|
123
|
+
<td colspan="6" class="px-6 py-8 text-center text-gray-500 text-sm dark:text-neutral-400">No logs match your filters.</td>
|
|
124
|
+
</tr>
|
|
125
|
+
</tbody>
|
|
126
|
+
</table>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="flex items-center justify-between mt-4">
|
|
132
|
+
<div class="flex items-center">
|
|
133
|
+
<span class="text-gray-700 text-sm dark:text-neutral-400">
|
|
134
|
+
Showing <span class="font-medium">{{ paginatedLogs().length }}</span> of <span class="font-medium">{{ totalItems() }}</span> results
|
|
135
|
+
</span>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="flex items-center space-x-2">
|
|
138
|
+
<select x-model="itemsPerPage" class="px-2 py-1 text-sm dark:text-neutral-100 dark:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600">
|
|
139
|
+
<option value="10">10 per page</option>
|
|
140
|
+
<option value="25">25 per page</option>
|
|
141
|
+
<option value="50">50 per page</option>
|
|
142
|
+
<option value="100">100 per page</option>
|
|
143
|
+
</select>
|
|
144
|
+
|
|
145
|
+
<div class="flex items-center space-x-1">
|
|
146
|
+
<button @click="prevPage()" :disabled="currentPage() === 1" class="px-2 py-1 text-sm hover:bg-gray-100 dark:hover:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600 disabled:opacity-50 disabled:cursor-not-allowed">
|
|
147
|
+
<i class="h-4 w-4 i-hugeicons-arrow-left-01" aria-hidden="true"></i>
|
|
148
|
+
</button>
|
|
149
|
+
|
|
150
|
+
<template :for="page in visiblePages">
|
|
151
|
+
<button @click="goToPage(page)" class="{{ pageButtonClass(page) }}">{{ page }}</button>
|
|
152
|
+
</template>
|
|
153
|
+
|
|
154
|
+
<span :show="totalPages() > 5" class="px-2 text-gray-500 dark:text-neutral-400">...</span>
|
|
155
|
+
|
|
156
|
+
<button :show="totalPages() > 5" @click="goToPage(totalPages())" class="{{ pageButtonClass(totalPages()) }}">{{ totalPages() }}</button>
|
|
157
|
+
|
|
158
|
+
<button @click="nextPage()" :disabled="currentPage() >= totalPages() || totalPages() === 0" class="px-2 py-1 text-sm hover:bg-gray-100 dark:hover:bg-neutral-700 border border-gray-300 rounded-md dark:border-neutral-600 disabled:opacity-50 disabled:cursor-not-allowed">
|
|
159
|
+
<i class="h-4 w-4 i-hugeicons-arrow-right-01" aria-hidden="true"></i>
|
|
160
|
+
</button>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<div :show="selectedLog() !== null" @click.self="closeModal()" class="flex fixed inset-0 z-50 items-center justify-center p-4 bg-black bg-opacity-50">
|
|
166
|
+
<div class="overflow-y-auto p-6 max-h-[90vh] max-w-2xl w-full bg-white dark:bg-neutral-800 rounded-lg shadow-xl">
|
|
167
|
+
<div class="flex items-center justify-between mb-4">
|
|
168
|
+
<h3 class="font-semibold text-gray-900 text-lg dark:text-neutral-100">Log Details</h3>
|
|
169
|
+
<button @click="closeModal()" class="text-gray-500 dark:text-neutral-400 hover:text-gray-700 dark:hover:text-neutral-200">
|
|
170
|
+
<i class="h-5 w-5 i-hugeicons-cancel-01" aria-hidden="true"></i>
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="space-y-4">
|
|
174
|
+
<div>
|
|
175
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Timestamp</label>
|
|
176
|
+
<p class="mt-1 text-gray-900 text-sm dark:text-neutral-100">{{ formatDateTime(selectedLog()?.timestamp) }}</p>
|
|
177
|
+
</div>
|
|
178
|
+
<div>
|
|
179
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Type</label>
|
|
180
|
+
<div class="flex items-center mt-1">
|
|
181
|
+
<i :class="selectedLogIconClass()" aria-hidden="true"></i>
|
|
182
|
+
<span class="ml-2 capitalize text-gray-900 text-sm dark:text-neutral-100">{{ selectedLog()?.type }}</span>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
<div>
|
|
186
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Source</label>
|
|
187
|
+
<p class="mt-1 text-gray-900 text-sm dark:text-neutral-100">{{ selectedLog()?.source }}</p>
|
|
188
|
+
</div>
|
|
189
|
+
<div>
|
|
190
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Project</label>
|
|
191
|
+
<p class="mt-1 text-gray-900 text-sm dark:text-neutral-100">{{ selectedProjectName() }}</p>
|
|
192
|
+
</div>
|
|
193
|
+
<div>
|
|
194
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Message</label>
|
|
195
|
+
<p class="mt-1 text-gray-900 text-sm dark:text-neutral-100">{{ selectedLog()?.message }}</p>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div :if="selectedLog()?.metadata?.command" class="mt-4">
|
|
199
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Command</label>
|
|
200
|
+
<div class="mt-2 p-3 font-mono text-sm dark:text-neutral-100 bg-gray-50 dark:bg-neutral-900 rounded-md">{{ selectedLog()?.metadata?.command }}</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<div>
|
|
204
|
+
<label class="block font-medium text-gray-700 text-sm dark:text-neutral-300">Metadata</label>
|
|
205
|
+
<pre class="overflow-x-auto mt-1 p-3 text-gray-900 text-sm dark:text-neutral-100 bg-gray-50 dark:bg-neutral-900 rounded">{{ selectedMetadataJson() }}</pre>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<script client>
|
|
214
|
+
interface Log {
|
|
215
|
+
id: string
|
|
216
|
+
timestamp: string
|
|
217
|
+
type: 'info' | 'error' | 'success' | 'warning' | 'mail'
|
|
218
|
+
source: 'CLI' | 'File' | 'System' | 'Mail' | 'Notification'
|
|
219
|
+
message: string
|
|
220
|
+
metadata: Record<string, unknown>
|
|
221
|
+
project?: string
|
|
222
|
+
email?: { subject?: string, sender?: string, recipient?: string }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface Project { id: string, name: string, color: string }
|
|
226
|
+
|
|
227
|
+
interface ChartLike { destroy: () => void, update: () => void, data: { labels: string[], datasets: Array<{ label?: string, data: number[], borderColor?: string, backgroundColor?: string, fill?: boolean }> } }
|
|
228
|
+
type ChartCtor = new (canvas: HTMLElement, config: { type: string, data: unknown, options?: unknown }) => ChartLike
|
|
229
|
+
|
|
230
|
+
const projectsList: Project[] = [
|
|
231
|
+
{ id: 'stacks', name: 'Stacks', color: 'blue' },
|
|
232
|
+
{ id: 'rpx', name: 'rpx', color: 'purple' },
|
|
233
|
+
{ id: 'tlsx', name: 'tlsx', color: 'green' },
|
|
234
|
+
{ id: 'dtsx', name: 'dtsx', color: 'indigo' },
|
|
235
|
+
{ id: 'ts-collect', name: 'ts-collect', color: 'rose' },
|
|
236
|
+
{ id: 'vite-plugin-local', name: 'vite-plugin-local', color: 'amber' },
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
const now = Date.now()
|
|
240
|
+
const sampleLogs: Log[] = [
|
|
241
|
+
{ id: '1', timestamp: new Date(now).toISOString(), type: 'info', source: 'CLI', message: 'buddy build started', metadata: { user: 'chris@stacksjs.com', command: 'buddy build' }, project: 'stacks' },
|
|
242
|
+
{ id: '2', timestamp: new Date(now - 5000).toISOString(), type: 'error', source: 'File', message: 'Failed to compile component', metadata: { file: './components/Header.stx', line: 42 }, project: 'rpx' },
|
|
243
|
+
{ id: '3', timestamp: new Date(now - 15000).toISOString(), type: 'success', source: 'System', message: 'Production deployment successful', metadata: { deployment_id: 'dep_abc123', environment: 'production', branch: 'main', commit: '7829abc', duration: '45s' }, project: 'stacks' },
|
|
244
|
+
{ id: '4', timestamp: new Date(now - 60000).toISOString(), type: 'info', source: 'CLI', message: 'Starting database migration', metadata: { migration: 'create_users_table', database: 'production', user: 'deploy@stacksjs.com', command: 'buddy db:migrate' }, project: 'stacks' },
|
|
245
|
+
{ id: '5', timestamp: new Date(now - 120000).toISOString(), type: 'error', source: 'System', message: 'Failed to connect to Redis cache', metadata: { error: 'Connection timeout', host: 'redis.internal', port: 6379, attempt: 3 }, project: 'stacks' },
|
|
246
|
+
{ id: '6', timestamp: new Date(now - 180000).toISOString(), type: 'success', source: 'CLI', message: 'Assets compiled successfully', metadata: { duration: '12.5s', assets: ['main.js', 'vendor.js', 'app.css'], size: '2.3MB', command: 'buddy build --production' }, project: 'stacks' },
|
|
247
|
+
{ id: '7', timestamp: new Date(now - 240000).toISOString(), type: 'info', source: 'System', message: 'Auto-scaling triggered', metadata: { reason: 'High CPU usage', current_instances: 3, target_instances: 5, region: 'us-east-1' }, project: 'stacks' },
|
|
248
|
+
{ id: '8', timestamp: new Date(now - 300000).toISOString(), type: 'success', source: 'CLI', message: 'Configuration cache cleared', metadata: { triggered_by: 'deployment', cache_size: '156KB', duration: '0.8s', command: 'buddy config:clear' }, project: 'stacks' },
|
|
249
|
+
{ id: '9', timestamp: new Date(now - 360000).toISOString(), type: 'info', source: 'CLI', message: 'Running test suite', metadata: { suite: 'Integration Tests', total_tests: 156, parallel: true, ci: true, command: 'buddy test --suite=integration' }, project: 'stacks' },
|
|
250
|
+
{ id: '10', timestamp: new Date(now - 420000).toISOString(), type: 'error', source: 'System', message: 'SSL certificate expiring soon', metadata: { domain: 'api.stacksjs.com', expires_in: '7 days', certificate_id: 'cert_xyz789' }, project: 'stacks' },
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
const logs = state<Log[]>(sampleLogs)
|
|
254
|
+
const currentPage = state(1)
|
|
255
|
+
const itemsPerPage = state('10')
|
|
256
|
+
const sourceFilter = state('all')
|
|
257
|
+
const logTypeFilter = state('all')
|
|
258
|
+
const searchTerm = state('')
|
|
259
|
+
const autoRefresh = state(true)
|
|
260
|
+
const selectedLogId = state<string | null>(null)
|
|
261
|
+
const selectedProjects = state<string[]>([])
|
|
262
|
+
const isLoading = state(false)
|
|
263
|
+
const timeRange = state('day')
|
|
264
|
+
|
|
265
|
+
const itemsPerPageNum = derived(() => Number.parseInt(itemsPerPage(), 10) || 10)
|
|
266
|
+
|
|
267
|
+
const filteredLogs = derived(() => {
|
|
268
|
+
const q = searchTerm().toLowerCase()
|
|
269
|
+
const src = sourceFilter()
|
|
270
|
+
const type = logTypeFilter()
|
|
271
|
+
const projs = selectedProjects()
|
|
272
|
+
return logs()
|
|
273
|
+
.filter((log) => {
|
|
274
|
+
const matchesSearch = !q
|
|
275
|
+
|| log.message.toLowerCase().includes(q)
|
|
276
|
+
|| (log.email?.subject?.toLowerCase().includes(q) ?? false)
|
|
277
|
+
|| (log.email?.recipient?.toLowerCase().includes(q) ?? false)
|
|
278
|
+
const matchesSource = src === 'all' || log.source.toLowerCase() === src.toLowerCase()
|
|
279
|
+
const matchesType = type === 'all' || log.type === type
|
|
280
|
+
const matchesProject = projs.length === 0 || (log.project !== undefined && projs.includes(log.project))
|
|
281
|
+
return matchesSearch && matchesSource && matchesProject && matchesType
|
|
282
|
+
})
|
|
283
|
+
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
const totalItems = derived(() => filteredLogs().length)
|
|
287
|
+
const totalPages = derived(() => Math.max(1, Math.ceil(totalItems() / itemsPerPageNum())))
|
|
288
|
+
|
|
289
|
+
const paginatedLogs = derived(() => {
|
|
290
|
+
const start = (currentPage() - 1) * itemsPerPageNum()
|
|
291
|
+
return filteredLogs().slice(start, start + itemsPerPageNum())
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
const visiblePages = derived(() => {
|
|
295
|
+
const max = Math.min(5, totalPages())
|
|
296
|
+
return Array.from({ length: max }, (_, i) => i + 1)
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
const selectedLog = derived(() => logs().find(l => l.id === selectedLogId()) ?? null)
|
|
300
|
+
|
|
301
|
+
const selectedProjectName = derived(() => {
|
|
302
|
+
const log = selectedLog()
|
|
303
|
+
if (!log?.project)
|
|
304
|
+
return 'N/A'
|
|
305
|
+
return projectsList.find(p => p.id === log.project)?.name ?? log.project
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const selectedMetadataJson = derived(() => {
|
|
309
|
+
const log = selectedLog()
|
|
310
|
+
return log ? JSON.stringify(log.metadata, null, 2) : ''
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
const hasActiveFilters = derived(() =>
|
|
314
|
+
searchTerm() !== '' || sourceFilter() !== 'all' || logTypeFilter() !== 'all' || selectedProjects().length > 0,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
effect(() => {
|
|
318
|
+
if (currentPage() > totalPages())
|
|
319
|
+
currentPage.set(totalPages())
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
effect(() => {
|
|
323
|
+
filteredLogs()
|
|
324
|
+
currentPage.set(1)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
function formatTime(ts: string) {
|
|
328
|
+
return new Date(ts).toLocaleTimeString()
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function formatDateTime(ts: string | undefined) {
|
|
332
|
+
return ts ? new Date(ts).toLocaleString() : ''
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function projectName(id: string | undefined) {
|
|
336
|
+
if (!id)
|
|
337
|
+
return ''
|
|
338
|
+
return projectsList.find(p => p.id === id)?.name ?? id
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function isProjectSelected(id: string) {
|
|
342
|
+
return selectedProjects().includes(id)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function toggleProject(id: string) {
|
|
346
|
+
const current = selectedProjects()
|
|
347
|
+
selectedProjects.set(current.includes(id) ? current.filter(p => p !== id) : [...current, id])
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function projectButtonClassFor(id: string) {
|
|
351
|
+
const base = 'inline-flex items-center px-3 py-1 font-medium text-sm rounded-full transition-colors'
|
|
352
|
+
const palette = projectPalette(id)
|
|
353
|
+
if (selectedProjects().includes(id))
|
|
354
|
+
return `${base} ${palette.bg} ${palette.text} ring-2 ${palette.ring}`
|
|
355
|
+
return `${base} bg-gray-100 dark:bg-neutral-700 text-gray-700 dark:text-neutral-200 hover:bg-gray-200 dark:hover:bg-neutral-600`
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function projectBadgeClassFor(id: string | undefined) {
|
|
359
|
+
const base = 'inline-flex px-2 font-semibold leading-5 text-xs rounded-full'
|
|
360
|
+
if (!id)
|
|
361
|
+
return base
|
|
362
|
+
const palette = projectPalette(id)
|
|
363
|
+
return `${base} ${palette.bg} ${palette.text}`
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function projectPalette(id: string) {
|
|
367
|
+
switch (id) {
|
|
368
|
+
case 'stacks': return { bg: 'bg-blue-100 dark:bg-blue-900', text: 'text-blue-800 dark:text-blue-200', ring: 'ring-blue-500' }
|
|
369
|
+
case 'rpx': return { bg: 'bg-purple-100 dark:bg-purple-900', text: 'text-purple-800 dark:text-purple-200', ring: 'ring-purple-500' }
|
|
370
|
+
case 'tlsx': return { bg: 'bg-green-100 dark:bg-green-900', text: 'text-green-800 dark:text-green-200', ring: 'ring-green-500' }
|
|
371
|
+
case 'dtsx': return { bg: 'bg-indigo-100 dark:bg-indigo-900', text: 'text-indigo-800 dark:text-indigo-200', ring: 'ring-indigo-500' }
|
|
372
|
+
case 'ts-collect': return { bg: 'bg-rose-100 dark:bg-rose-900', text: 'text-rose-800 dark:text-rose-200', ring: 'ring-rose-500' }
|
|
373
|
+
case 'vite-plugin-local': return { bg: 'bg-amber-100 dark:bg-amber-900', text: 'text-amber-800 dark:text-amber-200', ring: 'ring-amber-500' }
|
|
374
|
+
default: return { bg: 'bg-gray-100 dark:bg-neutral-700', text: 'text-gray-800 dark:text-neutral-200', ring: 'ring-gray-500' }
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function logRowClass(log: Log) {
|
|
379
|
+
const base = 'hover:bg-gray-50 dark:hover:bg-neutral-700/50 cursor-pointer'
|
|
380
|
+
switch (log.type) {
|
|
381
|
+
case 'error': return `${base} bg-red-50/50 dark:bg-red-900/10`
|
|
382
|
+
case 'success': return `${base} bg-green-50/50 dark:bg-green-900/10`
|
|
383
|
+
case 'warning': return `${base} bg-amber-50/50 dark:bg-amber-900/10`
|
|
384
|
+
case 'mail': return `${base} bg-purple-50/50 dark:bg-purple-900/10`
|
|
385
|
+
default: return base
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function logIconFor(type: Log['type']) {
|
|
390
|
+
switch (type) {
|
|
391
|
+
case 'error': return 'i-hugeicons-alert-02'
|
|
392
|
+
case 'info': return 'i-hugeicons-information-circle'
|
|
393
|
+
case 'success': return 'i-hugeicons-checkmark-circle-02'
|
|
394
|
+
case 'warning': return 'i-hugeicons-alert-02'
|
|
395
|
+
case 'mail': return 'i-hugeicons-mail-01'
|
|
396
|
+
default: return 'i-hugeicons-computer-terminal-01'
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function logIconColorFor(type: Log['type']) {
|
|
401
|
+
switch (type) {
|
|
402
|
+
case 'error': return 'text-red-500'
|
|
403
|
+
case 'info': return 'text-blue-500'
|
|
404
|
+
case 'success': return 'text-green-500'
|
|
405
|
+
case 'warning': return 'text-amber-500'
|
|
406
|
+
case 'mail': return 'text-purple-500'
|
|
407
|
+
default: return 'text-gray-500'
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function logIconClass(type: Log['type']) {
|
|
412
|
+
return `h-5 w-5 ${logIconFor(type)} ${logIconColorFor(type)}`
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const selectedLogIconClass = derived(() => {
|
|
416
|
+
const log = selectedLog()
|
|
417
|
+
if (!log)
|
|
418
|
+
return ''
|
|
419
|
+
return `h-5 w-5 ${logIconFor(log.type)} ${logIconColorFor(log.type)}`
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
const autoRefreshClass = derived(() => {
|
|
423
|
+
const base = 'flex gap-2 items-center px-4 py-2 rounded-lg'
|
|
424
|
+
return autoRefresh()
|
|
425
|
+
? `${base} bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200`
|
|
426
|
+
: `${base} bg-gray-100 text-gray-700 dark:bg-neutral-700 dark:text-neutral-200`
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
function pageButtonClass(page: number) {
|
|
430
|
+
const base = 'px-3 py-1 text-sm border border-gray-300 dark:border-neutral-600 rounded-md'
|
|
431
|
+
return page === currentPage()
|
|
432
|
+
? `${base} bg-blue-600 text-white border-blue-600`
|
|
433
|
+
: `${base} hover:bg-gray-100 dark:hover:bg-neutral-700 text-gray-900 dark:text-neutral-100`
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function selectLog(id: string) {
|
|
437
|
+
selectedLogId.set(id)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function closeModal() {
|
|
441
|
+
selectedLogId.set(null)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function goToPage(p: number) {
|
|
445
|
+
if (p >= 1 && p <= totalPages())
|
|
446
|
+
currentPage.set(p)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function nextPage() {
|
|
450
|
+
if (currentPage() < totalPages())
|
|
451
|
+
currentPage.set(currentPage() + 1)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function prevPage() {
|
|
455
|
+
if (currentPage() > 1)
|
|
456
|
+
currentPage.set(currentPage() - 1)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function resetFilters() {
|
|
460
|
+
searchTerm.set('')
|
|
461
|
+
sourceFilter.set('all')
|
|
462
|
+
logTypeFilter.set('all')
|
|
463
|
+
selectedProjects.set([])
|
|
464
|
+
currentPage.set(1)
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let refreshHandle: ReturnType<typeof setInterval> | null = null
|
|
468
|
+
|
|
469
|
+
function startAutoRefresh() {
|
|
470
|
+
if (refreshHandle)
|
|
471
|
+
return
|
|
472
|
+
refreshHandle = setInterval(() => {
|
|
473
|
+
// placeholder: in real usage this would refetch logs
|
|
474
|
+
}, 2000)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function stopAutoRefresh() {
|
|
478
|
+
if (refreshHandle) {
|
|
479
|
+
clearInterval(refreshHandle)
|
|
480
|
+
refreshHandle = null
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function toggleAutoRefresh() {
|
|
485
|
+
const next = !autoRefresh()
|
|
486
|
+
autoRefresh.set(next)
|
|
487
|
+
if (next)
|
|
488
|
+
startAutoRefresh()
|
|
489
|
+
else
|
|
490
|
+
stopAutoRefresh()
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function buildVolumeData() {
|
|
494
|
+
const labels = Array.from({ length: 24 }, (_, i) => `${i}:00`)
|
|
495
|
+
return {
|
|
496
|
+
labels,
|
|
497
|
+
datasets: [
|
|
498
|
+
{ label: 'Info', data: Array.from({ length: 24 }, () => Math.floor(Math.random() * 100) + 50), borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', fill: true },
|
|
499
|
+
{ label: 'Error', data: Array.from({ length: 24 }, () => Math.floor(Math.random() * 20)), borderColor: 'rgb(239, 68, 68)', backgroundColor: 'rgba(239, 68, 68, 0.1)', fill: true },
|
|
500
|
+
{ label: 'Success', data: Array.from({ length: 24 }, () => Math.floor(Math.random() * 40) + 20), borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', fill: true },
|
|
501
|
+
{ label: 'Mail', data: Array.from({ length: 24 }, () => Math.floor(Math.random() * 60) + 30), borderColor: 'rgb(139, 92, 246)', backgroundColor: 'rgba(139, 92, 246, 0.1)', fill: true },
|
|
502
|
+
{ label: 'Warning', data: Array.from({ length: 24 }, () => Math.floor(Math.random() * 15) + 5), borderColor: 'rgb(245, 158, 11)', backgroundColor: 'rgba(245, 158, 11, 0.1)', fill: true },
|
|
503
|
+
],
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const chartOptions = {
|
|
508
|
+
responsive: true,
|
|
509
|
+
maintainAspectRatio: false,
|
|
510
|
+
scales: {
|
|
511
|
+
y: { beginAtZero: true, grid: { color: 'rgba(200, 200, 200, 0.1)' }, ticks: { color: 'rgb(156, 163, 175)', font: { family: "'JetBrains Mono', monospace" } } },
|
|
512
|
+
x: { grid: { display: false }, ticks: { color: 'rgb(156, 163, 175)', font: { family: "'JetBrains Mono', monospace" } } },
|
|
513
|
+
},
|
|
514
|
+
plugins: {
|
|
515
|
+
legend: { display: true, position: 'top', align: 'end', labels: { color: 'rgb(156, 163, 175)', font: { family: "'JetBrains Mono', monospace" }, boxWidth: 12, padding: 15 } },
|
|
516
|
+
tooltip: { mode: 'index', intersect: false },
|
|
517
|
+
},
|
|
518
|
+
elements: { line: { tension: 0.4 } },
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
let chartHandle: ChartLike | null = null
|
|
522
|
+
|
|
523
|
+
onMount(async () => {
|
|
524
|
+
const { Chart, registerables } = await import('@stacksjs/charts')
|
|
525
|
+
Chart.register(...registerables)
|
|
526
|
+
const Ctor = Chart as unknown as ChartCtor
|
|
527
|
+
const handle = useChart({ Chart: Ctor, id: 'logs_volume_chart', type: 'line', data: buildVolumeData(), options: chartOptions })
|
|
528
|
+
chartHandle = handle.instance as ChartLike | null
|
|
529
|
+
if (autoRefresh())
|
|
530
|
+
startAutoRefresh()
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
onDestroy(() => {
|
|
534
|
+
stopAutoRefresh()
|
|
535
|
+
chartHandle?.destroy()
|
|
536
|
+
chartHandle = null
|
|
537
|
+
})
|
|
538
|
+
</script>
|
|
539
|
+
|
|
540
|
+
@endsection
|