Add the pages the relaunch is for, without pointing anyone at them yet - #123
Add the pages the relaunch is for, without pointing anyone at them yet#123openipc-ai wants to merge 1 commit into
Conversation
Seven pages -- home, get-started, low-latency, ecosystem, business, community, donate -- plus the shared partials they are built from. They answer on their own URLs from this commit, but the root route and the navigation still serve the pre-relaunch structure, so nothing a visitor sees changes. The cutover is a separate change, and this one can go to dev.openipc.org and be looked at first. The copy is written in all three locales the site now serves. English and Russian are as drafted; the Chinese was written for this commit and has not been read by a native speaker -- it should be, before it is linked to. i18n-tasks reports 347 keys in each of the three files and no missing translations. Not everything from the draft survived contact with the current tree, and the rendering tests are what found each one. /get-started hardcoded four WebUI screenshots by filename -- webui/preview.jpg and three others. The gallery was reshot at twice the resolution in 0f42514 and every one of those files stopped existing; the page raised on render. It now takes them from WebuiGallery, the same manifest /web-interface reads and the same one tools/webui-gallery photographs from, so the two cannot disagree about what exists. Tile and full-resolution copy are passed as a pair, which is what data-zoom in src/zoom.js is for. Every link in the new copy that pointed at wiki.openipc.org now points at github.com/OpenIPC/wiki. That host is retired; 2842ffa and 73c0961 removed the last references to it and this copy would have put four of them back. The partner wall moves out of the markup into PagesHelper, transcribed from /introduction as it stands today rather than from the June draft, which was ten entries out of date. Entries that page has commented out are commented out here too, with their URLs, so nothing appears or disappears silently when /introduction goes. REVIEW POINT: the Russian integrator block is currently commented out on /introduction, so no visitor sees any of it. Rendering it for :ru brings it back. That is what the relaunch plan asks for and it is gated to :ru as the maintainers asked, but it is a content decision -- say so if it should stay hidden. Worth knowing: the CSS that was supposed to enforce that gate, `html:not([lang="ru"]) article.introduction .col.logo.ru`, has never matched anything. No logo on that page carries the `ru` class it selects on. The gate being in Ruby now is what makes it testable, and there is a test. /open-wall is uncommented. It was commented out in ed0e025, a bulk tidy-up, while five places that redirect to it were left in place -- twice in snapshots_controller, once in admin/snapshots_controller, and the breadcrumb on three views. All five fell through the catch-all and answered a 302 to the homepage. This exposes nothing new: `resources :snapshots` has served the same gallery at /snapshots throughout. Snapshot.latest_per_camera lifts the correlated subquery out of SnapshotsController#index, because the homepage mosaic wants the same list and two copies of that query is one too many. pages.donate belonged to the band rendered under every page. It is now the /donate page's, and the band's two keys moved to pages.donate_band -- otherwise lazy lookup in the partial and the new page's title would have fought over the same key, and the band would have lost its please_support string. 272 runs, 1223 assertions, 0 failures. Each page is rendered in each of the three locales and checked for "translation missing"; every internal link on them is followed and required not to land on the catch-all; the homepage is rendered against an empty database, which is what a fresh checkout has. rubocop is unchanged at 53 offences across the files this touches, and the two new files add none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hvzXBErEjEGMyRme2K3hi
PR Summary by QodoStage seven localized relaunch pages for pre-cutover review
AI Description
Diagram
High-Level Assessment
Files changed (35)
|
Code Review by Qodo
1. Missing metadata crashes homepage
|
| <a href="<%= snapshot_path(snapshot) %>" class="wall-tile"> | ||
| <%= image_tag snapshot.file.variant(:thumb), alt: t('.wall_snapshot_alt'), | ||
| loading: (idx.zero? ? 'eager' : 'lazy') %> | ||
| <span class="wall-caption"><%= snapshot.soc.upcase %> · <%= snapshot.sensor.upcase %></span> |
There was a problem hiding this comment.
1. Missing metadata crashes homepage 🐞 Bug ☼ Reliability
The homepage calls upcase on every snapshot's soc and sensor, but the public upload path permits both fields to be absent and the model does not validate them. One otherwise-valid recent upload with either value missing makes /home raise instead of rendering.
Agent Prompt
## Issue description
The new homepage assumes every snapshot has non-null `soc` and `sensor`, although accepted uploads may omit both. Prevent the mosaic caption from raising on valid persisted snapshots.
## Issue Context
The upload controller permits these fields but does not require them, and `Snapshot` only validates the attachment and MAC address. Use a safe fallback in the caption and add coverage for a recent snapshot missing either metadata field.
## Fix Focus Areas
- app/views/pages/home.html.erb[18-22]
- app/models/snapshot.rb[61-64]
- app/controllers/snapshots_controller.rb[92-95]
- test/controllers/relaunch_pages_test.rb[46-56]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| @meta_description = t('site.default_meta_description') | ||
| @wall_snapshots = Snapshot.latest_per_camera(limit: 5) | ||
| @soc_count = Soc.count | ||
| @vendor_names = Vendor.order(:name).pluck(:name) |
There was a problem hiding this comment.
2. Sensor vendors inflate statistics 🐞 Bug ≡ Correctness
PagesController#home loads every Vendor, so the “Runs on silicon by” strip and chip-vendor count include vendors that only manufacture image sensors. The model already provides Vendor.soc_vendors specifically to restrict this list to vendors associated with SoCs.
Agent Prompt
## Issue description
The homepage lists and counts every vendor record as a chip vendor, including sensor-only manufacturers. Restrict the homepage query to vendors that have SoCs.
## Issue Context
`Vendor` already defines the `soc_vendors` scope for this distinction. Apply it before ordering/plucking and add a test with a sensor-only vendor.
## Fix Focus Areas
- app/controllers/pages_controller.rb[61-64]
- app/models/vendor.rb[3-12]
- app/views/pages/home.html.erb[42-49]
- app/views/pages/home.html.erb[101-104]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def home | ||
| @page_title = t('pages.home.title') | ||
| @meta_description = t('site.default_meta_description') | ||
| @wall_snapshots = Snapshot.latest_per_camera(limit: 5) |
There was a problem hiding this comment.
3. Timestamp ties duplicate cameras 🐞 Bug ≡ Correctness
The homepage asks latest_per_camera(limit: 5) for five camera tiles, but the anti-join treats every row sharing a camera's maximum created_at as latest because it only compares timestamps with <. Concurrent uploads can therefore let duplicate rows for one MAC consume multiple limited mosaic slots instead of showing five distinct cameras.
Agent Prompt
## Issue description
The homepage's limited latest-per-camera query can return multiple snapshots for one camera when maximum timestamps tie. Make selection deterministic and guarantee one row per MAC address.
## Issue Context
The schema does not make `created_at` unique, and the interval validation is an application-level read-before-write check rather than a database constraint. Add an ID tie-break to the anti-join or use an equivalent deterministic grouped/window query, with a regression test for equal timestamps.
## Fix Focus Areas
- app/models/snapshot.rb[24-30]
- app/controllers/pages_controller.rb[58-64]
- app/views/pages/home.html.erb[18-25]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Fourth of five PRs rebasing the June 11 relaunch onto master.
Stacked on #122 (which is stacked on #121). Merge in order and GitHub
retargets each one.
Seven pages — home, get-started, low-latency, ecosystem, business, community,
donate — plus the shared partials they're built from. They answer on their own
URLs from this commit, but the root route and navigation still serve the
pre-relaunch structure, so nothing a visitor sees changes. The cutover is #5.
This one can go to dev.openipc.org and be looked at first.
Things the draft got wrong, that the rendering tests caught
/get-startedraised on render. It hardcoded four WebUI screenshots byfilename —
webui/preview.jpgand three others. The gallery was reshot at twicethe resolution in 0f42514 and every one of those files stopped existing. It now
takes them from
WebuiGallery— the same manifest/web-interfacereads andtools/webui-galleryphotographs from — so the two cannot disagree about whatexists. Tile and full-resolution copy are passed as a pair, which is what
data-zoomis for.Four links to the retired wiki host. Every
wiki.openipc.orglink in the newcopy now points at
github.com/OpenIPC/wiki. 2842ffa and 73c0961 removed thelast references to that host; this copy would have put four back.
The partner wall was ten entries out of date. It moves out of the markup into
PagesHelper, transcribed from/introductionas it stands today. Entriesthat page has commented out are commented out here too, with their URLs, so
nothing appears or disappears silently when
/introductiongoes.The Russian integrator block is currently commented out on
/introduction,so no visitor sees any of it today. Rendering it for
:rubrings it back. That'swhat the relaunch plan asks for, and it's gated to
:ruas you asked — but it'sa content call, not a technical one. Say the word if it should stay hidden.
Related: the CSS that was supposed to enforce that gate,
html:not([lang="ru"]) article.introduction .col.logo.ru, has never matchedanything — no logo on that page carries the
ruclass it selects on. Havingthe gate in Ruby is what makes it testable, and there's now a test.
Also here
/open-wallis uncommented. It was commented out in ed0e025, a bulktidy-up, while five places that redirect to it were left in — twice in
snapshots_controller, once inadmin/snapshots_controller, and thebreadcrumb on three views. All five fell through the catch-all to a 302 home.
This exposes nothing new:
resources :snapshotshas served the same gallery at/snapshotsthroughout.Snapshot.latest_per_cameralifts the correlated subquery out ofSnapshotsController#index; the homepage mosaic wants the same list.pages.donatechanged owner. It belonged to the band rendered under everypage; it's now the
/donatepage's, and the band's two keys moved topages.donate_band. Otherwise lazy lookup in the partial and the new page'stitle would have fought over one key and the band would have lost its
please_supportstring.Chinese
Written for this commit and not read by a native speaker — it should be
before it's linked to. No translation API key was available, so it isn't machine
output either.
i18n-tasksreports 347 keys in each of the three files.Verification
bin/rails testi18n-tasks missing/unusedrubocop🤖 Generated with Claude Code
https://claude.ai/code/session_015hvzXBErEjEGMyRme2K3hi