Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Global Timeline #2265

Merged

Conversation

michael-genson
Copy link
Collaborator

@michael-genson michael-genson commented Mar 18, 2023

What type of PR is this?

(REQUIRED)

  • feature

What this PR does / why we need it:

(REQUIRED)

This adds a brand new "global" page to Mealie that features the entire group's timeline events. It re-uses the recipe-specific timeline view, but expands the functionality to include recipe cards (so you can see which recipe the event is for). It also fixes tons of little formatting issues with the existing timeline, particularly for mobile users.

In addition to the new page, many of the recipe timeline event components were abstracted into sub components to make everything more reusable. I also needed to extend the query filter API to understand related table properties (more on that below).


Global Timeline

The Global Timeline is the main focus of this PR. It adds a new shiny menu button:
image

Which brings you here:
image

Or, on mobile:
image

A few things to point out here:

  1. This shows you all events from all recipes, as opposed to only showing events for a single recipe (which is what the old dialog does).
  2. The recipe cards are inserted on the event for easy reference (and so you know which recipe the event came from!)
  3. On mobile, the recipe card layout is modified to put the picture on top (since we have very little horizontal space to work with)

Since recipes need to be loaded to display the recipe card, we can't just load all of the events at once like we could on the individual recipe page. To fix this, I implemented infinite scrolling/pagination:
2023-03-18_16h37_34

I have a local cache for recipes so they're only fetched once (rather than once per event). When we eventually implement a "light" recipe API we can speed this up by using that instead.

On mobile:
2023-03-18_16h40_48

You'll also notice there's a button to switch the event direction (oldest to newest vs newest to oldest). This is cached in local storage so it's remembered between sessions.

All of the enhancements to the timeline were applied to the timeline components, so individual recipe timelines see these changes too (but recipes are disabled):
image


Query Filter API

For this to work, I needed to be able to fetch all timeline events for a particular group. We don't store the group on the timeline event, we only have the user (which belongs to a group). I modified the events API to not require a recipe when querying (but it's still required for creating them), and added support for related fields on the query API.

So, for instance, this is the queryFilter for the global timeline:
recipe.group_id="${groupId}"

And for an individual recipe, we don't need the recipeId prop anymore:
recipe.slug="${props.slug}"

Recipe API

Since the event only stores the recipe id, and I need to fetch the recipe to display the recipe card, I needed a way to fetch a recipe by its id. I feel like we've needed this a few times before but always worked around it.

I added a simple check to the "get recipe" API that checks if the provided value is a valid UUID, and if it is, look for the recipe by id instead of by slug. So now you can supply either the slug or the id and the API will figure it out.

def get_one_by_slug_or_id(self, slug_or_id: str | UUID) -> Recipe | None:
    if isinstance(slug_or_id, str):
        try:
            slug_or_id = UUID(slug_or_id)
        except ValueError:
            pass

    if isinstance(slug_or_id, UUID):
        return self._get_recipe(slug_or_id, "id")

    else:
        return self._get_recipe(slug_or_id, "slug")

Miscellaneous Visual Improvements

Since this touched a lot of components, I made some revisions on how certain components render. Here is a summary of those:

  • The timeline item is much more mobile friendly with limited horizontal space
  • The recipe card can optionally be flipped vertically (where the image is above the card, rather than to the left) and is a bit more flexible in wrapping some components
  • The loading animation is properly centered (rather than being off to the far left which has been bugging me forever) and can accept an arbitrary loading text

Which issue(s) this PR fixes:

(REQUIRED)

N/A

Special notes for your reviewer:

(fill-in or delete this section)

I know a more modular infinite scroll is being worked on, so whenever that's completed we can probably swap out the one I built here. It's more-or-less the same as the existing recipe one, just tweaked to work with timeline events.

I had to do some fun DOM stuff to get the scroll events to register properly (the v-card intersect method used with the recipe infinite scroll wasn't working like 80% of the time for some reason). It looks a little gross but it works super consistently (I also saw a ton of variations on the same premise on multiple stack overflow posts, which is where the idea came from).

Testing

(fill-in or delete this section)

Updated pytest with the API changes and added a new test for the new nested filter functionality. For the frontend I tested it to death locally (standard and mobile layouts).

Release Notes

(REQUIRED)

added new global timeline page to view all timeline events across the entire group
added support for filtering related table properties using the query filter API
added support for fetching a recipe by id (in addition to fetching by slug)

@github-advanced-security
Copy link

You have successfully added a new Trivy configuration .github/workflows/pull-requests.yml:build. As part of the setup process, we have scanned this repository and found 5 existing alerts. Please check the repository Security tab to see all alerts.

@cmintey
Copy link
Contributor

cmintey commented Mar 24, 2023

My only suggestion with this is maybe move the timeline button below the shopping lists. The reason for this is that shopping lists will probably be used more frequently. Other than that, I like it!

@michael-genson
Copy link
Collaborator Author

My only suggestion with this is maybe move the timeline button below the shopping lists. The reason for this is that shopping lists will probably be used more frequently.

I think that's a good suggestion, I'll move it. I put it under the meal planner because it "relates" to the planner more, but I think your point that the shopping list is more frequently used is more significant

@hay-kot hay-kot merged commit fe17922 into mealie-recipes:mealie-next Apr 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants