@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.
Files changed (408) hide show
  1. package/TODO.md +21 -0
  2. package/ai/AGENTS.md +79 -0
  3. package/ai/README.md +45 -0
  4. package/ai/claude/launch.json +12 -0
  5. package/ai/skills/stacks-actions/SKILL.md +128 -0
  6. package/ai/skills/stacks-ai/SKILL.md +276 -0
  7. package/ai/skills/stacks-alias/SKILL.md +94 -0
  8. package/ai/skills/stacks-analytics/SKILL.md +91 -0
  9. package/ai/skills/stacks-api/SKILL.md +738 -0
  10. package/ai/skills/stacks-arrays/SKILL.md +277 -0
  11. package/ai/skills/stacks-auth/SKILL.md +422 -0
  12. package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
  13. package/ai/skills/stacks-brandkit/SKILL.md +811 -0
  14. package/ai/skills/stacks-browse/SKILL.md +127 -0
  15. package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
  16. package/ai/skills/stacks-browser/SKILL.md +145 -0
  17. package/ai/skills/stacks-buddy/SKILL.md +676 -0
  18. package/ai/skills/stacks-build/SKILL.md +163 -0
  19. package/ai/skills/stacks-cache/SKILL.md +125 -0
  20. package/ai/skills/stacks-calendar/SKILL.md +113 -0
  21. package/ai/skills/stacks-chat/SKILL.md +371 -0
  22. package/ai/skills/stacks-cli/SKILL.md +112 -0
  23. package/ai/skills/stacks-cloud/SKILL.md +192 -0
  24. package/ai/skills/stacks-cms/SKILL.md +217 -0
  25. package/ai/skills/stacks-collections/SKILL.md +82 -0
  26. package/ai/skills/stacks-commerce/SKILL.md +114 -0
  27. package/ai/skills/stacks-composables/SKILL.md +161 -0
  28. package/ai/skills/stacks-config/SKILL.md +144 -0
  29. package/ai/skills/stacks-configuration/SKILL.md +154 -0
  30. package/ai/skills/stacks-cron/SKILL.md +123 -0
  31. package/ai/skills/stacks-crosswind/SKILL.md +190 -0
  32. package/ai/skills/stacks-dashboard/SKILL.md +173 -0
  33. package/ai/skills/stacks-database/SKILL.md +286 -0
  34. package/ai/skills/stacks-datetime/SKILL.md +269 -0
  35. package/ai/skills/stacks-dependencies/SKILL.md +111 -0
  36. package/ai/skills/stacks-deploy/SKILL.md +102 -0
  37. package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
  38. package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
  39. package/ai/skills/stacks-design-output/SKILL.md +55 -0
  40. package/ai/skills/stacks-design-soft/SKILL.md +156 -0
  41. package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
  42. package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
  43. package/ai/skills/stacks-desktop/SKILL.md +78 -0
  44. package/ai/skills/stacks-development/SKILL.md +298 -0
  45. package/ai/skills/stacks-dns/SKILL.md +149 -0
  46. package/ai/skills/stacks-docs/SKILL.md +109 -0
  47. package/ai/skills/stacks-email/SKILL.md +236 -0
  48. package/ai/skills/stacks-enums/SKILL.md +100 -0
  49. package/ai/skills/stacks-env/SKILL.md +181 -0
  50. package/ai/skills/stacks-error-handling/SKILL.md +137 -0
  51. package/ai/skills/stacks-events/SKILL.md +228 -0
  52. package/ai/skills/stacks-faker/SKILL.md +158 -0
  53. package/ai/skills/stacks-git/SKILL.md +158 -0
  54. package/ai/skills/stacks-guard/SKILL.md +98 -0
  55. package/ai/skills/stacks-health/SKILL.md +75 -0
  56. package/ai/skills/stacks-http/SKILL.md +316 -0
  57. package/ai/skills/stacks-i18n/SKILL.md +198 -0
  58. package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
  59. package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
  60. package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
  61. package/ai/skills/stacks-investigate/SKILL.md +119 -0
  62. package/ai/skills/stacks-jobs/SKILL.md +136 -0
  63. package/ai/skills/stacks-lint/SKILL.md +184 -0
  64. package/ai/skills/stacks-listeners/SKILL.md +99 -0
  65. package/ai/skills/stacks-logging/SKILL.md +78 -0
  66. package/ai/skills/stacks-mail/SKILL.md +120 -0
  67. package/ai/skills/stacks-middleware/SKILL.md +249 -0
  68. package/ai/skills/stacks-migrations/SKILL.md +105 -0
  69. package/ai/skills/stacks-models/SKILL.md +267 -0
  70. package/ai/skills/stacks-new-feature/SKILL.md +206 -0
  71. package/ai/skills/stacks-notifications/SKILL.md +210 -0
  72. package/ai/skills/stacks-objects/SKILL.md +205 -0
  73. package/ai/skills/stacks-office-hours/SKILL.md +134 -0
  74. package/ai/skills/stacks-orm/SKILL.md +342 -0
  75. package/ai/skills/stacks-path/SKILL.md +118 -0
  76. package/ai/skills/stacks-payments/SKILL.md +373 -0
  77. package/ai/skills/stacks-plan-review/SKILL.md +152 -0
  78. package/ai/skills/stacks-plugins/SKILL.md +149 -0
  79. package/ai/skills/stacks-push/SKILL.md +376 -0
  80. package/ai/skills/stacks-query-builder/SKILL.md +128 -0
  81. package/ai/skills/stacks-queue/SKILL.md +559 -0
  82. package/ai/skills/stacks-realtime/SKILL.md +442 -0
  83. package/ai/skills/stacks-redesign/SKILL.md +182 -0
  84. package/ai/skills/stacks-registry/SKILL.md +58 -0
  85. package/ai/skills/stacks-repl/SKILL.md +80 -0
  86. package/ai/skills/stacks-retro/SKILL.md +122 -0
  87. package/ai/skills/stacks-review/SKILL.md +135 -0
  88. package/ai/skills/stacks-router/SKILL.md +231 -0
  89. package/ai/skills/stacks-routes/SKILL.md +105 -0
  90. package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
  91. package/ai/skills/stacks-scheduler/SKILL.md +363 -0
  92. package/ai/skills/stacks-search-engine/SKILL.md +112 -0
  93. package/ai/skills/stacks-security/SKILL.md +129 -0
  94. package/ai/skills/stacks-security-audit/SKILL.md +128 -0
  95. package/ai/skills/stacks-server/SKILL.md +458 -0
  96. package/ai/skills/stacks-shell/SKILL.md +62 -0
  97. package/ai/skills/stacks-slug/SKILL.md +87 -0
  98. package/ai/skills/stacks-sms/SKILL.md +385 -0
  99. package/ai/skills/stacks-socials/SKILL.md +303 -0
  100. package/ai/skills/stacks-storage/SKILL.md +576 -0
  101. package/ai/skills/stacks-strings/SKILL.md +416 -0
  102. package/ai/skills/stacks-stx/SKILL.md +176 -0
  103. package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
  104. package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
  105. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
  106. package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
  107. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
  108. package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
  109. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
  110. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
  111. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
  112. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
  113. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
  114. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
  115. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
  116. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
  117. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
  118. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
  119. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
  120. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
  121. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
  122. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
  123. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
  124. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
  125. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
  126. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
  127. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
  128. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
  129. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
  130. package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
  131. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
  132. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
  133. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
  134. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
  135. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
  136. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
  137. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
  138. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
  139. package/ai/skills/stacks-testing/SKILL.md +129 -0
  140. package/ai/skills/stacks-tunnel/SKILL.md +125 -0
  141. package/ai/skills/stacks-types/SKILL.md +178 -0
  142. package/ai/skills/stacks-ui/SKILL.md +246 -0
  143. package/ai/skills/stacks-utils/SKILL.md +444 -0
  144. package/ai/skills/stacks-validation/SKILL.md +371 -0
  145. package/ai/skills/stacks-whois/SKILL.md +315 -0
  146. package/assets/world-map-data.ts +121 -0
  147. package/bootstrap.ts +114 -0
  148. package/docs/api-examples.md +46 -0
  149. package/docs/index.md +24 -0
  150. package/docs/markdown-examples.md +87 -0
  151. package/functions/analytics.ts +97 -0
  152. package/functions/api.ts +143 -0
  153. package/functions/auth.ts +208 -0
  154. package/functions/billing/payments.ts +149 -0
  155. package/functions/blog.ts +120 -0
  156. package/functions/cms/categorizables.ts +107 -0
  157. package/functions/cms/pages.ts +108 -0
  158. package/functions/cms/posts.ts +100 -0
  159. package/functions/cms/taggables.ts +102 -0
  160. package/functions/commerce/coupons.ts +128 -0
  161. package/functions/commerce/customers.ts +128 -0
  162. package/functions/commerce/gift-cards.ts +119 -0
  163. package/functions/commerce/orders.ts +112 -0
  164. package/functions/commerce/payments.ts +119 -0
  165. package/functions/commerce/products/categories.ts +123 -0
  166. package/functions/commerce/products/manufacturers.ts +123 -0
  167. package/functions/commerce/products/products.ts +123 -0
  168. package/functions/commerce/products/reviews.ts +123 -0
  169. package/functions/commerce/products/units.ts +123 -0
  170. package/functions/commerce/products/variants.ts +123 -0
  171. package/functions/commerce/shippings/delivery-routes.ts +123 -0
  172. package/functions/commerce/shippings/digital-deliveries.ts +119 -0
  173. package/functions/commerce/shippings/drivers.ts +123 -0
  174. package/functions/commerce/shippings/license-keys.ts +123 -0
  175. package/functions/commerce/shippings/shipping-methods.ts +123 -0
  176. package/functions/commerce/shippings/shipping-rates.ts +119 -0
  177. package/functions/commerce/shippings/shipping-zones.ts +119 -0
  178. package/functions/commerce/taxes.ts +119 -0
  179. package/functions/commerce/waitlist/products.ts +123 -0
  180. package/functions/commerce/waitlist/restaurants.ts +123 -0
  181. package/functions/craft.ts +107 -0
  182. package/functions/dashboard.ts +153 -0
  183. package/functions/inbox.ts +95 -0
  184. package/functions/jobs.ts +86 -0
  185. package/functions/monitoring/errors.ts +295 -0
  186. package/functions/queue.ts +111 -0
  187. package/functions/realtime/websockets.ts +96 -0
  188. package/functions/realtime.ts +52 -0
  189. package/functions/releases.ts +49 -0
  190. package/functions/search.ts +126 -0
  191. package/functions/toasts.ts +95 -0
  192. package/functions/uploads.ts +216 -0
  193. package/ide/.gitignore +4 -0
  194. package/ide/cursor/rules/auto-imports.mdc +574 -0
  195. package/ide/cursor/rules/code-style.mdc +12 -0
  196. package/ide/cursor/rules/documentation.mdc +9 -0
  197. package/ide/cursor/rules/error-handling-validation.mdc +11 -0
  198. package/ide/cursor/rules/key-conventions.mdc +11 -0
  199. package/ide/cursor/rules/project-structure.mdc +169 -0
  200. package/ide/cursor/rules/readme.mdc +318 -0
  201. package/ide/cursor/rules/syntax-formatting.mdc +9 -0
  202. package/ide/cursor/rules/testing.mdc +10 -0
  203. package/ide/cursor/rules/typescript.mdc +9 -0
  204. package/ide/cursor/rules/ui-styling.mdc +0 -0
  205. package/ide/dictionary.txt +397 -0
  206. package/ide/jetbrains/.fleet/settings.json +4 -0
  207. package/ide/jetbrains/.idea/.gitignore +5 -0
  208. package/ide/jetbrains/.idea/.name +1 -0
  209. package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
  210. package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
  211. package/ide/jetbrains/.idea/modules.xml +8 -0
  212. package/ide/jetbrains/.idea/stacks.iml +22 -0
  213. package/ide/jetbrains/.idea/vcs.xml +6 -0
  214. package/ide/jetbrains/.idea/webResources.xml +14 -0
  215. package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
  216. package/ide/jetbrains/installed.txt +4 -0
  217. package/ide/jetbrains/options/github-copilot.xml +5 -0
  218. package/ide/jetbrains/options/nodejs.xml +7 -0
  219. package/ide/jetbrains/options/templates.xml +124 -0
  220. package/ide/jetbrains/templates/JavaScript.xml +6 -0
  221. package/ide/jetbrains/templates/Stacks.xml +8 -0
  222. package/ide/vscode/.vscode/README.md +23 -0
  223. package/ide/vscode/.vscode/extensions.json +5 -0
  224. package/ide/vscode/.vscode/settings.json +176 -0
  225. package/ide/vscode/.vscode/stacks.code-snippets +181 -0
  226. package/ide/vscode/LICENSE.md +21 -0
  227. package/ide/vscode/README.md +36 -0
  228. package/ide/vscode/logo.png +0 -0
  229. package/ide/vscode/package.json +79 -0
  230. package/ide/zed/.zed/settings.json +139 -0
  231. package/lang/README.md +28 -0
  232. package/lang/de.yml +14 -0
  233. package/lang/en.yml +15 -0
  234. package/package.json +19 -3
  235. package/project/bootstrap +161 -0
  236. package/project/buddy +175 -0
  237. package/project/storage/framework/tsconfig.app.json +50 -0
  238. package/project/storage/framework/tsconfig.base.json +58 -0
  239. package/routes/core.ts +78 -0
  240. package/routes/dashboard-api.ts +233 -0
  241. package/routes/dashboard.ts +739 -0
  242. package/routes/email.ts +129 -0
  243. package/stores/[name].stx +16 -0
  244. package/stores/git.ts +71 -0
  245. package/stores/payment.ts +474 -0
  246. package/stores/queue.ts +43 -0
  247. package/stores/user.ts +29 -0
  248. package/stx-components-plugin.ts +25 -0
  249. package/styles/design-tokens.css +597 -0
  250. package/types/dashboard.ts +70 -0
  251. package/types/defaults.ts +438 -0
  252. package/vcs/github/CODE_OF_CONDUCT.md +83 -0
  253. package/vcs/github/CONTRIBUTING.md +187 -0
  254. package/vcs/github/EXPLANATIONS.md +41 -0
  255. package/vcs/github/FUNDING.yml +1 -0
  256. package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  257. package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
  258. package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  259. package/vcs/github/SECURITY.md +70 -0
  260. package/vcs/github/renovate.json +5 -0
  261. package/vcs/github/stale.yml +14 -0
  262. package/vcs/github/workflows/README.md +16 -0
  263. package/vcs/github/workflows/ci.yml +114 -0
  264. package/vcs/github/workflows/export-size.yml +25 -0
  265. package/vcs/github/workflows/labeler.yml +13 -0
  266. package/vcs/github/workflows/release.yml +219 -0
  267. package/views/[...all].stx +8 -0
  268. package/views/about.md +3 -0
  269. package/views/auth/login.stx +1 -0
  270. package/views/auth/signup.stx +85 -0
  271. package/views/dashboard/.discovered-models.json +542 -0
  272. package/views/dashboard/AUDIT.md +904 -0
  273. package/views/dashboard/[...all].stx +89 -0
  274. package/views/dashboard/access-tokens/index.stx +177 -0
  275. package/views/dashboard/actions/index.stx +129 -0
  276. package/views/dashboard/analytics/blog/index.stx +356 -0
  277. package/views/dashboard/analytics/browsers/index.stx +263 -0
  278. package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
  279. package/views/dashboard/analytics/commerce/web/index.stx +379 -0
  280. package/views/dashboard/analytics/countries/index.stx +289 -0
  281. package/views/dashboard/analytics/devices/index.stx +305 -0
  282. package/views/dashboard/analytics/events/index.stx +536 -0
  283. package/views/dashboard/analytics/index.stx +88 -0
  284. package/views/dashboard/analytics/marketing/index.stx +315 -0
  285. package/views/dashboard/analytics/pages/index.stx +271 -0
  286. package/views/dashboard/analytics/referrers/index.stx +319 -0
  287. package/views/dashboard/analytics/web/index.stx +356 -0
  288. package/views/dashboard/buddy/index.stx +198 -0
  289. package/views/dashboard/ci/index.stx +462 -0
  290. package/views/dashboard/cloud/index.stx +452 -0
  291. package/views/dashboard/commands/index.stx +295 -0
  292. package/views/dashboard/commerce/categories/index.stx +406 -0
  293. package/views/dashboard/commerce/coupons/index.stx +485 -0
  294. package/views/dashboard/commerce/customers/index.stx +410 -0
  295. package/views/dashboard/commerce/dashboard/index.stx +287 -0
  296. package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
  297. package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
  298. package/views/dashboard/commerce/delivery/drivers.stx +397 -0
  299. package/views/dashboard/commerce/delivery/index.stx +18 -0
  300. package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
  301. package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
  302. package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
  303. package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
  304. package/views/dashboard/commerce/delivery/tabs.ts +25 -0
  305. package/views/dashboard/commerce/gift-cards/index.stx +561 -0
  306. package/views/dashboard/commerce/manufacturers/index.stx +308 -0
  307. package/views/dashboard/commerce/orders/index.stx +247 -0
  308. package/views/dashboard/commerce/payments/index.stx +535 -0
  309. package/views/dashboard/commerce/pos/index.stx +653 -0
  310. package/views/dashboard/commerce/printers/devices/index.stx +273 -0
  311. package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
  312. package/views/dashboard/commerce/products/detail.stx +563 -0
  313. package/views/dashboard/commerce/products/index.stx +370 -0
  314. package/views/dashboard/commerce/reviews/index.stx +656 -0
  315. package/views/dashboard/commerce/reviews/index.ts +0 -0
  316. package/views/dashboard/commerce/taxes/index.stx +377 -0
  317. package/views/dashboard/commerce/units/index.stx +317 -0
  318. package/views/dashboard/commerce/variants/index.stx +319 -0
  319. package/views/dashboard/commerce/waitlist/products.stx +942 -0
  320. package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
  321. package/views/dashboard/components/index.stx +330 -0
  322. package/views/dashboard/composables/index.ts +19 -0
  323. package/views/dashboard/composables/useChart.ts +77 -0
  324. package/views/dashboard/composables/useNavigation.ts +99 -0
  325. package/views/dashboard/composables/useRole.ts +58 -0
  326. package/views/dashboard/composables/useTheme.ts +74 -0
  327. package/views/dashboard/content/authors/index.stx +171 -0
  328. package/views/dashboard/content/blog/index.stx +493 -0
  329. package/views/dashboard/content/categories/index.stx +169 -0
  330. package/views/dashboard/content/comments/index.stx +189 -0
  331. package/views/dashboard/content/dashboard.stx +383 -0
  332. package/views/dashboard/content/files/index.stx +706 -0
  333. package/views/dashboard/content/pages/index.stx +174 -0
  334. package/views/dashboard/content/posts/index.stx +269 -0
  335. package/views/dashboard/content/seo/index.stx +240 -0
  336. package/views/dashboard/content/tags/index.stx +167 -0
  337. package/views/dashboard/data/activity/index.stx +261 -0
  338. package/views/dashboard/data/dashboard/index.stx +116 -0
  339. package/views/dashboard/data/subscribers.stx +270 -0
  340. package/views/dashboard/data/teams.stx +275 -0
  341. package/views/dashboard/data/users.stx +279 -0
  342. package/views/dashboard/dependencies/index.stx +178 -0
  343. package/views/dashboard/deployments/[id].stx +234 -0
  344. package/views/dashboard/deployments/index.stx +9 -0
  345. package/views/dashboard/dns/index.stx +163 -0
  346. package/views/dashboard/environment/index.stx +283 -0
  347. package/views/dashboard/errors/index.stx +274 -0
  348. package/views/dashboard/forgot-password.stx +57 -0
  349. package/views/dashboard/functions/index.stx +159 -0
  350. package/views/dashboard/health/index.stx +248 -0
  351. package/views/dashboard/inbox/activity.stx +350 -0
  352. package/views/dashboard/inbox/index.stx +452 -0
  353. package/views/dashboard/inbox/settings.stx +290 -0
  354. package/views/dashboard/index.stx +252 -0
  355. package/views/dashboard/insights/index.stx +529 -0
  356. package/views/dashboard/jobs/[id].stx +430 -0
  357. package/views/dashboard/jobs/history.stx +222 -0
  358. package/views/dashboard/jobs/index.stx +214 -0
  359. package/views/dashboard/kanban/[id].stx +899 -0
  360. package/views/dashboard/kanban/index.stx +260 -0
  361. package/views/dashboard/layouts/default.stx +565 -0
  362. package/views/dashboard/layouts/guest.stx +10 -0
  363. package/views/dashboard/login.stx +48 -0
  364. package/views/dashboard/logs/index.stx +540 -0
  365. package/views/dashboard/mailboxes/index.stx +149 -0
  366. package/views/dashboard/management/permissions/index.stx +490 -0
  367. package/views/dashboard/marketing/campaigns/index.stx +604 -0
  368. package/views/dashboard/marketing/lists/index.stx +514 -0
  369. package/views/dashboard/marketing/reviews/index.stx +475 -0
  370. package/views/dashboard/marketing/social-posts/index.stx +560 -0
  371. package/views/dashboard/models/[model].stx +195 -0
  372. package/views/dashboard/models/index.stx +159 -0
  373. package/views/dashboard/monitoring/errors/index.stx +415 -0
  374. package/views/dashboard/notifications/dashboard.stx +383 -0
  375. package/views/dashboard/notifications/email.stx +336 -0
  376. package/views/dashboard/notifications/history.stx +373 -0
  377. package/views/dashboard/notifications/sms.stx +332 -0
  378. package/views/dashboard/packages/index.stx +195 -0
  379. package/views/dashboard/queries/[id].stx +381 -0
  380. package/views/dashboard/queries/history.stx +227 -0
  381. package/views/dashboard/queries/index.stx +335 -0
  382. package/views/dashboard/queries/slow.stx +318 -0
  383. package/views/dashboard/queue/index.stx +427 -0
  384. package/views/dashboard/realtime/index.stx +429 -0
  385. package/views/dashboard/register.stx +46 -0
  386. package/views/dashboard/releases/index.stx +389 -0
  387. package/views/dashboard/requests/index.stx +462 -0
  388. package/views/dashboard/serverless/index.stx +475 -0
  389. package/views/dashboard/servers/[id].stx +299 -0
  390. package/views/dashboard/servers/index.stx +483 -0
  391. package/views/dashboard/settings/billing.stx +50 -0
  392. package/views/dashboard/settings/index.stx +256 -0
  393. package/views/dashboard/settings/mail.stx +252 -0
  394. package/views/dashboard/stores/auth.ts +123 -0
  395. package/views/dashboard/stores/ci.ts +342 -0
  396. package/views/dashboard/stores/index.ts +129 -0
  397. package/views/dashboard/stores/kanban.ts +723 -0
  398. package/views/dashboard/stores/rbac.ts +350 -0
  399. package/views/dashboard/stx.config.ts +34 -0
  400. package/views/dashboard/teams/[id].stx +170 -0
  401. package/views/forum/category.stx +92 -0
  402. package/views/forum/index.stx +209 -0
  403. package/views/forum/new-topic.stx +113 -0
  404. package/views/forum/profile.stx +1 -0
  405. package/views/forum/topic.stx +143 -0
  406. package/views/hello-world/[name].stx +47 -0
  407. package/views/index.stx +21 -0
  408. package/views/system-tray/index.stx +147 -0
