mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-11-02 03:11:24 -05:00
release97
1229
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
02f5f95b9a |
Add "New" badge and welcome message for neighbours page
- Define launch date and duration for "New" badge visibility - Update neighbours menu to display badge when applicable - Enhance neighbours show page with a welcome message for new users - Add corresponding translations for welcome message and feedback link |
||
|
|
3b06325e62 |
Add friends and neighbours feature with member dismissal functionality
- Implement RecentActivity service to track recent planting, harvesting, and trading events. - Enhance TimelineService to include garden layouts in event queries. - Update navigation menu to include a link to friends and neighbours. - Create member card partial for displaying gardener information. - Add follow button partial for managing follow actions. - Refactor members index view to use the new member card partial. - Introduce neighbours feed view with daily updates and entries. - Implement entry partial for displaying individual neighbour activities. - Create layout partial for visualizing garden layouts. - Add posts section to neighbours view for displaying recent posts. - Implement reach section to show nearby gardeners. - Add suggestions section for recommending gardeners to follow. - Create routes for neighbours functionality and member dismissals. - Add migrations for member dismissals and garden layout timestamps. - Write feature and request specs for neighbours functionality. - Include support for creating located members in tests. |
||
|
|
54258de6c4 |
Refactor home dashboard and related components
- Removed unused styles and helper methods from _garden_layout.scss, _homepage.scss, and overrides.scss. - Updated _home_dashboard.scss to enhance button styles and added new harvest picker styles. - Introduced HarvestPicker component for improved harvest recording functionality. - Refactored home dashboard views to utilize new home_section helper for consistent layout. - Simplified and optimized existing methods in application_helper.rb, activity.rb, and harvest.rb. - Removed deprecated homepage_records methods from Activity and Harvest models. - Updated tests to reflect changes in helper methods and removed obsolete tests. |
||
|
|
ef06bab74f |
Add crop suggestions feature and dashboard enhancements
- Introduced crop suggestions functionality allowing users to receive tailored crop recommendations based on their location and preferences. - Implemented the ability for users to dismiss specific crop suggestions, preventing them from receiving recommendations for crops they are not interested in. - Added a location picker for users to set their gardening location, enhancing the accuracy of crop suggestions. - Enhanced the dashboard to display relevant statistics, including plantings and harvests, with comparisons to previous years. - Created new views and partials for displaying statistics, crop suggestions, and user interactions on the dashboard. - Updated routes to accommodate new features related to crop suggestions and member locations. - Added migrations for new database tables and columns to support crop dismissal and suggestion preferences. - Developed tests for the new features, ensuring functionality and user experience are maintained. |
||
|
|
c2e79dbc13 | Enhance plant_before_year method to retain user input on error and add tests for input handling in seed model | ||
|
|
84e6b1cbbd | Add plant_before_year attribute to seeds and update related forms and views | ||
|
|
53dbbbaf46 | Remove ruby-units gem and implement weight unit conversion directly in Harvest model | ||
|
|
6a208a127b |
Tidy up plantings#show (#4848)
* Restore the Ruby 4.0.6 upgrade PR #4831 committed a stale Gemfile.lock over the newer one, taking .ruby-version back to 3.2.3 and rolling back active_median, dalli, parallel, rbs and selenium-webdriver. Dockerfile and .devcontainer/Dockerfile still build on Ruby 4, so the Gemfile's version check fails against the image. Restores both files to what they were before that merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy plantings#show, and make cards and menus consistent This page read as a page about the crop rather than about one member's planting, and its sections each did things their own way. Changes follow the conventions written up in the UI consistency guide. Identity - Title, meta description and OpenGraph all read "<crop> planting by <owner>"; the hero carries a muted "planting by X in Y" subtitle and the scientific name moves to the crop card. - Breadcrumb's last item is plain text, not a link to the current page. Actions - One actions menu per page: a quiet three-dot button in the top right of the hero, rendered by the new PlantingActions island, opening the EditPlanting, RecordHarvest, SaveSeeds, MarkFinished and AddPhoto dialogs that already existed for the garden list. - Menu items are lower case, so a menu reads as a list of things you can do rather than a row of headings. - Transplanting moves out of the sidebar into a dialog off that menu: it is done once in a planting's life and should not hold real estate. - The second seed-saving dropdown and the loose photo buttons are gone; each section keeps one quiet "add" on its heading bar as the non-JS path. - The plant-part icons from the server-rendered harvest form now reach the dialog, via icon_url on HarvestFormSerializer. Fact cards - Every card fills the same four slots, and the core cards always render so one planting's page has the same shape as the next. - Progress reads as a percentage with "day 43 of 90" beneath; quantity and "grown from" merge into one card rather than both saying "seedling"; rating is stars and renders even when unrated. - Dates go through I18n.l and standard_time_distance instead of assembling abbr_month_names by hand. - Adds Planting#planned?, replacing three copies of age_in_days < 0. - Perennial no longer claims the plant "grows back each year". Cards by type - Harvest cards get square corners, a warm accent and the harvest icon, and say "<crop> harvest", so they are not mistaken for plantings. - Seed cards are drawn as seed packets: portrait, papery, torn top edge, printed band, small print along the foot and the year saved stamped on them. Layout - The page wrapper is .planting-show, not .planting: that is the planting *card's* class, and its absolutely positioned badges and quick actions were leaking onto this page. - Sections are bordered blocks with their heading bar as the lid, so a heading and its content read as one thing. - One spacing scale, and the hero aligns to the same left edge as everything below it. Copy - Section headings and empty states go through en.yml, in one voice. - "Add a photo to visually track growth of this planting, to Flickr, iNaturalist or Pl@ntNet" was nonsense: photos come from Flickr only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Use the harvest and seed cards site-wide, and rate a planting in place The new harvest cards and seed packets only appeared on plantings#show. Everywhere else either used the old thumbnails or hand-rolled its own markup, which is what made harvests and plantings look alike in the first place. - members#show and members/_harvests render harvests/card. The latter also wrapped each card in another .card, which nested a card in a card. - The homepage harvest list was hand-rolled markup beside a seeds section that already used seeds/card; both now use the shared partials. - Homepage seed packets go in an .index-cards grid. Outside one they have no width, and the packet's 3:4 ratio made each half the page wide. - harvests/_harvest and seeds/_seed chose between card and thumbnail on a `full:` local that nothing passes. Both render the card. The crop pages' harvest and seed panels are lists of links in a sidebar, not card grids, so they are left alone. Section "add" buttons now open the same dialogs as the actions menu, via a data-planting-dialog attribute the island listens for. Their href stays as the fallback without JavaScript. The rating card is now clickable: for someone who may edit the planting it renders StarRating, which saves the new rating and puts it back if the save fails. The card's own heading is the label, so the fieldset legend is hidden rather than saying "Rating" twice. "More photos" is a plain link again, and only shows when there are more photos than the page is displaying — the photos are now paginated to 12, where before the whole set was loaded and the link always showed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Put the like button beside the planting's name It sat on its own below the hero, with a section's worth of space above and below it, reading as an orphan rather than as something belonging to the planting. It now sits on the title line, right after the name, at its own size rather than the title's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Draw a border around the planting's own data The title, facts, photos, harvests, seeds and planned activities now sit inside one subtle border, so they read as one body of data rather than running into the sidebar beside them. Also drops the raised shadow from the like button. The global .btn shadow made the heart look like a call to action it isn't. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy the planting page sidebar, and the add-photo dialog The sidebar was three blocks with three different treatments: a bare owner card, the shared crop card, and a bordered neighbours section. They now all use the same sections as the main column, with a heading bar each. - The owner block leads with the avatar and who grows this where, rather than a heading repeating "Planted by". - The crop card renders without its footer here. "Add to my garden" and "Save seeds" made no sense beside a planting you are already growing, and the page offers both already. crops/_crop takes actions: false; everywhere else keeps them. - Partials shared with other pages bring their own .card, which inside a section is a box in a box, so those are flattened. Add-photo dialog: - It now says what it is adding to: "Add photo to chives planting", rather than "Add a photo to chives". Garden cards say which garden. - While Flickr is being read the body holds roughly the height the picker will take and centres the spinner, instead of a short dialog with a spinner in the corner that jumps open when the photos arrive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say what kind of record a page is about in its title "Chives" is a crop. A page about one member's chives should say "Chives planting" in its heading, not leave the reader to work it out from the furniture around it. The same for harvests and saved seeds. - plantings#show: "Chives planting", subtitle "by <owner> in <garden>". - harvests#show: "Basil harvest", subtitle "by <owner> · <date>". The owner was in a %small inside the h1 before. - seeds#show: already said "seeds"; it now names who saved them. Gardens are left as they are: a garden's name is the member's own, so the noun belongs in the subtitle rather than appended to a name that may already contain it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * One corner radius for all data cards, and harvest months by season Cards used three different shapes: plantings rounded at 5%, harvests and seed packets square. A percentage radius also draws an ellipse that changes with the card's size, so a tall packet and a square planting card curved differently. There is now one $card-radius, used by every data card and by the section boxes. Harvest months are grouped into the grower's own seasons, three months each, named and kept together, starting at their spring — so a Wellington gardener sees spring begin in September. Where we have no latitude we show the plain January-to-December row rather than guessing at a hemisphere. The grower's location now appears in the page subtitle. It decides the seasons and the harvest times, so it belongs with the rest of the planting's identity rather than only as a "nearby" link in the sidebar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tidy the harvest months block It was loose text at the end of the timeline partial: a bare "Harvest months:" label, twelve badges, and a trailing "in <place>" that now repeats the location in the page subtitle. - Moved into its own partial with a proper label, rather than trailing off the timeline. - Dropped the repeated location. - A legend says what a highlighted month means. Nothing said so before. - The empty state is its own muted line instead of a sentence running on from the label, and no longer says "we need more data" at the reader. - Each badge carries its full month name for screen readers, and highlighted ones say they are harvest months. The quiet months were aria-hidden, so a screen reader heard the harvest months with no calendar around them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Give the sidebar crop block its own partial Reusing crops/_crop inside a section meant a card inside a box: a white strip between the green heading and the photo, the card's own shadow sitting proud of the section, a photo that overshot the right edge, and two corner radii disagreeing. Flattening it with negative margins was fighting the card rather than fixing it. plantings/_crop is written for this spot instead: the photo runs edge to edge under the heading bar, the crop's name is title-cased with its scientific name beneath, and the growing times are a short list rather than three stats laid out side by side. crops/_crop goes back to how it was, including its footer buttons, since nothing needs to suppress them now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Update the specs for the tidied planting page Mostly copy and flow changes from the tidy-up, but two real bugs came out of running them. Bugs fixed: - planting_actions_props didn't pass planted_at or today, which MarkFinishedModal needs to decide whether "today" may be offered and where the date box starts. Without them the dialog threw while rendering, and with no error boundary React tore down the whole island, so the actions menu vanished entirely. - The dialogs reloaded the page from inside the save callback, tearing the page down while the dialog was still finishing its own update. They now close first and reload on the next tick. Menu items are lower-cased in CSS, as the garden cards already do it, rather than by calling downcase on the shared button translations. That was mangling labels other pages show in sentence case. Specs: - Menu, dialog and section-heading flows updated: the actions menu opens dialogs rather than navigating, so recording a harvest, marking a planting finished, editing and transplanting all drive the dialog. - Copy: "grows this in", "day 14 of 50", "Planned" for a future planting, "4 of 5", the new harvest-months wording, and the add-photo dialog naming what it adds to. - The parent-seed example asserted a link to the planting, which came from the breadcrumb; the last crumb is the page you are on, so it is plain text now and the example checks the seed link instead. - Removed spec/features/shared_examples/append_date.rb. It drove the old datepicker finish flow and had one caller. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Stop avatars shifting the page during feature specs spec/features/places/searching_a_place_spec.rb intermittently failed on "goes to members' index page": the click on "View all members >>" landed on nothing and the browser stayed put. Member avatars come from gravatar.com over the network and were rendered with img-fluid and no dimensions, so they reserved no space until they arrived. The link sits directly under that grid. Capybara found the link, an avatar landed, the link moved, and the click missed. rails_helper meant to prevent this, but its guard tested for Poltergeist's url_blacklist. Poltergeist is long gone and Selenium's browser has no such method, so the condition was always false and the block never ran. - Give the two avatar image tags explicit width and height, so the box is reserved before the image loads. This fixes real layout shift for members too, not only the specs. - Replace the dead guard with config.x.blank_avatars, which browser specs set, making avatar_uri return a blank inline GIF. Helper specs still assert the real Gravatar URLs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Fix avatar URI logic to prevent layout shift in all environments * Add waiting assertions to prevent premature content checks after saving harvest * Refactor PlantingActions to improve dialog handling and state management Enhance PlantingRating to prevent multiple saves and improve error messaging * Fix date input handling in planting edit dialog * Add neighbour planting sidebar with improved styling and layout * Tidy crops#show, and share the record page layout The planting page's layout was planting-specific CSS. It is now a shared .record-page / .record-panel in _record_page.scss, and crops#show uses it: the crop's own data inside one border, the sidebar outside, sections as bordered blocks with a heading bar as the lid. Along the way a duplicate section rule and two copies of the kebab button styling collapsed into one each. Crop page: - Scientific and alternate names sit under the crop's name, where they belong, instead of having a sidebar card of their own. Wranglers add and edit them from the actions menu, in a dialog; the loose "Add" buttons in the page body are gone. - The actions menu is the same three-dot kebab as plantings, in the top right of the hero. The "you are a CROP WRANGLER" banner is gone: seeing the menu already tells you that. Menu items have no icons now, except delete, which keeps its icon and its red. - Growing facts were split three ways — prose in the hero, prediction cards in the main column, an OpenFarm list in the sidebar — and the hero prose was the same fields as the OpenFarm ones. One "Growing X" section of fact cards now holds all of it. - The sidebar listed planting, harvest and seed counts directly above three sections with those same names. The counts are headline numbers in the hero instead, which also fills the space the hero was wasting. - Main column reads top to bottom: how to grow it, how members grow it, varieties, companions, photos, video, where it grows, posts, history. Headings say something rather than naming a partial. - Crop actions are just "Add to my garden". Recording a harvest, saving seeds, posting and marking a planting failed all belong to a planting you already have. - The charts section rendered as an empty white strip whenever a crop had any plantings or harvests but no chart to draw. - The hero photo moved to the sidebar, where it has room. Also: the whimsical icons perch on the heading bar below them rather than sitting inside the box, the garden picker dialog gives every row the same shape so the names line up, and crops/_grown_for.html.haml is deleted — nothing rendered it once its content moved into the growing cards. Specs are not updated yet: crop_detail_page_spec clicks "Record harvest" on this page, which no longer exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Refactor crop-related views and styles for improved layout and functionality - Update styles in _crops.scss for better alignment and spacing. - Enhance _record_page.scss with a new section footer for actions. - Modify _alternate_names.html.haml to improve dropdown functionality for editing and deleting names. - Change _history.html.haml header to "Edit history" for clarity. - Adjust _info.haml to display sowing method and sun requirements prominently. - Revise _openfarm_data.html.haml to remove unnecessary comments and clarify content. - Update _photos.html.haml to include a section footer for the "More photos" link. - Refine _posts.html.haml to streamline the display of posts and actions. - Improve _scientific_names.html.haml to enhance dropdown functionality for scientific names. - Update tests in alternate_name_spec.rb and scientific_name_spec.rb to reflect UI changes. - Remove unused _grown_for.html.haml_spec.rb file. * Replace language text field with a dropdown select for improved user experience * Enhance editable forms and fact cards for improved user interaction and layout * Refactor styles and improve layout for planting details, including muted text color updates and enhanced card displays * Refactor crop detail page for improved SEO and user experience, including updated links and content for planting and growing information. * Adjust section add button width for better layout on heading bar * Update link text for consistency and clarity in crop detail page --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> |
||
|
|
a0245174c7 |
Only geocode garden when location changes
Update after_validation callbacks for geocoding in Garden model to use `if: :will_save_change_to_location?`. This prevents external geocoding requests when non-location attributes (e.g. layout grid dimensions) are updated. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
3dc8379238 |
Add a garden layout page for mapping where plants sit in a bed (#4835)
* Share the three-dots button style outside planting rows The round three-dots toggle was scoped to .planting-row. Move it to a generic .actions-toggle-dots so other menus can reuse it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Show the garden card actions menu as three dots Matches the planting rows, and gives the button an aria-label naming the garden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let garden cards update a planting as JSON PATCH /plantings/:slug.json now returns the garden's refreshed card, as create does, or the validation errors as 422. Annual plantings in the card say whether the viewer can edit them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add a PATCH helper and a shared way to swap in a garden card Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let owners edit the planted date on garden cards The date on an annual planting row is a button with a pencil hint for plantings the viewer can edit. It opens the browser's date picker, saves with the tick or Enter, and swaps in the refreshed card so predictions follow the new date. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Serve a planting's form values as JSON for the edit dialog Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add a shared isPlainClick helper Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Edit a planting in a dialog over the garden list Three dots > Edit opens the planting's form in a modal instead of going to the edit page. It saves as JSON and swaps in the refreshed garden card, so the page is never left. Ctrl/cmd-click still opens the edit page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Drop the garden choice from the planting edit dialog Moving a planting between gardens isn't part of quick editing. The dialog no longer asks, or sends, which garden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Rate a planting with stars in the edit dialog Overall rating is five clickable stars (real radio buttons underneath, so the keyboard works) with a Clear button, in place of a select. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Only ask for a finished date once a planting is marked finished Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Show planting menu items in lowercase Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add an Add planting button to garden cards The way to plant in a garden was an item in its actions menu. Put a green button in the card header, next to the menu, that opens the same dialog. It only shows for gardens you can plant in. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Take Plant something here out of the garden card menu The Add planting button does that now. The card data carries its link as plant_url, instead of it being borrowed from a menu item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add a gallery page of a member's past gardens /members/:slug/gardens/past shows their inactive gardens as photo cards: when each was in use, how many plantings, and the crops grown in it. The owner (or a collaborator) can mark a garden active again from its card. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Replace the include in-active tickbox with a link to past gardens Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Call them inactive gardens, and explain what that page is Rename the past gardens page to inactive gardens throughout (label, route, action, view, styles). Move its link on the gardens page to below the member's card, with a line saying what it holds, and add an explanation to the page itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Line the breadcrumb up with the page content The breadcrumb bar is the same colour as the page, but its side padding pushed the text 1rem in from the edge the heading and content sit on. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Line the sidebar text up with the text in the member card The skip link, nav links, button, blurb and inactive gardens link sat at the card's edge while the card's own text is inset. Give them the same inset, left-align the blurb, and add a little space between the links. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the sidebar nav links look like links Link colour and underline, with the page you are on in bold and marked aria-current. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let garden cards record a harvest as JSON GET /plantings/:slug/harvests/new.json gives the form's starting values and choices; POST /harvests.json returns the garden's refreshed card, or the validation errors as 422. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Record a harvest in a dialog over the garden list Three dots > record harvest opens a quick entry form (how many, weight, when, plant part, notes) in a modal, with the crop and today's date filled in. It saves as JSON and swaps in the refreshed card, so the page is never left. Ctrl/cmd-click still opens the full harvest page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Pass the harvest handler to the planting row, not the perennial chip The record harvest prop had been attached to the first matching element in GardenCard, the perennials' CropChip, so the row's menu item fell through to a normal link. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Share the dialog step indicator Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Record a harvest in two steps, styled like Add planting Step 1 is what part you harvested: a big text box, with the cursor in it, that completes from the plant parts (the crop's usual one first). Step 2 is how much: quantity, weight, when and notes, with the choice shown back and a Change button. Same look as the Add planting dialog. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Harvest dialog: add When and Any notes steps, drop Cancel Step 3 is when (Today, Yesterday, or Enter date), step 4 is any notes, and that step saves. The choices so far are shown back with Change buttons, and there is a Back button. Closing the dialog is how you cancel. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Mark the planting that has just had a harvest recorded For a few seconds the row goes amber and gets a Harvest recorded tag, and the notice names the garden, so it is clear which planting it was. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Only offer Yesterday when a harvest then would be after planting The server needs a harvest to come after the planted date, so a planting made today (or yesterday) has no Yesterday, and the date box starts the day after it was planted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix the JSON request specs, and tolerate an empty harvest param The update helper took its hash as keywords, and the form GET sent a JSON content type, which Rails wraps into an empty harvest param that new then rejected. The specs are fixed, and new ignores a blank harvest param. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Put Mark as finished last in the planting menu, below a divider It takes the planting off the list, so it goes after the everyday actions, separated from them. The card menu and the garden page menu match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Show a tick on the progress bar for each harvest Each harvest is a small tick at its date on the bar's own scale, with the date as a tooltip and a hidden sentence for screen readers. The card data carries the positions, worked out with the same formula as the fill. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the pill choice styles general, not about harvests Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let garden cards save seeds as JSON GET /plantings/:slug/seeds/new.json gives the form's starting values and choices; POST /seeds.json returns a link to the new seed, or the validation errors as 422, without queueing a flash message. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Save seeds in a dialog over the garden list Three dots > save seeds opens a dialog in the same style as record harvest: about how many (with quick picks), whether to offer them for trade, and any notes. It saves as JSON and shows a notice with a link to the seeds, so the page is never left. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add feature specs for the save seeds and record harvest dialogs Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let garden cards choose and add a Flickr photo as JSON GET /photos/new.json gives a page of the member's Flickr photos (or says to connect or reconnect Flickr), and POST /photos.json adds one to the planting or garden and returns the garden's refreshed card, or the validation errors as 422. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add a small page for a Flickr connect pop-up to end on /authentications/connected says whether Flickr got connected and closes itself. It has no site header or footer, as it appears in a small window. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add a photo in a dialog over the garden list, connecting Flickr there too Three dots > add photo (on a planting or a garden) opens a dialog: choose one of your Flickr photos by album or tag, confirm it, and it is added without leaving the page, with the garden's card refreshed. If Flickr is not connected, or the connection has expired, the first step connects it in a pop-up and the dialog carries on by itself once it has worked. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add feature specs for the add photo dialog, with Flickr stubbed Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Stop handled menu clicks reaching jquery_ujs, and close the menu A menu item that carries a data-method (mark as finished) was still sent as a request by jquery_ujs after a dialog had taken the click over, so the page navigated and the change was made before the dialog could be used. A click a dialog handles is now stopped in the menu, which also closes it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Mark a planting finished in a dialog, asking when it finished Three dots > mark as finished opens a dialog over the list: when did it finish, today unless you enter a date. Today is not offered for a planting made today, as the server needs a finish after the planting. It saves as JSON and the planting leaves the list, without leaving the page. The card data carries the server's date for today. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add specs for the mark as finished dialog Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the crop chip the planting's menu, for annuals and perennials Clicking a chip opens the planting's menu under it (view, edit, add photo, record harvest, save seeds, mark as finished), in place of the three dots on annual rows, so perennials get the same menu. A caret shows the chip opens something. Someone who can't change the planting still gets a plain link chip. The menu items are lowercase for every planting menu. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Update the garden index spec for chip menus An owner's planting chip is a menu now, with a View link to the planting. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Let garden cards edit a garden as JSON GET /gardens/:slug/edit.json gives the form's values and choices, and PATCH /gardens/:slug.json returns the garden's refreshed card, or the validation errors as 422, without queueing a flash message. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Edit a garden in a dialog over the garden list Three dots on a garden card > edit opens its form in a dialog, and saves without leaving the page. A garden saved as inactive leaves the list, with a note saying where it went. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add feature specs for the edit garden dialog Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Update the edit garden spec: Edit on a card opens the dialog Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Re-dump schema.rb under Rails 8.1 Rails 8.1's schema dumper sorts each table's columns alphabetically, and schema.rb was last dumped under 8.0, so the next migration rewrites the whole file. Doing that on its own here, with no schema changes, keeps the garden layout commit's schema diff down to what it actually adds. The lines are identical to before, only reordered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add a garden layout page for mapping where plants sit in a bed A new page at /members/:member_slug/gardens/:slug/layout shows the bed as a grid, and the garden cards link to it as "Garden layout". Each planting in the sidebar is a crop chip. Dragging it onto the bed places one plant there, and the chip stays so it can be dragged again; dragging a plant back to the sidebar takes it off the bed. Plants can go anywhere on the bed, not just in a cell, and are drawn as circles with the crop's icon. The owner can change the bed's size above it, and it redraws as they type. There is also a "Remove all" button, and a "Plant something" button that opens the same dialog as the garden cards. Plants are a new model, one row per individual plant in a planting, so a planting of ten tomatoes is ten plants that are placed one at a time. That also gives per-plant state, such as one plant failing, somewhere to go later. A planting's quantity now follows its number of plants, and existing plantings are backfilled with one plant each per plant they say they have, up to 100. The layout saves the whole arrangement in one request, in a transaction, so a bad placement leaves the bed as it was. The owner and collaborators can arrange plants; only the owner can resize the bed or plant into it. The members-nested gardens routes now use :slug, like the top-level ones. They used :id, which the controller's loader never read, so those routes could not find a garden; nothing linked to them. The specs are not up to date with the Plant model yet, and have not been run: the layout request, serializer and feature specs still describe earlier versions of the page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add a compost bin to the garden layout, and make the bed look like soil Dragging a plant into the compost bin deletes it, so its planting has one fewer; dropping it anywhere else in the sidebar still just lifts it off the bed. The save request carries the composted plant ids, since a plant missing from the arrangement otherwise means lifted, not gone. The plant arcs into the bin as it's dropped, unless the viewer prefers reduced motion. The bin sits under "About this garden", drawn there through a portal so it stays part of the layout island, and is sticky so it stays in reach on a long bed. There is no compost icon in the Icons8 set, so it uses the earth worm. The bed is now dark soil in a timber frame, with the grid as twine. The frame is the border, so drops are measured against the soil inside it. The sidebar is just the crop chips now, without a status line under each. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Let plants on the garden layout be resized, and make dragging easier Each plant can be drawn bigger or smaller, since a tomato takes more room than basil: drag the handle on its edge. plants.diameter holds the size in grid cells once a plant is resized; until then it follows its crop's new default_diameter, or the parent crop's, or one cell. There is no form for crop defaults yet. The next plant taken off a planting's chip is the size last given to one of its plants, so shrinking one chive shrinks the next. Dragging is easier to follow. The browser's own drag picture all but vanished on the soil, so a ringed circle at the plant's size follows the pointer instead, centred where it will land. Only a plant's circle picks it up, not the square around it, which overlapped neighbouring plants and could pick up the wrong one. Clicking a plant no longer opens its planting. A crop chip dropped in the compost bin composts one of that planting's unplaced plants. Drag state is now cleared on any drop, since a plant composted from the bed is gone before its own drag end would fire, which left the bin highlighted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Point people at the garden layout, and tidy its crop chips The garden page has a card inviting people to the layout, with a small bed drawn in the same soil and timber: "Try out the new garden layout tool" for those who can arrange it, "Open the garden layout" for everyone else. It isn't shown for inactive gardens, which have nothing growing to place. On the gardens list the layout link is now a small "Layout" button beside "Add planting", rather than a line of text under the owner. The sidebar's crop chips are all the width of the sidebar, with the icon inside the chip (the shared chip style pulled it half outside) and the counts lined up. Plantings are listed by crop name, then date, then id; by date alone, plantings made the same day came back in no fixed order and reshuffled whenever a save touched them. A crop in the bed more than once shows each planting's date, so they can be told apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Make a planting's plants when its garden's layout is used, not up front Most plantings will never go on a layout, so giving every planting a row per plant, when it was made and by backfilling the existing ones, filled the plants table for nothing. Now a garden's growing plantings get their plants the first time someone who can arrange the bed opens its layout, in one insert; someone only looking makes none. The backfill migration is gone, so there is nothing to run on deploy. A planting's quantity only adds or removes plants once it is on a layout. Zero now means no plants rather than one, so a planting composted down to nothing isn't given a fresh plant next time the layout is opened; a blank quantity still counts as one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Bring the garden layout specs up to date The specs described the layout as it was several versions ago, with positions and spans on plantings. They now cover plants: where they can sit, their sizes and the fallback to the parent crop's, the 100-plant cap, and being made when a layout is first used. The request specs cover saving an arrangement, dragging off a chip, composting, resizing the bed, and who may do each. The feature spec drives the page in a browser. The garden page's layout card and the layout's save route have specs too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Tell people about the garden layout at the top of the home page A card at the top of the home page, with the same small drawn bed as the garden page's, invites people to the layout. A signed-in member is sent to the layout of their active garden with the most growing in it, so there is something to arrange, alphabetically between ones with the same. A member with no active garden is asked to add one, and anyone signed out to sign up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Keep plants wholly on the garden layout's bed A plant's position is its centre, so a big plant near the edge hung over the timber frame, and ones along the bottom were cut off. Now a plant always stays half its width from each edge: when it's dropped, resized, or the arrangement is saved. Plants already hanging over are drawn pulled in, and saved that way on the next change. A plant can't be made wider than the bed, and shrinking the bed counts each plant's edge, not just its centre. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Make it easier to tell plants apart on the garden layout Every plant was a circle with its crop's icon, and many crops share an icon or have none, so a bed could be a field of identical sprouts. - A plant big enough on screen carries its crop's name beneath it. - Pointing at a plant, or at a planting's chip in the sidebar, picks out all of that planting's plants and fades the rest. - Plantings drawn with the same icon get a coloured ring, with a matching dot on their chip. There are five colours, which are the ones that stay distinguishable from each other against the soil for every pair, colour blind or not. They go to the plantings that share an icon in the order those were made, so a planting keeps its colour. Past five in one group, plantings go by their names. The layout's data now says which icon each planting is drawn with, so the page can group them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Put stepping stones, labels and rows on the garden layout A "Garden features" group in the layout's sidebar has three things to drag onto the bed besides plants: - A stepping stone: a grey pebble, moved by dragging. - A label, such as "path" or "N": asks what it should say, sits over the plants like a marker, and is renamed by double-clicking it. - A row: a furrow two cells long, whose ends can be dragged to set where it runs, moved by the handle at its middle, and optionally named. Any of them goes in the compost bin to be removed. They're kept as a list on the garden, gardens.layout_features, and saved in the same request as the plants, so a bad one rolls back the whole save. They're checked and written directly rather than by saving the garden, which would geocode it on every drag. A save that doesn't send them leaves them alone, and the bed can't be shrunk out from under one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Put the garden layout's sidebar on the left, next to the bed The bed sits at the start of its column, sized to fit the window, so a tall, narrow bed left the sidebar stranded far off to its right. With the plantings and garden features on the left, the bed is always right next to them. On a phone they still stack, with the list under the bed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Call the garden layout's planting button "Add a planting" Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Add sprinklers, taps, stakes, paths, drip lines, fences, trellises and netting More garden features to put on the layout besides plants: - Points: an irrigation sprinkler and a tap (their Icons8 icons on a white disc ringed in blue), and a stake (the round top of a post). - Lines, drawn and reshaped like rows: a path (a wide gravel strip), a drip line (a thin blue pipe with emitters), a fence (a rail with posts) and a trellis (a strip of timber lattice). - An area: netting, a see-through mesh over the plants it covers, between two corners that can be dragged to resize it. Lines and netting share their handles: the middle to move and name it, the ends or corners to reshape it. The types are now one table in the layout, each with a name and a shape (point, label, line or area), and the sidebar offers them from it. The server knows them by the same split, checks both points of every line and area, and sends the icons as one set, feature_icon_urls. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Call the garden layout's "Remove all" button "Clear bed" It still lifts only the plants back to their chips; the confirmation now says that stones, lines, netting and the rest stay where they are. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Put garden features in a toolbar above the bed, and keep the sidebar in view With eleven garden features under the plantings, the sidebar no longer fit on the screen. The features are now a row of small tiles above the bed, in groups (ground, water, supports, markers), each named when pointed at, and the sidebar is just the plantings. The sidebar also stays in view as a tall bed is scrolled, scrolling itself if the list of plantings is long. On a phone it still sits under the bed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Implement bed resizing functionality with drag support * Style the garden layout bed's edges, so they can be dragged The bed's right edge, bottom edge and corner had their drag handling but no styles, so they had no size or position and couldn't be grabbed. Now they sit over the timber frame, with a pale grip showing while the bed is pointed at, and a dashed outline shows the size the bed is being dragged to. The bed's column no longer clips, so that outline can show past it when the bed is dragged bigger. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Bring two garden layout feature specs up to date A chip dropped in the middle of the bed lands within a fraction of a pixel of the middle, not exactly on it. And shrinking the bed past something on it now says "things", as stones and fences count too, not "plants". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Wait for a garden to be reactivated before checking it "Mark as active" sends the change in the background, and the spec looked at the garden straight after clicking, so it failed whenever the request hadn't finished yet. It now waits for the page to come back first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> |
||
|
|
3d64118cdf |
Merge pull request #4837 from Growstuff/feat/fluent-crop-icons
Give crops icons from Fluent Emoji, chosen by crop wranglers |
||
|
|
27f4282f5b |
Let plantings use a crop's alternate name
A planting can now choose one of its crop's alternate names (eg. "lauki" for calabash, "aubergine" for eggplant) and shows it instead of the crop's primary name. - plantings.alternate_name_id, validated to belong to the planting's crop - Planting#display_name, used on cards, the planting page, garden lists, the member page, the homepage and the RSS/ICS feeds - planting form offers the crop's alternate names, preselecting the one that was searched for - crop autosuggest shows the matched alternate name, eg. "aubergine (eggplant)", via matched_alternate_name in the search JSON Part of #554 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
a05df8546f |
Colour progress bars by how the planting is getting on
Blue while growing, green while harvesting, amber when late, red when very late, grey when finished. The track is now neutral grey so every colour reads against it. Planting#progress_state decides, and the garden cards, planting progress and timeline bars use it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
9dae899693 |
Quick planting addition form (#4808)
* Add rake tasks to pull crops and a member's data from production crops:pull_from_production copies approved crops, and members:pull_from_production copies one member's gardens, plantings and planting photos, from growstuff.org into a local database. Both refuse to run in a production environment. They are built to be gentle on a server that has been struggling: one request at a time with a pause between requests, exponential backoff (honouring Retry-After) on timeouts, 429s and 5xx, and a hard stop rather than endless retries. The client also stops if a server keeps sending the same page, and will not follow a next link to another host. Gardens and plantings come from the site's own JSON, which carries every column; the JSON:API only exposes a garden's name, and its related resource endpoints return the wrong records. Only the crops that a member's plantings use are fetched. Flickr photos are stored as records pointing at Flickr's image URLs, as on production, so nothing is downloaded from Flickr. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add ACTIVE_ONLY option to the member import ACTIVE_ONLY=true leaves out the site's all=1 flag, so production lists only the member's active gardens and current (not finished, not failed) plantings. The server does the filtering, so it also means fewer requests, and no crops or photos are fetched for plantings that are skipped. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Bundle JavaScript with esbuild via jsbundling-rails Adds React and an esbuild build (yarn build, yarn build:watch) that writes app/assets/builds/react_islands.js, which Sprockets serves. jsbundling-rails runs the build as part of assets:precompile, which CI and the Dockerfile already run after yarn install. react_islands.jsx is the entry point: it mounts a React component into every element with data-react-component. No components are registered yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add react_component view helper Renders an empty element carrying the component name and its props as JSON, for react_islands.jsx to mount a React component into. Props go through Rails' attribute escaping. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Show a React GardenSummary island on the gardens index The first React island, to prove the pipeline end to end: server-rendered props (owner and garden count) drive a small component with client-side state. Loaded only on this page, deferred, via the scripts content block. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add GardenCardSerializer for the React garden cards Turns a page of gardens into plain hashes: the garden, its owner, its actions menu, and its active plantings split into perennials and annuals, with progress, badges and quick actions. It mirrors what gardens/_card, gardens/_actions and the planting partials render today, so the server still decides labels, links and permissions. Active plantings for the whole page are loaded in one query (with harvests and the crop's parents), instead of several queries per garden. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Render the garden cards on the index with React The gardens index now hands GardenCardSerializer's output to a GardenCards island instead of rendering gardens/_card per garden. The actions menu moves to the top right of the card header. Everything else on the card is the same: image, perennials, and each annual planting with badges, progress bar and its own quick actions menu. The server still chooses labels, links and permissions. The dropdowns keep the existing Bootstrap and jquery_ujs markup (data-bs-toggle, data-method, data-confirm), so mark inactive, delete and the confirmations work unchanged. Menu button ids are now unique per card, so the edit-from-index spec finds the menu by its Actions text instead of the old repeated id. gardens/_card stays for the activity page. This replaces the GardenSummary island, which only proved the pipeline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Don't raise when validating a planting that has no garden owner_must_match_garden_owner called garden.owner unconditionally, so a planting with a missing garden raised NoMethodError (a 500) instead of failing the garden presence validation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Create plantings as JSON for the React garden cards POST /plantings.json returns the garden's updated card (201), or the validation errors (422), so the cards can show a new planting without a page reload. It is for our own pages only: session cookie plus CSRF token, and no CORS headers, unlike the public /api/v1. Creating now also checks the garden is yours. Before, can :create Planting had no garden condition and create never authorized the garden, so a crafted request could plant into someone else's garden. This applies to the HTML form as well. A missing garden is still left to the presence validation. CanCan::AccessDenied now answers JSON requests with a 403 and an error, instead of redirecting them. The request spec logs in through a real cookie session to exercise CSRF protection: PlantingsController uses the null_session strategy, so a request without the token is treated as signed out (401), and the sign_in test helper would bypass that. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Don't ask which garden when planting from a garden Arriving at the planting form with a garden_id of one of your own gardens (from 'Plant something here') now shows 'Planting in <garden>' with a hidden garden field and a link to choose a different one, instead of the garden radio buttons. Any other arrival, including a garden_id that isn't yours, still asks as before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Open 'Plant something here' as a dialog over the garden cards Clicking 'Plant something here' on a card opens a dialog to plant into that garden, without leaving the list or asking which garden. Saving posts to POST /plantings.json, swaps in the garden's updated card so the new planting shows straight away (briefly highlighted, with a confirmation), and closes the dialog. Errors show inside it and it stays open. A ctrl/cmd/shift-click still opens the normal form. The dialog is a React-controlled Bootstrap modal: focus moves in and is trapped, Escape and the backdrop close it, and focus returns afterwards. The crop picker searches /crops/search.json like the existing autosuggest, and the planted-from and sun choices come from Planting's constants via props. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Use the Bootstrap 4 class names the app's CSS defines in the card components The stylesheet is MDB 4 (Bootstrap 4), with Bootstrap 5's JavaScript on top, so Bootstrap 5-only classes had no styling: the dialog's close button was btn-close (a small grey box), and visually-hidden, form-select and text-start did nothing. Use close with a times sign, sr-only, form-control and text-left, as the app's existing modals do. dropdown-menu-end stays, because Bootstrap 5's dropdown JavaScript reads it to place the menu; dropdown-menu-right is added for the CSS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the plant-something form read as a sentence 'I planted [N] [crop](s) on [date] from [seed] in [sun].' Each blank is an underlined inline field: quantity, the crop search, the planted date, and planted-from and sun/shade selects. The (s) drops away when the quantity is 1. The blanks are labelled for screen readers (Quantity, Crop, Planted date, Planted from, Sun or shade). Notes and 'Mark as finished' stay below. The browser spec now fills in quantity, planted from and sun as well, and checks they are saved. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Hint at typing a crop name, and offer to request one that isn't found The crop blank says 'type a crop name'. When a search finds nothing it says so and links to the new-crop form (in a new tab, so the dialog stays open), as the old planting form did. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Say 'number' in the quantity blank Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Choose a crop with the cursor keys The crop picker is now an accessible combobox. As you type, matches appear in a listbox: Up and Down move through them, Enter chooses the highlighted one (or the top match if none is highlighted), and Escape closes the list before a second Escape closes the dialog. Focus moves to 'Change' once a crop is chosen. Matches can still be clicked. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Trim the plant-something form to just the sentence Remove 'Mark as finished' and the 'Tell us more about it' notes from the dialog, along with the never-shown rating field it carried in its state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the highlighted crop match obvious The theme's list-group 'active' shade was barely darker than the other matches. The one Enter would choose now has a solid blue background, white bold text and a darker left edge. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Tidy the plant-something sentence layout Group the sentence into phrases (I planted..., on..., from..., in...) that stay together when it wraps, so a word is never stranded away from its blank. Hide the quantity spinner that clipped 'number', widen the date, and give the two selects a minimum width, with a grey 'optional' when they are still empty. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Don't let a second Enter undo a chosen crop After choosing a crop the input is replaced by the crop's name and a Change button. Focus went to that button, so pressing Enter again pressed it and cleared the choice. Focus now moves on to the date blank, so a second Enter submits the form as it would from any field. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Plant with one search and a confirmation, instead of the sentence form The dialog asks one big question, 'What did you plant?', with the same crop search as before (arrow keys, Enter, and a way to request a crop that isn't found). Choosing a crop shows it back ('You're planting lettuce in Orchard, today.') with Change and Plant it buttons, and focus lands on Plant it so Enter confirms. The planting gets today's date and no other details; those can be added later, which keeps adding one quick. Drops the sentence blanks, their styles, and the planted-from/sun option lists the page passed down. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix unreadable text on a just-planted crop The highlight for a newly added planting set an inline pale green background on the crop chip. Chips are brown with white text, so the name became white on light green. The highlight is now a CSS class that leaves the chip's colours alone: a soft green row with a left bar for annual plantings, and a green ring around the chip for perennials. The browser spec checks the chip carries no inline style. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Tidy the plant dialog and show what is happening at each stage Standard patterns so the dialog always says where you are and what it is doing: - a two-step indicator (Choose a crop, Confirm) with a tick on the finished step - a spinner in the search box while searching, plus a 'Searching...' status, a count of matches, and an info icon on the 'no crops match' note - the choice shown back as a Crop / Garden / When summary with a Change button - Plant it as a filled green primary button that stays green while focused (the theme greys a focused button) and shows a spinner while planting, with Cancel and Change disabled meanwhile - an error panel with a warning icon that says the choice is kept for retrying - the matches listed in the dialog rather than floating over its buttons - a tick on the 'Planted ...' notice on the cards - the shovel (spade-marker.svg, the map marker) in the dialog title Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Build the React bundle in CI and for fresh checkouts app/assets/builds/react_islands.js is built by esbuild and not committed, so on a fresh checkout pages that load it (the gardens index) fail with 'The asset react_islands.js is not present in the asset pipeline'. The rspec CI job never built it: only the browser-feature jobs did, through assets:precompile. Add a yarn build step there, and have the specs build the bundle once if it is missing so a local checkout doesn't fail either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add the missing 'View' translation The planting quick-actions menu used t('view'), which has no translation. In a view Rails hides that by showing a humanised 'View'; the card serializer uses I18n.t, which showed 'Translation missing: en.view' in the menu. Add buttons.view, use it in both places, and add a serializer spec that fails if any card label is a missing translation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix two crop_jsonld_data specs that could not pass The helper builds its hash with symbol keys, but the spec read 'data["@context"]' with a string key. And 'caps posts and photos at 50' relied on create(:post, crops: [crop]), which creates no crop_posts rows here, and on crop.photo_associations.create!, which the Crop model's own association leaves without a photographable. Link posts with CropPost and photos with PhotoAssociation explicitly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Run the helper and serializer specs in CI The rspec job ran lib, services, models, controllers, views, routing and requests, but not spec/helpers or spec/serializers, so those specs (including the react_component helper and the card serializer) never ran there, and two broken crops_helper specs went unnoticed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Tidy the garden cards The cards were cluttered and misaligned. Now: - the header has a smaller title with the owner under it, and the menu top right - a smaller picture, and 'Perennials' and 'Annuals' headings instead of a divider and a gap; 'Nothing planted here yet.' for an empty garden - each annual planting is a row of three aligned columns: the crop with when it was planted (which tells duplicates apart), then its badges and progress bar, then a labelled three-dots menu in place of a bare chevron - the note when there is nothing to predict from is one short muted line that no longer repeats the crop name - on a phone the picture and rows stack Also restores the just-planted highlight styles, which a stylesheet edit had dropped, and adds a spec that the highlight has a background, since the class existing was all that was checked. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Make the planting menu button compact The theme gives every .btn a 5.5rem minimum width, so the three-dots button's hover background was a wide grey box. It is now a 2.25rem round button. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
a3811cf9bd |
Optimize SearchCrops#search_data planters_ids and has_photos (#4806)
Use `.distinct` when fetching `planters_ids` to avoid duplicate member IDs and replace `photos.size` with the `photo_associations_count` counter cache column for `has_photos`. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
a349ce784a |
Optimize Like lookups in Likeable concern (#4799)
- Update liked_by? to return false if member is nil and use likes.exists?(member_id: member.id) instead of allocating login name arrays. - Simplify liked_by_members_names to use members.pluck(:login_name). - Update app/views/photos/_likes.html.haml to use photo.liked_by?(current_member). - Add unit tests for liked_by? in spec/models/like_spec.rb. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
4d87d9ccb9 |
Optimize places memory usage by paginating, plucking fields, and limiting nearest_to (#4792)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Brenda Wallace <brenda@wallace.net.nz> |
||
|
|
4dee371b34 |
Optimize CanCan abilities using declarative hash conditions (#4797)
Refactor block-based CanCan ability definitions for ScientificName, AlternateName, Planting, Activity, and Harvest into declarative hash conditions to eliminate per-record SQL queries and N+1 evaluation overhead. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
07f07e4c3d |
Merge pull request #4794 from Growstuff/improve-cache-memory-usage-9918781528129420138
Optimize caching memory usage in PhotoCapable and CropsHelper |
||
|
|
298a56f1c8 |
Use database distinct count for GardenType gardens
Replaces in-memory `.uniq.count`, `.uniq.empty?`, and `.uniq.each` calls with database-level `.distinct` queries on GardenType gardens association. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
2f43175324 |
Fallback to crop specific photos in PhotoCapable thumbnail_url (#4739)
* Implement crop photo fallback in PhotoCapable thumbnail_url Currently, plantings, seeds, and harvests display "no photo available" placeholders when they do not have specific photos attached. This change enables the PhotoCapable#thumbnail_url method to automatically fall back to the associated crop's thumbnail_url when no item-specific photo is present. Additionally, this commit: - Fixes validation in PhotoAssociation to handle crop photos that do not have a polymorphic photographable owner. - Disables cache store during testing to prevent stale/cached default photos from leaking across specs. - Adds comprehensive unit tests for the fallback logic. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Keep only core crop photo fallback and unit tests, removing excess changes Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
fa7f460510 |
Refactor Plantings to remove Elasticsearch dependency (#4686)
* Refactor Plantings to remove Elasticsearch dependency This commit refactors the Plantings controller, model, and views to use ActiveRecord instead of Searchkick/Elasticsearch. Key changes: - Refactored `PlantingsController#index` to use an ActiveRecord-based `plantings` method. - Moved `homepage_records` logic from `SearchPlantings` concern to the `Planting` model using ActiveRecord scopes. - Removed `SearchPlantings` concern and deleted the file. - Updated `home/_plantings.html.haml` and `plantings/index.rss.haml` to use dot notation for `Planting` object attributes. - Updated specs to remove Searchkick-related setup and assertions. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix Planting.reindex * Fix test * Mark test pending --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
6e7cf1c813 |
Refactor Seeds to remove Elasticsearch dependency (#4684)
* Refactor Seeds to remove Elasticsearch dependency This commit refactors the `SeedsController` and `Seed` model to remove dependency on Elasticsearch and Searchkick. Key changes: - Removed `SearchSeeds` concern from the `Seed` model. - Reimplemented `Seed.homepage_records` using ActiveRecord. - Refactored `SeedsController#index` to use ActiveRecord for filtering, eager loading, and pagination. - Deleted `app/models/concerns/search_seeds.rb`. - Updated relevant specs to remove Searchkick-specific tags and setup. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Remove Seed.reindex * Remove trait * Fix tests --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
3edd2510d8 |
Merge pull request #4683 from Growstuff/refactor-harvests-remove-elasticsearch-14630838429921835504
Refactor harvests to remove Elasticsearch |
||
|
|
97e236f7e8 |
Convert Photos controller to plain SQL queries
- Refactored `PhotosController#index` to use ActiveRecord queries instead of Searchkick/Elasticsearch. - Handled filtering by crop and planting via associations. - Added eager loading for the photo owner to prevent N+1 queries. - Decoupled the `Photo` model from Elasticsearch by removing the `SearchPhotos` concern. - Deleted `app/models/concerns/search_photos.rb`. - Updated controller and model specs to use standard ActiveRecord expectations. - Cleaned up the photo factory by removing the now-obsolete `:reindex` trait. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
1467ec9364 |
Add Wikidata climate attributes and integration to gardens (#4627)
* Add Wikidata integration for garden climate data - Add location_wikidata_id, lowest_temp_c, and highest_temp_c to gardens. - Implement WikidataService for fetching IDs and temperature properties. - Map P6591 to highest_temp_c and P7422 to lowest_temp_c with unit conversion. - Automatically populate Wikidata info on garden location change. - Add manual "Fetch Wikidata info" button and opt-in prompt to garden show page. - Update gardens_controller to permit new attributes and handle manual fetch. - Update db/schema.rb manually to include new columns and migration version. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix migration * Improve display --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
d7a50f86b5 |
Allow collaborators to remove themselves from gardens (#4630)
- Update Ability to grant destroy permission to collaborators for their own record - Add 'Leave garden' link to garden show page - Add specs for garden collaborator permissions Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
3d63d12908 |
Improve read performance with caching and memoization (#4572)
* Improve read performance with caching and memoization - Memoize `Crop#all_companions` and `Member#unread_count` in models - Implement instance-level memoization in `CropsHelper#crop_or_parent` - Add Rails caching for expensive aggregate queries in `Charts::CropsController` - Add fragment caching for high-impact sections on the crop show page Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix header spec failure due to memoized unread_count - Reset `@unread_count` in `spec/views/layouts/_header_spec.rb` to ensure the updated notification count is rendered correctly. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
035210197f |
Prompt for updated planting rating when harvesting (#4608)
* Update planting rating when recording a harvest - Added virtual attribute `overall_rating` to `Harvest` model. - Updated `HarvestsController` to permit `overall_rating` and synchronize it to the associated `Planting`. - Added a rating range field (1-5) to the harvest form. - Added controller tests to verify that the planting rating is updated. - Refined feature tests for harvesting. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * I have updated the system to allow for recording a planting rating when a harvest is logged. Here is a summary of the changes: - Added a virtual attribute `overall_rating` to the `Harvest` model. - Updated `HarvestsController` to permit `overall_rating` and synchronize it to the associated `Planting`. - Added a rating range field (1-5) to the harvest form. - Added controller tests to verify that the planting rating is updated correctly. - Updated feature tests to ensure the harvest form functions as expected. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Update database.yml * Apply suggestions from code review Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> * Adjust wording * Change harvest modal * Fix tests --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
8a8fd6eabd |
Merge pull request #4575 from Growstuff/memoize-unread-count
Memoize unread messages count |
||
|
|
e423e6ac79 |
Add weekly harvest reminder emails and scheduled task
- Added `send_harvest_reminder` preference to Member model and settings UI. - Implemented `harvest_in_next_week?` in PredictHarvest concern. - Created `harvest_reminder` email with localized templates. - Added `growstuff:send_harvest_reminders` Rake task to run weekly. - Refactored existing and new reminder tasks to use `deliver_later` for scalability. - Added unit tests for prediction logic and mailer. - Fixed a bug in the existing planting reminder task where it was using an uninitialized constant `Notifier`. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
7160f50ac1 |
Refactor Activity model to remove Elasticsearch integration (#4576)
* Refactor Activity model to remove Elasticsearch integration - Removed `SearchActivities` concern and Searchkick from `Activity` model. - Implemented `Activity.homepage_records` using ActiveRecord with `DISTINCT ON` for PostgreSQL. - Updated `ActivitiesController#index` to use ActiveRecord queries with eager loading and pagination. - Added `active` scope to `Activity`. - Added unit tests for `Activity` model. - Deleted `app/models/concerns/search_activities.rb`. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix NoMethodError: undefined method 'reindex' for class Activity - Removed all calls to `Activity.reindex` in migrations, rake tasks, and spec helpers. - These were causing failures after the removal of Searchkick from the Activity model. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix ambiguous column id in homepage_records query - Updated `Activity.homepage_records` to use `activities.id` instead of `id` in the subquery. - This resolves the `PG::AmbiguousColumn: ERROR: column reference "id" is ambiguous` error. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Fix ambiguous created_at in homepage_records query - Use `unscoped` in the subquery for `Activity.homepage_records` to bypass the default scope from `Ownable` concern. - This prevents the join with the `members` table in the subquery, which was causing `PG::AmbiguousColumn: ERROR: column reference "created_at" is ambiguous`. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Complete refactoring of Activity model to remove Elasticsearch - Removed SearchActivities concern and searchkick integration. - Updated ActivitiesController#index to use ActiveRecord queries. - Implemented performant Activity.homepage_records using DISTINCT ON (PostgreSQL). - Added Activity.active scope. - Added no-op Activity.reindex (class and instance methods) for backward compatibility. - Cleaned up leftover reindex calls in rake tasks, migrations, and spec helpers. - Added unit tests for new Activity model logic. - Updated factories to include no-op reindex traits. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Less eager loading --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
dfac51ee97 |
Merge pull request #4595 from Growstuff/optimize-harvests-caching-memoization-9176733581563564983
Optimize Harvests with memoization and fragment caching |
||
|
|
7360bc968b |
Merge pull request #4596 from Growstuff/flickr-tag-filtering-3395495860406820072
Add Flickr tag filtering for adding photos |
||
|
|
2e0c8a910d |
Memoize Planting-related methods for performance optimization
This commit introduces memoization to various methods in the Planting model, PredictPlanting and PredictHarvest concerns, PlantingsHelper, and PlantingsController. Specifically: - Memoized database-intensive lookups like `nearby_same_crop`, `first_harvest_date`, and `last_harvest_date`. - Memoized calculated fields like `finish_predicted_at`, `expected_lifespan`, and `age_in_days`. - Optimized `PlantingsHelper#transplantable_gardens_by_owner` using a hash to cache results per planting instance within a request. - Applied the `defined?(@variable)` pattern where appropriate to ensure efficient handling of `nil` results. These changes reduce redundant database queries and expensive calculations, particularly during view rendering where these methods are frequently accessed. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
3c70ba12ca |
Allow filtering Flickr photos by tag when adding photos
- Update MemberFlickr concern to support tag-based search using flickr.photos.search - Update PhotosController to handle the 'tag' parameter - Add tag search input field to the 'New Photo' view - Add test case to verify tag filtering in PhotosController spec Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
0df7589feb |
Optimize Harvests with memoization and fragment caching
- Memoize display methods in `Harvest` model. - Memoize calculation methods in `PredictHarvest` concern using `defined?` for nil safety. - Add fragment caching to `app/views/harvests/_popover.html.haml`. - Add fragment caching to `app/views/crops/_harvests.html.haml` with daily expiration for relative time strings. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
3127f45d0f |
Merge pull request #4578 from Growstuff/member-inactive-delete
Delete inactive members with no activity in 3 years |
||
|
|
8e7dd25e98 |
Add rake task to cleanup inactive members (#4574)
* Add members:cleanup_inactive rake task This task identifies and deletes members who have not logged in for over 24 months and have no gardens, plantings, or other activity (posts, comments, seeds, harvests, etc). Includes support for DRY_RUN=true to preview deletions. Added tests in spec/tasks/members_spec.rb. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Refactor activity check to Member#has_activity? and update rake task - Added `Member#has_activity?` to encapsulate the check for gardens, plantings, and other activity. - Updated `members:cleanup_inactive` rake task to use `Member#has_activity?`. - Maintained `DRY_RUN` support and existing tests. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Apply suggestion from @CloCkWeRX * Apply suggestions from code review Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |
||
|
|
5174b1236e |
Merge pull request #4567 from Growstuff/memory-optimisation-3
Members - Nearest To - Memory improvements |
||
|
|
8cfef5ce1a | Rubocop fixes | ||
|
|
209973e72b | Memory usage | ||
|
|
3b60e8f974 |
Implement blocking feature (#4199)
* Implement blocking feature This commit introduces a blocking feature that allows members to block other members. A blocked member is prevented from: - following the blocker - sending private messages to the blocker - replying to the blocker's posts - liking the blocker's content The implementation includes: - A new `Block` model and a corresponding database table. - Updates to the `Member` model to include associations for blocks. - A new `BlocksController` to handle blocking and unblocking actions. - New routes for the `BlocksController`. - UI changes to add block/unblock buttons to the member profile page. - Validations in the `Follow`, `Comment`, and `Like` models to enforce the blocking rules. - A check in the `MessagesController` to prevent sending messages to a member who has blocked the sender. - A callback in the `Block` model to destroy the follow relationship when a block is created. - New feature and model specs to test the blocking functionality. * Implement blocking feature and fix failing tests This commit introduces a blocking feature that allows members to block other members. A blocked member is prevented from: - following the blocker - sending private messages to the blocker - replying to the blocker's posts - liking the blocker's content The implementation includes: - A new `Block` model and a corresponding database table. - Updates to the `Member` model to include associations for blocks. - A new `BlocksController` to handle blocking and unblocking actions. - New routes for the `BlocksController`. - UI changes to add block/unblock buttons to the member profile page. - Validations in the `Follow`, `Comment`, and `Like` models to enforce the blocking rules. - A check in the `MessagesController` to prevent sending messages to a member who has blocked the sender. - A callback in the `Block` model to destroy the follow relationship when a block is created. - New feature and model specs to test the blocking functionality. This commit also fixes a failing test in the blocking feature. The error was caused by the validation being called even when the `member` association was `nil`. A guard has been added to the validation methods in the `Like`, `Follow`, and `Comment` models to prevent this from happening. * Generate schema * Fix tests * Add permissions * Define Block permissions in Ability model The feature specs for member blocking were failing because the "Block" link was not being rendered on member profiles. This was due to the lack of explicit create and destroy permissions for the Block resource in the Ability model, which is used by CanCanCan to authorize actions and by the view to conditionally show links. This change adds the necessary permissions to `member_abilities`: - Allows members to create blocks (except for blocking themselves). - Allows members to destroy blocks where they are the blocker. These rules ensure that the "Block" and "Unblock" links are correctly rendered and authorized for signed-in members. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> * Comment out specs for now --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> |
||
|
|
ed87d23ece |
Merge pull request #4560 from Growstuff/fix-i18n-locale-texts-16171345716630423189
Fix Rails/I18nLocaleTexts RuboCop errors |
||
|
|
d0ca944899 | Relax the criteria as photos are uploaded less often | ||
|
|
c45b75a967 |
feat: Add nutritional data partial to crops and harvests
This commit introduces a new partial to display nutritional data from the Australian Food Composition Database. Key changes: - Adds a database index to the `public_food_key` on the `crops` table. - Establishes a `has_one` relationship between `Crop` and `AustralianFoodClassificationData`. - Creates a `_nutritional_data.html.haml` partial to display a summary of key nutritional information. - Renders the partial on the `show` pages for both crops and harvests. |
||
|
|
620337fbac |
Merge pull request #4353 from Growstuff/feat/import-australian-food-data
Add Rake Task to Import Australian Food Data |
||
|
|
13a8276313 |
Add version tracking to crops model (#4343)
* feat: Add version tracking to Crop model This commit introduces version tracking for the Crop model using the PaperTrail gem. Key changes include: - Integrating `has_paper_trail` into the `Crop` model. - Adding a "History" section to the crop show page to display a timeline of changes for that specific crop. - Creating a new admin page for users with the "crop_wrangler" role to view a log of all recent crop edits, creations, and deletions. - Fixing several N+1 query performance issues by eager-loading associated `Member` records in both the `CropsController` and the new `Admin::CropsController`. - Refactoring view logic into a shared partial to reduce code duplication. * Add papertrail * Admin UI * Add papertrail DB * Add papertrail DB * Rearrange * Fix permissions * Fix permissions * Fix UI * Fix UI --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com> |
||
|
|
cef23b8212 | More recursive companions | ||
|
|
ba9117db4d |
I have added the before_destroy callback to the Crop model to destroy all CropCompanion records where the crop is crop_b. (#4266)
I have added a new test to `spec/models/crop_spec.rb` to verify that deleting a crop also destroys the associated `CropCompanion` records. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> |