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

Major overhaul (RecipeView update, sections support, recipes list view, ...) #2115

Draft
wants to merge 188 commits into
base: master
Choose a base branch
from

Conversation

seyfeb
Copy link
Collaborator

@seyfeb seyfeb commented Jan 31, 2024

Topic and Scope

A lot of the UI is touched, with a focus on the RecipeView.

This PRs goal is manifold:

  • Introduction of model classes for schema.org entities should provide a cleaner way of dealing with recipe data
    • The correct format of the received JSON data is checked during parsing
    • The model classes support complex scenarios like (nested) sections in recipe instructions. Those could have their own set of ingredients and tools by collecting those from child directions, tips, ...
    • Added "support" for (until now) unused property supply, which would allow structuring ingredients
  • List of recipes:
    • Adding a list view as an alternative to the grid view currently used for selecting recipes. This was requested (e.g., Complete rework of frontend #1244) to be more in line with other Nextcloud apps. However, further appointments with the NC design team surfaced more votes towards the previous grid-style view. Since the implementation was already largely done, there are now both available, though the list view is currently hidden from the user.
    • complete rework of filter logic similar to github
  • Restructured paths
    • With the introduction of the list view which required additional <router-view>s the need for a different structure of the URL

Some minor changes/fixes that popped up during development include additional helper functions, file restructuring, improving the Jest config and reworking the RecipeView:

  • Updated image: No collapsing anymore, click opens image in modal
  • Improved spacing
  • Improved headline sizing
  • Updated recipe-yield input (updated style of buttons and input, changes from default value are highlighted)
  • Updated main timer visuals (less intrusive, running timer is highlighted with larger font)
  • Updated recipe instructions
    • moved to separate component
    • non-bold font consistent with rest of the recipe, completed ingredients get muted text color
    • ingredients in sections are indented (solely CSS, JS props for indenting are removed)
  • Unify indents of ingredients, tools, and nutrition information
  • Add dynamic padding and max size to content, such that on large displays the recipe info does not get "stretched" to wide
  • Move certain information to a sidebar in the RecipeView
  • AppControls omit redundant "Viewing recipe" and adds currently viewed section's name as subtitle. The edit button resizes to icon-only for small viewports
  • many more ...

Related: #382 #428 #311 #135 #1875 #1244

Closes #1855 closes #2114

Currently supported in RecipeView

  • More complex structures for recipe instructions
    • Top-level HowToSections
      • HowToSection's title
      • HowToSection's description
      • HowToSection's sub-steps
      • HowToTips in HowToSection
    • Top-level array of mixed HowToSections, HowToSteps and strings
    • Nested HowToSections (At some point this might even be confusing for the user) Note: In a meeting w/ the NC design team, we decided not to support nested sections (for now).
    • Display summarized supply of all nested HowToDirections in a HowToSection
    • Display summarized tools of all nested HowToDirections in a HowToSection
    • HowToTips in HowToStep
  • HowToTool objects in Recipe
  • HowToSupply objects in Recipe
  • NutritionInformation objects in Recipe

Concerns/issues

Currently the UI does not support

  • viewing recipes with sections, tips, etc. in the full glory (see above)
  • editing recipes with sections, tips, etc.

We need to consider how to handle recipes where both supply and recipeIngredient are defined.

Supported properties are checked for their correctness, but additional properties, e.g., those allowed by the schema.org standard that are not supported in our app are currently ignored.

Recipes List

  • There should be an API endpoint to allow renaming a recipe so we don't need to down-/upload the complete recipe just to change the name

Restructured paths

With the introduction of the list view which required additional <router-view>s the need for a different structure of the URLs appeared that allows defining the selected (filtered) list of recipes as well as a selected recipe. Currently the routes look like:

  • category/:value
  • tags/:value
  • search/:value

for filtering/searching the available recipes. These paths can remain the same. However if additional filters are applied, they are added as query parameters.

  • category/:value?q=tag%3A%2522spicy%2522 (?q=tag:"spicy")
  • etc.

When viewing a recipe the user was directed to

  • recipe/:id

This would loose the information that the recipe was, e.g., selected from a list of recipes within a specific category, maybe filtered down by certain parameters. This PR introduces new paths in the form of

  • category/:value/:id?q=tag%3A%2522spicy%2522 (?q=tag:"spicy")`
  • etc.

where id is the recipe identifier. Navigating to the URL will show the same view as before when the list view is selected: A filtered list with the recipe open next to it. For editing the recipe the path

  • category/:value/:id/edit?q=tag%3A%2522spicy%2522
  • etc.

is introduced.

Try out locally

Although the backend does not support the current structure it is possible to test this locally. You may start with copying the JSON code to a recipe.json file in a new subdirectory of the Recipes/ folder. If you wish you can download some image and add it as full.jpg to the same folder.

Then you need to make two tweaks to the PHP code. In FixInstructionsFilter.php early return the apply function

public function apply(array &$json): bool {
		return true;
  // Rest does not matter
}

and in FixToolsFilter.php in the apply function remove the else block and early return

//		else {
//			$tools = array_map(function ($t) {
//				$t = trim($t);
//				$t = $this->textCleaner->cleanUp($t, false);
//				return $t;
//			}, $json[self::TOOLS]);
//			$tools = array_filter($tools, fn ($t) => ($t));
//			ksort($tools);
//			$tools = array_values($tools);
//		}
		return false;

Preview

Current state of the RecipeView. The following JSON produces below image

Recipe JSON
{
  "@context": "https://schema.org/",
  "@type": "Recipe",
  "name": "Chocolate Cake",
  "description": "A delicious and moist chocolate cake recipe.",
  "image": "cake.jpg",
  "recipeCategory": "Dessert",
  "cookTime": "PT40M",
  "prepTime": "PT20M",
  "totalTime": "PT1H",
  "recipeYield": 12,
  "url": "https://my-yummy-recipes.io/choc-cake/",
  "keywords": ["cake", "chocolate", "juicy", "dessert"],
  "recipeIngredient": [
    "1/2 teaspoon salt",
    "2 large eggs",
    "1 cup milk",
    "1/2 cup vegetable oil",
    "2 teaspoons vanilla extract",
    "1 cup boiling water"
  ],
  "supply" : [
    {
      "@type": "HowToSupply",
      "name": "all-purpose flour",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 2,
        "unitText": "cups"
      },
      "description": "Main ingredient for the recipe"
    },
    {
      "@type": "HowToSupply",
      "name": "granulated sugar",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 1,
        "unitText": "cup"
      },
      "description": "Sweetens the recipe"
    },
    {
      "@type": "HowToSupply",
      "name": "unsweetened cocoa powder",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 1,
        "unitText": "cup"
      }
    },
    {
      "@type": "HowToSupply",
      "name": "baking powder",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 1,
        "unitText": "teaspoon"
      }
    },
    {
      "@type": "HowToSupply",
      "name": "baking soda"
    }
  ],
  "tool": [
    "mixing bowl",
    "whisk",
    "sifter",
    {
      "@type": "HowToTool",
      "name": "measuring cups",
      "requiredQuantity": 2,
      "description": "grandma's **nice** ones"
    },
    "measuring spoons",
    "cake pans"
  ],
  "nutrition": {
    "@type": "NutritionInformation",
    "servingSize": "1 slice",
    "calories": "250 calories",
    "fatContent": "12 grams",
    "carbohydrateContent": "30 grams",
    "proteinContent": "8 grams",
    "sodiumContent": "500 milligrams",
    "fiberContent": "2 grams",
    "sugarContent": "5 grams"
  },
  "recipeInstructions": [
    {
      "@type": "HowToSection",
      "name": "Prepare Dry Ingredients",
      "description": "Prepare the dry Ingredients by mixing them together. Follow the steps closely to get a perfect result!",
      "itemListElement": [
        {
          "@type": "HowToStep",
          "text": "Mix together the flour, sugar, cocoa, baking powder, baking soda, and salt in a large bowl.",
          "position": 1,
          "timeRequired": "PT5M"
        },
        {
          "@type": "HowToStep",
          "text": "Sift the dry ingredients to remove any lumps.",
          "position": 2,
          "timeRequired": "PT2M",
          "itemListElement": [
            {
              "@type": "HowToDirection",
              "text": "Pour dry ingredients in a sieve",
              "timeRequired": "PT1M",
              "tool": [
                "mixing bowl",
                "sifter",
                {
                  "@type": "HowToTool",
                  "name": "measuring cups",
                  "requiredQuantity": 2,
                  "description": "grandma's **nice** ones"
                },
                "measuring spoons"
              ]
            },
            {
              "@type": "HowToDirection",
              "text": "Move a spoon clockwise in the sieve to apply some pressure on the ingredients.",
              "timeRequired": "PT1M",
              "supply" : [
                {
                  "@type": "HowToSupply",
                  "name": "all-purpose flour",
                  "requiredQuantity": {
                    "@type": "QuantitativeValue",
                    "value": 2,
                    "unitText": "cups"
                  },
                  "description": "Main ingredient for the recipe"
                },
                {
                  "@type": "HowToSupply",
                  "name": "granulated sugar",
                  "requiredQuantity": {
                    "@type": "QuantitativeValue",
                    "value": 1,
                    "unitText": "cup"
                  },
                  "description": "Sweetens the recipe"
                }
              ]
            },
            {
              "@type": "HowToTip",
              "text": "Use a hair sieve"
            }
          ]
        },
        {
          "@type": "HowToStep",
          "position": 3,
          "timeRequired": "PT1M",
          "itemListElement": [
            {
              "@type": "HowToDirection",
              "text": "Set aside the dry ingredients for later use.",
              "timeRequired": "PT1M",
              "supply" : [
                {
                  "@type": "HowToSupply",
                  "name": "baking powder",
                  "requiredQuantity": {
                    "@type": "QuantitativeValue",
                    "value": 1,
                    "unitText": "teaspoon"
                  }
                },
                {
                  "@type": "HowToSupply",
                  "name": "baking soda"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "@type": "HowToSection",
      "name": "Wet ingredients",
      "description": "Prepare the Wet Ingredients",
      "itemListElement": [
        {
          "@type": "HowToStep",
          "text": "In a separate bowl, whisk together the eggs, milk, oil, and vanilla extract.",
          "position": 1,
          "timeRequired": "PT5M"
        },
        {
          "@type": "HowToStep",
          "text": "Gradually add the wet ingredients to the dry ingredients, stirring until well combined.",
          "position": 2,
          "timeRequired": "PT3M"
        },
        {
          "@type": "HowToStep",
          "text": "Pour in the boiling water and mix until smooth.",
          "position": 3,
          "timeRequired": "PT2M"
        }
      ]
    }
  ]
}

RecipeView:

Screen Shot 2024-05-02 at 09 11 43

Details sidebar opened:

Screen Shot 2024-05-02 at 09 11 47

Recipe sections

Screen Shot 2024-05-02 at 09 12 19

Clicking an image opens a modal with a slideshow of the full images:

Screen Shot 2024-05-02 at 09 39 18

Wide screen

The width of the recipe content is limited to maintain readability

Screen Shot 2024-05-02 at 09 37 58

Narrow screen

List view

Screen Shot 2024-05-02 at 09 13 08

Screen Shot 2024-05-02 at 09 13 20

Filtering:

Filter modal opened:

Screen Shot 2024-05-02 at 09 13 29

Filter selected (URL gets updated to ${HOST}/index.php/apps/cookbook/#/category/Dinner/412?q=tag%3A%2522spicy%2522):

Screen Shot 2024-05-02 at 09 13 41

Formal requirements

There are some formal requirements that should be satisfied. Please mark those by checking the corresponding box.

  • I did check that the app can still be opened and does not throw any browser logs
  • I created tests for newly added PHP code (check this if no PHP changes were made)
  • I updated the OpenAPI specs and added an entry to the API changelog (check if API was not modified)
  • I notified the matrix channel if I introduced an API change

@seyfeb seyfeb added enhancement New feature or request php Pull requests that update Php code javascript Pull requests that update Javascript code Backend Issue or PR related to the backend code Frontend Issue or PR related to the frontend code labels Jan 31, 2024
@seyfeb seyfeb marked this pull request as draft January 31, 2024 17:21
Copy link

codecov bot commented Jan 31, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 80.07%. Comparing base (153511f) to head (54de35b).
Report is 164 commits behind head on master.

❗ Current head 54de35b differs from pull request most recent head 6c27422. Consider uploading reports for the commit 6c27422 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #2115   +/-   ##
=======================================
  Coverage   80.07%   80.07%           
=======================================
  Files          92       92           
  Lines        2650     2650           
=======================================
  Hits         2122     2122           
  Misses        528      528           
Flag Coverage Δ
integration 21.43% <ø> (ø)
migration 5.69% <ø> (ø)
unittests 57.09% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Copy link

github-actions bot commented Jan 31, 2024

Test Results

   12 files    572 suites   1m 31s ⏱️
  552 tests   552 ✅ 0 💤 0 ❌
2 208 runs  2 207 ✅ 1 💤 0 ❌

Results for commit 54de35b.

♻️ This comment has been updated with latest results.

@seyfeb seyfeb force-pushed the refactor/add-schema-js-classes branch 2 times, most recently from 4a16282 to 3005528 Compare February 13, 2024 09:30
…nd `title-rename.js` to typescript

Signed-off-by: Sebastian Fey <[email protected]>
…nd `QuantitativeValue`.

Signed-off-by: Sebastian Fey <[email protected]>
…imple strings for `tool`, `recipeInstructions`, and `supply` properties

Signed-off-by: Sebastian Fey <[email protected]>
…uctions`, and `supply` properties to `fromJSON` method of `Recipe`.

Signed-off-by: Sebastian Fey <[email protected]>
…ud/axios usage.

Fix wrong import order in `HowToTool`

Signed-off-by: Sebastian Fey <[email protected]>
seyfeb added 12 commits May 1, 2024 11:44
…issing route names. Fix 'All recipes' view.

Signed-off-by: Sebastian Fey <[email protected]>
…s without requiring page reload.

Signed-off-by: Sebastian Fey <[email protected]>
@seyfeb seyfeb changed the title Add schema.org model classes Major overhaul (RecipeView update, sections support, recipes list view, ...) May 3, 2024
seyfeb added 13 commits May 3, 2024 14:55
Signed-off-by: Sebastian Fey <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Frontend Issue or PR related to the frontend code javascript Pull requests that update Javascript code
Projects
None yet
1 participant