@@ -0,0 +1,318 @@
1
+ @extends('layouts/default')
2
+
3
+ @section('content')
4
+ @title('Dashboard - Slow Queries')
5
+ <div class="min-h-screen">
6
+ <header class="flex sticky top-0 z-10 flex-wrap gap-6 items-center justify-between px-4 py-4 sm:px-6 lg:px-8 bg-white dark:bg-neutral-900 shadow-sm">
7
+ <div>
8
+ <h1 class="font-semibold leading-7 text-gray-900 text-lg dark:text-white">Slow Queries</h1>
9
+ <p class="mt-1 leading-6 text-gray-500 text-sm dark:text-neutral-400">Identify and optimize slow database queries</p>
10
+ </div>
11
+ <div class="flex flex-wrap gap-3 items-center">
12
+ <div class="inline-flex rounded-md shadow-sm">
13
+ <button type="button" @click="setTimeRange('day')" class="inline-flex relative items-center px-3 py-2 font-medium text-sm rounded-l-md ring-1 ring-gray-300 ring-inset dark:ring-neutral-700 {{ timeRange() === 'day' ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 dark:bg-neutral-800 dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700' }}">Day</button>
14
+ <button type="button" @click="setTimeRange('week')" class="inline-flex relative items-center -ml-px px-3 py-2 font-medium text-sm ring-1 ring-gray-300 ring-inset dark:ring-neutral-700 {{ timeRange() === 'week' ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 dark:bg-neutral-800 dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700' }}">Week</button>
15
+ <button type="button" @click="setTimeRange('month')" class="inline-flex relative items-center -ml-px px-3 py-2 font-medium text-sm rounded-r-md ring-1 ring-gray-300 ring-inset dark:ring-neutral-700 {{ timeRange() === 'month' ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 dark:bg-neutral-800 dark:text-neutral-200 hover:bg-gray-50 dark:hover:bg-neutral-700' }}">Month</button>
16
+ </div>
17
+ <div>
18
+ <select id="connection" name="connection" x-model="selectedConnection" class="block pl-3 pr-10 py-2 w-full text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 border-gray-300 rounded-md dark:border-neutral-700 focus:border-blue-600 focus:outline-none focus:ring-blue-600">
19
+ <option value="all">All connections</option>
20
+ <option value="mysql">MySQL</option>
21
+ <option value="postgres">PostgreSQL</option>
22
+ <option value="sqlite">SQLite</option>
23
+ <option value="mongodb">MongoDB</option>
24
+ </select>
25
+ </div>
26
+ <div>
27
+ <div class="flex items-center border-gray-300 rounded-md dark:border-neutral-700">
28
+ <span class="pl-3 pr-1 text-gray-600 text-sm dark:text-neutral-400">Threshold:</span>
29
+ <input type="number" x-model.number="thresholdMs" min="1" step="5" class="py-2 w-20 text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 border-gray-300 rounded-md dark:border-neutral-700 focus:border-blue-600 focus:outline-none focus:ring-blue-600" />
30
+ <span class="pl-1 pr-3 text-gray-600 text-sm dark:text-neutral-400">ms</span>
31
+ </div>
32
+ </div>
33
+ <div class="relative w-full sm:w-auto">
34
+ <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
35
+ <div class="h-5 w-5 text-gray-400 i-hugeicons-search-01"></div>
36
+ </div>
37
+ <input type="text" x-model="searchQuery" placeholder="Search queries..." class="block pl-10 py-2 w-full text-sm dark:text-neutral-200 bg-white dark:bg-neutral-800 border-gray-300 rounded-md dark:border-neutral-700 focus:border-blue-600 focus:outline-none focus:ring-blue-600" />
38
+ </div>
39
+ </div>
40
+ </header>
41
+
42
+ <main class="px-4 py-8 sm:px-6 lg:px-8">
43
+ <div class="grid gap-5 grid-cols-1 sm:grid-cols-2 md:grid-cols-4">
44
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
45
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-400">Total Slow Queries</dt>
46
+ <dd class="mt-1 font-semibold text-3xl text-yellow-600 tracking-tight dark:text-yellow-400">{{ totalCount() }}</dd>
47
+ </div>
48
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
49
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-400">Avg Duration</dt>
50
+ <dd class="mt-1 font-semibold text-3xl text-gray-900 tracking-tight dark:text-white">{{ avgDurationLabel() }}</dd>
51
+ </div>
52
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
53
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-400">Max Duration</dt>
54
+ <dd class="mt-1 font-semibold text-3xl text-red-600 tracking-tight dark:text-red-400">{{ maxDurationLabel() }}</dd>
55
+ </div>
56
+ <div class="overflow-hidden px-4 py-5 sm:p-6 bg-white dark:bg-neutral-800 rounded-lg shadow">
57
+ <dt class="font-medium text-gray-500 text-sm truncate dark:text-neutral-400">Most Affected Table</dt>
58
+ <dd class="mt-1 font-semibold text-3xl text-blue-600 tracking-tight dark:text-blue-400">{{ topAffectedTable() }}</dd>
59
+ </div>
60
+ </div>
61
+
62
+ <div class="mt-8">
63
+ <div class="relative">
64
+ <div :show="isLoading" class="flex absolute inset-0 z-10 items-center justify-center bg-white/50 dark:bg-neutral-900/50">
65
+ <div class="h-8 w-8 text-blue-600 dark:text-blue-400 animate-spin i-hugeicons-loading-01"></div>
66
+ </div>
67
+
68
+ <div class="overflow-hidden bg-white dark:bg-neutral-900 sm:rounded-md shadow">
69
+ <ul role="list" class="divide-gray-200 divide-y dark:divide-neutral-700">
70
+ <template :for="query in filteredQueries">
71
+ <li class="hover:bg-gray-50 dark:hover:bg-neutral-800 cursor-pointer group" @click="toggleQueryDetails('{{ query.id }}')">
72
+ <div class="px-4 py-4 sm:px-6">
73
+ <div class="flex items-center justify-between">
74
+ <div class="flex items-center space-x-3">
75
+ <p class="font-medium text-blue-600 text-sm truncate dark:text-blue-400">{{ querySource(query) }}</p>
76
+ <span class="inline-flex items-center px-2 py-1 font-medium text-xs text-yellow-700 dark:text-yellow-300 bg-yellow-50 dark:bg-yellow-900/50 ring-1 ring-inset ring-yellow-600/20 rounded-md">{{ formatDuration(query.duration) }}</span>
77
+ </div>
78
+ <div class="flex flex-shrink-0 ml-2">
79
+ <div class="h-5 w-5 text-gray-400 duration-200 transition-transform i-hugeicons-chevron-down {{ isExpanded(query.id) ? 'transform rotate-180' : '' }}"></div>
80
+ </div>
81
+ </div>
82
+ <div class="sm:flex sm:justify-between mt-2">
83
+ <div class="sm:flex">
84
+ <p class="flex items-center text-gray-500 text-sm dark:text-neutral-400">
85
+ <span class="font-mono text-xs truncate">{{ formatQuery(query.query) }}</span>
86
+ </p>
87
+ </div>
88
+ <div class="flex items-center mt-2 sm:mt-0 text-gray-500 text-sm dark:text-neutral-400">
89
+ <div class="mr-1.5 h-4 w-4 i-hugeicons-calendar"></div>
90
+ <p>{{ query.executed_at }}</p>
91
+ </div>
92
+ </div>
93
+ <div class="flex flex-wrap gap-1 mt-2">
94
+ <template :for="table in query.affected_tables">
95
+ <span class="inline-flex items-center px-2 py-1 font-medium text-blue-700 text-xs dark:text-blue-300 bg-blue-50 dark:bg-blue-900/20 ring-1 ring-blue-700/10 ring-inset rounded-md dark:ring-blue-400/30">{{ table }}</span>
96
+ </template>
97
+ </div>
98
+ </div>
99
+
100
+ <div :show="isExpanded('{{ query.id }}')" class="px-4 py-4 sm:px-6 bg-gray-50 dark:bg-neutral-800 border-gray-200 border-t dark:border-neutral-700">
101
+ <div class="grid gap-4 grid-cols-1 md:grid-cols-3">
102
+ <div class="md:col-span-2">
103
+ <h4 class="mb-2 font-medium text-gray-900 text-sm dark:text-white">Full Query</h4>
104
+ <div class="relative">
105
+ <pre class="overflow-x-auto mt-1 p-3 font-mono text-gray-100 text-xs bg-gray-800 rounded-md sql-highlight">{{ query.query }}</pre>
106
+ <button @click.stop="copyQuery('{{ query.id }}')" class="absolute right-2 top-2 p-1.5 text-gray-300 hover:text-white rounded-md {{ copiedQueryId() === query.id ? 'bg-green-700 hover:bg-green-600' : 'bg-gray-700 hover:bg-gray-600' }}">
107
+ <div class="h-4 w-4 {{ copiedQueryId() === query.id ? 'i-hugeicons-checkmark' : 'i-hugeicons-copy-01' }}"></div>
108
+ </button>
109
+ </div>
110
+
111
+ <h4 class="mb-2 mt-4 font-medium text-gray-900 text-sm dark:text-white">Bindings</h4>
112
+ <div class="mt-1 p-3 bg-gray-100 dark:bg-neutral-700 rounded-md">
113
+ <pre :show="{{ query.bindings && query.bindings.length ? 'true' : 'false' }}" class="overflow-x-auto font-mono text-gray-800 text-xs dark:text-neutral-200">{{ JSON.stringify(query.bindings, null, 2) }}</pre>
114
+ <p :show="{{ !query.bindings || !query.bindings.length ? 'true' : 'false' }}" class="text-gray-500 text-xs dark:text-neutral-400">No bindings</p>
115
+ </div>
116
+
117
+ <h4 class="mb-2 mt-4 font-medium text-gray-900 text-sm dark:text-white">Explain Plan</h4>
118
+ <div class="mt-1 p-3 bg-gray-100 dark:bg-neutral-700 rounded-md">
119
+ <pre class="overflow-x-auto font-mono text-gray-800 text-xs dark:text-neutral-200">{{ query.explain_plan }}</pre>
120
+ </div>
121
+ </div>
122
+
123
+ <div>
124
+ <h4 class="mb-2 font-medium text-gray-900 text-sm dark:text-white">Optimization Suggestions</h4>
125
+ <ul class="mt-1 space-y-2">
126
+ <template :for="suggestion in query.optimization_suggestions">
127
+ <li class="flex items-start">
128
+ <div class="flex-shrink-0 mr-2 mt-0.5 h-5 w-5 text-yellow-500 i-hugeicons-lightbulb-02"></div>
129
+ <span class="text-gray-700 text-sm dark:text-neutral-300">{{ suggestion }}</span>
130
+ </li>
131
+ </template>
132
+ </ul>
133
+
134
+ <h4 class="mb-2 mt-4 font-medium text-gray-900 text-sm dark:text-white">Source</h4>
135
+ <div class="mt-1">
136
+ <p class="text-gray-700 text-sm dark:text-neutral-300">{{ query.file }}:{{ query.line }}</p>
137
+ </div>
138
+
139
+ <h4 class="mb-2 mt-4 font-medium text-gray-900 text-sm dark:text-white">Index Information</h4>
140
+ <div class="mt-1">
141
+ <div class="mb-2">
142
+ <h5 class="font-medium text-gray-600 text-xs dark:text-neutral-400">Used Indexes</h5>
143
+ <div :show="{{ query.indexes_used && query.indexes_used.length ? 'true' : 'false' }}" class="mt-1">
144
+ <template :for="index in query.indexes_used">
145
+ <span class="inline-flex items-center mb-2 mr-2 px-2 py-1 font-medium text-green-700 text-xs dark:text-green-300 bg-green-50 dark:bg-green-900/20 ring-1 ring-green-700/10 ring-inset rounded-md dark:ring-green-400/30">{{ index }}</span>
146
+ </template>
147
+ </div>
148
+ <p :show="{{ !query.indexes_used || !query.indexes_used.length ? 'true' : 'false' }}" class="text-gray-500 text-xs dark:text-neutral-400">No indexes used</p>
149
+ </div>
150
+
151
+ <div>
152
+ <h5 class="font-medium text-gray-600 text-xs dark:text-neutral-400">Missing Indexes</h5>
153
+ <div :show="{{ query.missing_indexes && query.missing_indexes.length ? 'true' : 'false' }}" class="mt-1">
154
+ <template :for="index in query.missing_indexes">
155
+ <span class="inline-flex items-center mb-2 mr-2 px-2 py-1 font-medium text-red-700 text-xs dark:text-red-300 bg-red-50 dark:bg-red-900/20 ring-1 ring-inset ring-red-700/10 rounded-md dark:ring-red-400/30">{{ index }}</span>
156
+ </template>
157
+ </div>
158
+ <p :show="{{ !query.missing_indexes || !query.missing_indexes.length ? 'true' : 'false' }}" class="text-gray-500 text-xs dark:text-neutral-400">No missing indexes identified</p>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </li>
165
+ </template>
166
+ <li :show="hasNoQueries" class="px-4 py-6 sm:px-6 text-center text-gray-500 text-sm dark:text-neutral-400">No slow queries found matching your criteria.</li>
167
+ </ul>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </main>
172
+ </div>
173
+
174
+ <script client>
175
+ interface SlowQueryRecord {
176
+ id: string
177
+ query: string
178
+ duration: number
179
+ normalized_query: string
180
+ connection: string
181
+ status: 'slow'
182
+ executed_at: string
183
+ bindings?: unknown[]
184
+ model?: string
185
+ method?: string
186
+ file?: string
187
+ line?: number
188
+ memory_usage?: number
189
+ rows_affected?: number
190
+ tags?: string[]
191
+ optimization_suggestions?: string[]
192
+ affected_tables?: string[]
193
+ indexes_used?: string[]
194
+ missing_indexes?: string[]
195
+ explain_plan?: string
196
+ }
197
+
198
+ const slowQueries = state<SlowQueryRecord[]>([
199
+ { id: '1', query: 'SELECT p.*, c.name as category_name FROM posts p JOIN categories c ON p.category_id = c.id WHERE p.published_at IS NOT NULL ORDER BY p.published_at DESC LIMIT 10', normalized_query: 'SELECT p.*, c.name as category_name FROM posts p JOIN categories c ON p.category_id = c.id WHERE p.published_at IS NOT NULL ORDER BY p.published_at DESC LIMIT ?', duration: 45.7, connection: 'mysql', status: 'slow', executed_at: '2024-03-14 10:15:30', bindings: [10], model: 'Post', method: 'getRecentPublishedWithCategory', file: 'app/Models/Post.php', line: 78, memory_usage: 5.8, rows_affected: 10, tags: ['content', 'frontend'], affected_tables: ['posts', 'categories'], indexes_used: ['categories.primary'], missing_indexes: ['posts.published_at'], optimization_suggestions: ['Add index on posts.published_at column', 'Consider paginating results', 'Limit selected columns instead of using SELECT *'], explain_plan: 'EXPLAIN: id-1, select_type-SIMPLE, table-p, partitions-NULL, type-ALL, possible_keys-NULL, key-NULL, key_len-NULL, ref-NULL, rows-200, filtered-50.00, Extra-Using where; Using filesort...' },
200
+ { id: '2', query: 'SELECT COUNT(*) FROM orders WHERE status = ?', normalized_query: 'SELECT COUNT(*) FROM orders WHERE status = ?', duration: 78.4, connection: 'mysql', status: 'slow', executed_at: '2024-03-14 10:08:22', bindings: ['pending'], model: 'Order', method: 'countPendingOrders', file: 'app/Models/Order.php', line: 67, memory_usage: 3.1, rows_affected: 1, tags: ['reporting'], affected_tables: ['orders'], indexes_used: [], missing_indexes: ['orders.status'], optimization_suggestions: ['Add index on orders.status column', 'Consider caching count results', 'Use Redis counters for high-frequency status counts'], explain_plan: 'EXPLAIN: id-1, select_type-SIMPLE, table-orders, partitions-NULL, type-ALL, possible_keys-NULL, key-NULL, key_len-NULL, ref-NULL, rows-10000, filtered-10.00, Extra-Using where...' },
201
+ { id: '3', query: 'SELECT AVG(total) FROM orders WHERE created_at BETWEEN ? AND ?', normalized_query: 'SELECT AVG(total) FROM orders WHERE created_at BETWEEN ? AND ?', duration: 65.2, connection: 'mysql', status: 'slow', executed_at: '2024-03-14 10:05:11', bindings: ['2023-03-01 00:00:00', '2023-03-31 23:59:59'], model: 'Order', method: 'getAverageOrderTotal', file: 'app/Reports/MonthlyReport.php', line: 134, memory_usage: 4.2, rows_affected: 1, tags: ['reporting', 'monthly'], affected_tables: ['orders'], indexes_used: [], missing_indexes: ['orders.created_at'], optimization_suggestions: ['Add index on orders.created_at column', 'Precalculate and store aggregate data for reports', 'Consider using materialized views or summary tables'], explain_plan: 'EXPLAIN: id-1, select_type-SIMPLE, table-orders, partitions-NULL, type-ALL, possible_keys-NULL, key-NULL, key_len-NULL, ref-NULL, rows-10000, filtered-33.33, Extra-Using where...' },
202
+ { id: '4', query: 'TRUNCATE TABLE cache', normalized_query: 'TRUNCATE TABLE cache', duration: 125.3, connection: 'mysql', status: 'slow', executed_at: '2024-03-14 09:55:00', bindings: [], method: 'flush', file: 'app/Console/Commands/CacheClear.php', line: 28, memory_usage: 1.5, rows_affected: 0, tags: ['cache', 'console'], affected_tables: ['cache'], indexes_used: [], missing_indexes: [], optimization_suggestions: ['Schedule cache clearing during low traffic periods', 'Consider incremental cache invalidation instead of truncating', 'Partition cache table for more efficient truncation'], explain_plan: 'N/A - DDL Operation' },
203
+ { id: '5', query: 'SELECT u.*, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count FROM users u WHERE u.created_at > ? ORDER BY order_count DESC LIMIT 50', normalized_query: 'SELECT u.*, (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count FROM users u WHERE u.created_at > ? ORDER BY order_count DESC LIMIT ?', duration: 230.5, connection: 'mysql', status: 'slow', executed_at: '2024-03-14 09:45:00', bindings: ['2023-03-14 09:45:00', 50], model: 'User', method: 'getTopNewCustomers', file: 'app/Reports/CustomerReport.php', line: 58, memory_usage: 8.7, rows_affected: 50, tags: ['reporting', 'customers'], affected_tables: ['users', 'orders'], indexes_used: ['users.created_at_index', 'orders.primary'], missing_indexes: ['orders.user_id'], optimization_suggestions: ['Add index on orders.user_id', 'Replace correlated subquery with JOIN and GROUP BY', 'Use a materialized view for frequent reporting', 'Pre-compute order counts in a denormalized column or table'], explain_plan: 'EXPLAIN: id-1, select_type-PRIMARY, table-u, partitions-NULL, type-range, possible_keys-created_at_index, key-created_at_index, key_len-8, ref-NULL, rows-500, filtered-100.00, Extra-Using where; Using filesort...' },
204
+ ])
205
+
206
+ const timeRange = state('day')
207
+ const thresholdMs = state(10)
208
+ const selectedConnection = state('all')
209
+ const searchQuery = state('')
210
+ const isLoading = state(false)
211
+ const expandedQueryId = state<string | null>(null)
212
+ const copiedQueryId = state<string | null>(null)
213
+
214
+ const filteredQueries = derived(() => {
215
+ let list = [...slowQueries()]
216
+ const conn = selectedConnection()
217
+ const threshold = thresholdMs()
218
+ const q = searchQuery().toLowerCase()
219
+
220
+ if (conn !== 'all')
221
+ list = list.filter(qy => qy.connection === conn)
222
+ list = list.filter(qy => qy.duration >= threshold)
223
+
224
+ if (q) {
225
+ list = list.filter(qy =>
226
+ qy.query.toLowerCase().includes(q)
227
+ || (qy.model?.toLowerCase().includes(q) ?? false)
228
+ || (qy.method?.toLowerCase().includes(q) ?? false)
229
+ || (qy.affected_tables?.some(t => t.toLowerCase().includes(q)) ?? false),
230
+ )
231
+ }
232
+
233
+ return list.sort((a, b) => b.duration - a.duration)
234
+ })
235
+
236
+ const totalCount = derived(() => filteredQueries().length)
237
+
238
+ const avgDurationLabel = derived(() => {
239
+ const list = filteredQueries()
240
+ if (!list.length)
241
+ return '0 ms'
242
+ const avg = list.reduce((sum, q) => sum + q.duration, 0) / list.length
243
+ return formatDuration(avg)
244
+ })
245
+
246
+ const maxDurationLabel = derived(() => {
247
+ const list = filteredQueries()
248
+ if (!list.length)
249
+ return '0 ms'
250
+ return formatDuration(Math.max(...list.map(q => q.duration)))
251
+ })
252
+
253
+ const topAffectedTable = derived(() => {
254
+ const list = filteredQueries()
255
+ if (!list.length)
256
+ return 'N/A'
257
+ const counts: Record<string, number> = {}
258
+ list.flatMap(q => q.affected_tables || []).forEach((t) => { counts[t] = (counts[t] || 0) + 1 })
259
+ const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1])
260
+ return sorted[0]?.[0] || 'N/A'
261
+ })
262
+
263
+ const hasNoQueries = derived(() => filteredQueries().length === 0)
264
+
265
+ function setTimeRange(range: string): void {
266
+ timeRange.set(range)
267
+ }
268
+
269
+ function isExpanded(id: string): boolean {
270
+ return expandedQueryId() === id
271
+ }
272
+
273
+ function toggleQueryDetails(id: string): void {
274
+ expandedQueryId.set(expandedQueryId() === id ? null : id)
275
+ }
276
+
277
+ function querySource(query: SlowQueryRecord): string {
278
+ if (query.model && query.method)
279
+ return `${query.model}.${query.method}`
280
+ return query.method ?? ''
281
+ }
282
+
283
+ function formatQuery(q: string): string {
284
+ return q.length > 100 ? `${q.substring(0, 100)}...` : q
285
+ }
286
+
287
+ function formatDuration(d: number): string {
288
+ return `${d.toFixed(2)} ms`
289
+ }
290
+
291
+ function copyQuery(id: string): void {
292
+ const target = slowQueries().find(q => q.id === id)
293
+ if (!target)
294
+ return
295
+ if (typeof navigator !== 'undefined' && navigator.clipboard) {
296
+ navigator.clipboard.writeText(target.query).catch((err) => {
297
+ // eslint-disable-next-line no-console
298
+ console.error('Could not copy text:', err)
299
+ })
300
+ }
301
+ copiedQueryId.set(id)
302
+ setTimeout(() => {
303
+ if (copiedQueryId() === id)
304
+ copiedQueryId.set(null)
305
+ }, 2000)
306
+ }
307
+ </script>
308
+
309
+ <style>
310
+ .sql-highlight { color: #f8f8f2; }
311
+ .font-mono {
312
+ font-family: 'JetBrains Mono', Menlo, Monaco, Consolas, 'Courier New', monospace;
313
+ font-size: 0.85em;
314
+ line-height: 1.5;
315
+ }
316
+ </style>
317
+
318
+ @endsection