-
Notifications
You must be signed in to change notification settings - Fork 111
types_from_initializers + js_from_routes + performance fixes
#918
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
types_from_initializers + js_from_routes + performance fixes
#918
Conversation
types_from_initializers + js_from_routes + performance fixes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces generated TypeScript route helpers and serializer-derived TS types for the Svelte/Inertia frontend, along with dashboard query performance improvements (new indexes + optimized weekly aggregation).
Changes:
- Add
js_from_routes+types_from_serializerstooling/config and update Svelte pages to use generated route helpers and generated TS prop types. - Improve dashboard performance by adding partial indexes on
heartbeatsand replacing per-week queries with a single window-function aggregation. - Minor dependency/version bumps and small UI/accessibility tweaks.
Reviewed changes
Copilot reviewed 45 out of 51 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
config/initializers/js_from_routes.rb |
Configures generation of TS route helpers into app/javascript/api. |
config/routes.rb |
Adds route defaults intended for export/generation. |
app/javascript/pages/**/*.svelte |
Switches hardcoded paths + local prop types to generated route helpers and serializer-derived TS types. |
config/initializers/types_from_serializers.rb + app/serializers/**/* |
Adds serializer DSL and defines typed serializers to generate TS types. |
app/models/concerns/heartbeatable.rb + app/controllers/static_pages_controller.rb |
Adds weekly grouped duration query and uses it to speed up dashboard stats computation. |
db/migrate/*_add_indexes_for_dashboard_performance.rb + db/schema.rb |
Adds concurrent partial indexes to improve dashboard filter/stat queries. |
package.json + lockfiles |
Adds @js-from-routes/inertia and bumps Svelte/tsconfig versions. |
.gitignore |
Ignores generated route helper + generated serializer TS type output directories. |
app/javascript/layouts/AppLayout.svelte |
Accessibility-related markup changes and minor state logic adjustments. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| </svg> | ||
| </button> | ||
| <div class="nav-overlay" class:open={navOpen} onclick={closeNav}></div> | ||
| <div class="nav-overlay" class:open={navOpen} onclick={closeNav} role="button" tabindex="0" onkeydown={(e) => e.key === 'Enter' && closeNav()}></div> |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nav overlay is given role="button" and keyboard handling, but it only closes on Enter. For button-like elements, Space should also activate the action; otherwise keyboard users may not be able to dismiss the overlay reliably. Consider handling both Enter and Space (or use a real <button> element).
| <div class="nav-overlay" class:open={navOpen} onclick={closeNav} role="button" tabindex="0" onkeydown={(e) => e.key === 'Enter' && closeNav()}></div> | |
| <div class="nav-overlay" class:open={navOpen} onclick={closeNav} role="button" tabindex="0" onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); closeNav(); } }}></div> |
| role="button" | ||
| tabindex="-1" | ||
| aria-label="Close logout modal" | ||
| onkeydown={(e) => e.key === 'Escape' && closeLogout()} |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This backdrop is marked role="button" with an Escape key handler, but tabindex="-1" means it won’t receive focus via keyboard navigation, so the key handler is unlikely to fire. Since you already register a document-level Escape handler, consider removing the button semantics here (e.g., use role="presentation"/no role) to avoid exposing a non-interactive ‘button’ to assistive tech.
| role="button" | |
| tabindex="-1" | |
| aria-label="Close logout modal" | |
| onkeydown={(e) => e.key === 'Escape' && closeLogout()} |
| root "static_pages#index", defaults: { export: true } | ||
|
|
||
| resources :extensions, only: [ :index ] | ||
| resources :extensions, only: [ :index ], defaults: { export: true } |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding defaults: { export: true } to these routes will change Rails URL helper output (e.g., root_path becomes /?export=true). That will break existing current_page?(root_path) checks and server-rendered links/redirects that expect / (no query string). Consider using a route-tagging approach that doesn’t alter generated URLs, or ensure callers pass export: nil / update current_page? usage accordingly.
| "@fontsource/inter": "^5.2.8", | ||
| "@inertiajs/svelte": "^2.3.13", | ||
| "@js-from-routes/inertia": "^1.10.2", | ||
| "@sveltejs/vite-plugin-svelte": "^6.2.4", | ||
| "@tailwindcss/forms": "^0.5.11", |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@js-from-routes/inertia pulls in @inertiajs/inertia@0.11.1, which is marked deprecated in the lockfile and brings an old axios@0.21.x dependency. Please confirm this is intentional and upgrade/swap to a maintained client library that doesn’t require the deprecated Inertia v0 package (or explicitly depend on a secure axios version if unavoidable).
| JsFromRoutes.config do |config| | ||
| config.client_library = "@js-from-routes/inertia" | ||
| config.file_suffix = "Api.ts" | ||
| config.all_helpers_file = "index.ts" | ||
| config.output_folder = Rails.root.join("app/javascript/api") | ||
| end |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config.output_folder points to app/javascript/api, but that directory is currently absent and is now gitignored. Since the Svelte code imports from ../../api, a clean checkout/build will fail unless the routes file is generated as part of the build/dev startup. Please add an explicit generation step (CI/build script or bin/setup/bin/dev hook) or commit the generated output instead of ignoring it.
| if Rails.env.development? then | ||
| TypesFromSerializers.config do |config| | ||
| config.output_dir = Rails.root.join("app/javascript/types/serializers") | ||
| config.custom_types_dir = Rails.root.join("app/javascript/types") | ||
| config.transform_keys = ->(key) { key.to_s } |
Copilot
AI
Feb 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, TypesFromSerializers writes to app/javascript/types/serializers, but the directory is absent and gitignored while the frontend imports these types. Please ensure types are generated automatically before TypeScript/Svelte compilation (or commit them) so fresh clones and deploy builds don’t fail.
No description provided.