diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 5df2230ca..dc6f341fc 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -11,6 +11,8 @@ on: jobs: tests: + env: + PRODUCTION: false runs-on: ubuntu-latest steps: #---------------------------------------------- diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9b7582bd1..24b1da2e0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -52,6 +52,15 @@ "group": "groupA" }, "problemMatcher": [] + }, + { + "label": "Run python tests", + "command": "make test", + "type": "shell", + "presentation": { + "reveal": "always" + }, + "problemMatcher": [] } ] } diff --git a/Dockerfile b/Dockerfile index 2528d200b..e1321727d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ RUN apk add --no-cache libxml2-dev \ zlib-dev -ENV ENV True +ENV PRODUCTION true EXPOSE 80 WORKDIR /app/ @@ -40,14 +40,15 @@ RUN apk add --update --no-cache --virtual .build-deps \ cd /app/ && poetry install --no-root --no-dev && \ apk --purge del .build-deps - COPY ./mealie /app/mealie RUN poetry install --no-dev + COPY ./Caddyfile /app COPY ./dev/data/templates /app/data/templates COPY --from=build-stage /app/dist /app/dist VOLUME [ "/app/data/" ] + RUN chmod +x /app/mealie/run.sh CMD /app/mealie/run.sh diff --git a/Dockerfile.dev b/Dockerfile.dev index 918a7c432..2c5519117 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -2,6 +2,8 @@ FROM python:3 WORKDIR /app/ +ENV PRODUCTION false + RUN apt-get update -y && \ apt-get install -y python-pip python-dev @@ -14,12 +16,9 @@ RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get- # Copy poetry.lock* in case it doesn't exist in the repo COPY ./pyproject.toml /app/ -# RUN poetry install - COPY ./mealie /app/mealie RUN poetry install -RUN ["poetry", "run", "python", "mealie/db/init_db.py"] -RUN ["poetry", "run", "python", "mealie/services/image/minify.py"] -CMD ["poetry", "run", "python", "mealie/app.py"] \ No newline at end of file +RUN chmod +x /app/mealie/run.sh +CMD ["/app/mealie/run.sh", "reload"] diff --git a/depends/download-and-extract.sh b/depends/download-and-extract.sh deleted file mode 100644 index faa8b1ad1..000000000 --- a/depends/download-and-extract.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# Usage: ./download-and-extract.sh something https://example.com/something.tar.gz - -archive=$1 -url=$2 - -if [ ! -f $archive.tar.gz ]; then - wget -O $archive.tar.gz $url -fi - -rm -r $archive -tar -xvzf $archive.tar.gz \ No newline at end of file diff --git a/depends/install_webp.sh b/depends/install_webp.sh deleted file mode 100644 index 1c83eacc7..000000000 --- a/depends/install_webp.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# install webp - -archive=libwebp-1.2.0 - -./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz - -pushd $archive - -./configure --prefix=/usr --enable-libwebpmux --enable-libwebpdemux && make -j4 && sudo make -j4 install - -popd \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index a55b1f07f..6e1aac0a9 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -29,7 +29,7 @@ services: db_type: sqlite TZ: America/Anchorage # Specify Correct Timezone for Date/Time to line up correctly. volumes: - - ./app_data:/app_data + - ./dev/data:/app/dev/data - ./mealie:/app/mealie # Mkdocs diff --git a/docs/docs/api-usage/bulk-url-import.md b/docs/docs/api-usage/bulk-url-import.md new file mode 100644 index 000000000..130e42d9a --- /dev/null +++ b/docs/docs/api-usage/bulk-url-import.md @@ -0,0 +1,93 @@ +!!! info + This example was submitted by a user. Have an Example? Submit a PR! + + +Recipes can be imported in bulk from a file containing a list of URLs. This can be done using the following bash or python scripts with the `list` file containing one URL per line. + +#### Bash +```bash +#!/bin/bash + +function authentification () { + auth=$(curl -X 'POST' \ + "$3/api/auth/token" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=&username='$1'&password='$2'&scope=&client_id=&client_secret=') + + echo $auth | sed -e 's/.*token":"\(.*\)",.*/\1/' +} + +function import_from_file () { + while IFS= read -r line + do + echo $line + curl -X 'POST' \ + "$3/api/recipes/create-url" \ + -H "Authorization: Bearer $2" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{"url": "'$line'" }' + echo + done < "$1" +} + +input="list" +mail="changeme@email.com" +password="MyPassword" +mealie_url=http://localhost:9000 + + +token=$(authentification $mail $password $mealie_url) +import_from_file $input $token $mealie_url + +``` + +#### Python +```python +import requests +import re + +def authentification(mail, password, mealie_url): + headers = { + 'accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + } + data = { + 'grant_type': '', + 'username': mail, + 'password': password, + 'scope': '', + 'client_id': '', + 'client_secret': '' + } + auth = requests.post(mealie_url + "/api/auth/token", headers=headers, data=data) + token = re.sub(r'.*token":"(.*)",.*', r'\1', auth.text) + return token + +def import_from_file(input_file, token, mealie_url): + with open(input_file) as fp: + for l in fp: + line = re.sub(r'(.*)\n', r'\1', l) + print(line) + headers = { + 'Authorization': "Bearer " + token, + 'accept': 'application/json', + 'Content-Type': 'application/json' + } + data = { + 'url': line + } + response = requests.post(mealie_url + "/api/recipes/create-url", headers=headers, json=data) + print(response.text) + +input_file="list" +mail="changeme@email.com" +password="MyPassword" +mealie_url="http://localhost:9000" + + +token = authentification(mail, password, mealie_url) +import_from_file(input_file, token, mealie_url) +``` + diff --git a/docs/docs/api-usage/getting-started.md b/docs/docs/api-usage/getting-started.md new file mode 100644 index 000000000..95abfd6a1 --- /dev/null +++ b/docs/docs/api-usage/getting-started.md @@ -0,0 +1,39 @@ +# Usage + +## Getting a Token + +Currently Mealie doesn't support creating a long-live token. You can however get a token from the API. This example was pulled from the automatic API documentation provided by Mealie. + +### Curl +```bash +curl -X 'POST' \ + 'https://mealie-demo.hay-kot.dev/api/auth/token' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=&username=changeme%40email.com&password=demo&scope=&client_id=&client_secret=' + +``` + +#### Response +```json +{ + "snackbar": { + "text": "User Successfully Logged In", + "type": "success" + }, + "access_token": "your-long-token-string", + "token_type": "bearer" +} +``` + +## Key Components + +### Exploring Your Local API +On your local installation you can access interactive API documentation that provides `curl` examples and expected results. This allows you to easily test and interact with your API to identify places to include your own functionality. You can visit the documentation at `http://mealie.yourdomain.com/docs or see the example at the [Demo Site](https://mealie-demo.hay-kot.dev/docs) + +### Recipe Extras +Recipes extras are a key feature of the Mealie API. They allow you to create custom json key/value pairs within a recipe to reference from 3rd part applications. You can use these keys to contain information to trigger automation or custom messages to relay to your desired device. + +For example you could add `{"message": "Remember to thaw the chicken"}` to a recipe and use the webhooks built into mealie to send that message payload to a destination to be processed. + +![api-extras-gif](../assets/gifs/api-extras.gif) diff --git a/docs/docs/api-usage/home-assistant.md b/docs/docs/api-usage/home-assistant.md new file mode 100644 index 000000000..4de60be82 --- /dev/null +++ b/docs/docs/api-usage/home-assistant.md @@ -0,0 +1,30 @@ +In a lot of ways, Home Assistant is why this project exists! Since it Mealie has a robust API it makes it a great fit for interacting with Home Assistant and pulling information into your dashboard. + +### Get Todays Meal in Lovelace +Starting in v0.4.1 you are now able to use the uri `/api​/meal-plans​/today​/image?group_name=Home` to directly access the image to todays meal. This makes it incredible easy to include the image into your Home Assistant Dashboard using the picture entity. + +Here's an example where `sensor.mealie_todays_meal` is pulling in the meal-plan name and I'm using the url to get the image. + +![api-extras-gif](../assets/img/home-assistant-card.png) + +```yaml +type: picture-entity +entity: sensor.mealie_todays_meal +name: Dinner Tonight +show_state: true +show_name: true +image: 'http://localhost:9000/api/meal-plans/today/image?group_name=Home' +style: +.: | + ha-card { + max-height: 300px !important; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + } +``` + + +!!! tip + Due to how Home Assistant works with images, I had to include the additional styling to get the images to not appear distorted. This includes and [additional installation](https://github.com/thomasloven/lovelace-card-mod) from HACS. diff --git a/docs/docs/assets/img/home-assistant-card.png b/docs/docs/assets/img/home-assistant-card.png new file mode 100644 index 000000000..9a6e46acc Binary files /dev/null and b/docs/docs/assets/img/home-assistant-card.png differ diff --git a/docs/docs/changelog/v0.4.1.md b/docs/docs/changelog/v0.4.1.md index 4ed6b7e9e..9ab671f6a 100644 --- a/docs/docs/changelog/v0.4.1.md +++ b/docs/docs/changelog/v0.4.1.md @@ -4,6 +4,13 @@ **Database Version: v0.4.0** +!!! error "Breaking Changes" + + #### Recipe Images + While it *shouldn't* be a breaking change, I feel it is important to note that you may experience issues with the new image migration. Recipe images are now minified, this is done on start-up, import, migration, and when a new recipe is created. The initial boot or load may be a bit slow if you have lots of recipes but you likely won't notice. What you may notice is that if your recipe slug and the image name do not match, you will encounter issues with your images showing up. This can be resolved by finding the image directory and rename it to the appropriate slug. I did fix multiple edge cases, but it is likely more exists. As always make a backup before you update! + + On the plus side, this comes with a huge performance increase! 🎉 + - Add markdown support for ingredients - Resolves #32 - Ingredients editor improvements - Fix Tags/Categories render problems on recipes @@ -19,5 +26,10 @@ - A smaller image is used for recipe cards - A 'tiny' image is used for search images. - Advanced Search Page. You can now use the search page to filter recipes to include/exclude tags and categories as well as select And/Or matching criteria. -- First day of the week in a calendar (Meal planner) is now customizable in Site Settings. +- Added link to advanced search on quick search +- Better support for NextCloud imports + - Translate keywords to tags + - Fix rollback on failure +- Recipe Tag/Category Input components have been unified and now share a single way to interact. To add a new category in the recipe editor you need to click to '+' icon next to the input and fill out the form. This is the same for adding a Tag. + diff --git a/docs/docs/changelog/v0.4.2.md b/docs/docs/changelog/v0.4.2.md new file mode 100644 index 000000000..65c6ea6b4 --- /dev/null +++ b/docs/docs/changelog/v0.4.2.md @@ -0,0 +1,24 @@ +# v0.4.2 + +**App Version: v0.4.2** + +**Database Version: v0.4.0** + +!!! error "Breaking Changes" + 1. With a recent refactor some users been experiencing issues with an environmental variable not being set correct. If you are experiencing issues, please provide your comments [Here](https://github.com/hay-kot/mealie/issues/281). + + 2. If you are a developer, you may experience issues with development as a new environmental variable has been introduced. Setting `PRODUCTION=false` will allow you to develop as normal. + +- Improved Nextcloud Migration. Mealie will now walk the directories in a zip file looking for directories that match the pattern of a Nextcloud Recipe. Closes #254 + - Rewrite Keywords to Tag Fields + - Rewrite url to orgURL +- Improved Chowdown Migration +- Migration report is now similar to the Backup report +- Tags/Categories are now title cased on import "dinner" -> "Dinner" +- Fixed Initialization script (v0.4.1a Hot Fix) Closes #274 +- Depreciate `ENV` variable to `PRODUCTION` +- Set `PRODUCTION` env variable to default to true +- Unify Logger across the backend +- mealie.log and last_recipe.json are now downloadable from the frontend from the /admin/about +- New download schema where you request a token and then use that token to hit a single endpoint to download a file. This is a notable change if you are using the API to download backups. +- Recipe images can no be added directly from a URL - [See #177 for details](https://github.com/hay-kot/mealie/issues/117) \ No newline at end of file diff --git a/docs/docs/getting-started/api-usage.md b/docs/docs/getting-started/api-usage.md index b58fc485f..f44a30831 100644 --- a/docs/docs/getting-started/api-usage.md +++ b/docs/docs/getting-started/api-usage.md @@ -1,5 +1,8 @@ # Usage +## Getting a Token +Bla Bla + ## Key Components ### Recipe Extras Recipes extras are a key feature of the Mealie API. They allow you to create custom json key/value pairs within a recipe to reference from 3rd part applications. You can use these keys to contain information to trigger automation or custom messages to relay to your desired device. @@ -8,96 +11,4 @@ For example you could add `{"message": "Remember to thaw the chicken"}` to a rec ![api-extras-gif](../assets/gifs/api-extras.gif) - -## Examples -### Bulk import -Recipes can be imported in bulk from a file containing a list of URLs. This can be done using the following bash or python scripts with the `list` file containing one URL per line. - -#### Bash -```bash -#!/bin/bash - -function authentification () { - auth=$(curl -X 'POST' \ - "$3/api/auth/token" \ - -H 'accept: application/json' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -d 'grant_type=&username='$1'&password='$2'&scope=&client_id=&client_secret=') - - echo $auth | sed -e 's/.*token":"\(.*\)",.*/\1/' -} - -function import_from_file () { - while IFS= read -r line - do - echo $line - curl -X 'POST' \ - "$3/api/recipes/create-url" \ - -H "Authorization: Bearer $2" \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{"url": "'$line'" }' - echo - done < "$1" -} - -input="list" -mail="changeme@email.com" -password="MyPassword" -mealie_url=http://localhost:9000 - - -token=$(authentification $mail $password $mealie_url) -import_from_file $input $token $mealie_url - -``` - -#### Python -```python -import requests -import re - -def authentification(mail, password, mealie_url): - headers = { - 'accept': 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', - } - data = { - 'grant_type': '', - 'username': mail, - 'password': password, - 'scope': '', - 'client_id': '', - 'client_secret': '' - } - auth = requests.post(mealie_url + "/api/auth/token", headers=headers, data=data) - token = re.sub(r'.*token":"(.*)",.*', r'\1', auth.text) - return token - -def import_from_file(input_file, token, mealie_url): - with open(input_file) as fp: - for l in fp: - line = re.sub(r'(.*)\n', r'\1', l) - print(line) - headers = { - 'Authorization': "Bearer " + token, - 'accept': 'application/json', - 'Content-Type': 'application/json' - } - data = { - 'url': line - } - response = requests.post(mealie_url + "/api/recipes/create-url", headers=headers, json=data) - print(response.text) - -input_file="list" -mail="changeme@email.com" -password="MyPassword" -mealie_url="http://localhost:9000" - - -token = authentification(mail, password, mealie_url) -import_from_file(input_file, token, mealie_url) -``` - Have Ideas? Submit a PR! diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 1228e3f77..b3dc7a1e3 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 7d675172a..2b1560f6c 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -56,7 +56,6 @@ nav: - Organizing Recipes: "getting-started/organizing-recipes.md" - Planning Meals: "getting-started/meal-planner.md" - iOS Shortcuts: "getting-started/ios.md" - - API Usage: "getting-started/api-usage.md" - Site Administration: - User Settings: "site-administration/user-settings.md" - Site Settings: "site-administration/site-settings.md" @@ -64,6 +63,10 @@ nav: - User Management: "site-administration/user-management.md" - Backups and Restore: "site-administration/backups-and-exports.md" - Recipe Migration: "site-administration/migration-imports.md" + - API Usage: + - Getting Started: "api-usage/getting-started.md" + - Home Assistant: "api-usage/home-assistant.md" + - Bulk Url Import: "api-usage/bulk-url-import.md" - API Reference: "api/redoc.md" - Contributors Guide: - Non-Code: "contributors/non-coders.md" @@ -74,6 +77,7 @@ nav: - Guidelines: "contributors/developers-guide/general-guidelines.md" - Development Road Map: "roadmap.md" - Change Log: + - v0.4.2 Backend/Migrations: "changelog/v0.4.2.md" - v0.4.1 Frontend/UI: "changelog/v0.4.1.md" - v0.4.0 Authentication: "changelog/v0.4.0.md" - v0.3.0 Improvements: "changelog/v0.3.0.md" diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js index 8c4b0e71d..853d5ac9f 100644 --- a/frontend/src/api/api-utils.js +++ b/frontend/src/api/api-utils.js @@ -61,9 +61,16 @@ const apiReq = { processResponse(response); return response; }, + + async download(url) { + const response = await this.get(url); + const token = response.data.fileToken; + + const tokenURL = baseURL + "utils/download?token=" + token; + window.open(tokenURL, "_blank"); + return response.data; + }, }; - - export { apiReq }; export { baseURL }; diff --git a/frontend/src/api/backup.js b/frontend/src/api/backup.js index 3ec9a1285..b6afd6e98 100644 --- a/frontend/src/api/backup.js +++ b/frontend/src/api/backup.js @@ -4,7 +4,7 @@ import { store } from "@/store"; const backupBase = baseURL + "backups/"; -const backupURLs = { +export const backupURLs = { // Backup available: `${backupBase}available`, createBackup: `${backupBase}export/database`, @@ -13,6 +13,8 @@ const backupURLs = { downloadBackup: fileName => `${backupBase}${fileName}/download`, }; + + export const backupAPI = { /** * Request all backups available on the server @@ -43,19 +45,19 @@ export const backupAPI = { /** * Creates a backup on the serve given a set of options * @param {object} data - * @returns + * @returns */ async create(options) { let response = apiReq.post(backupURLs.createBackup, options); return response; }, /** - * Downloads a file from the server. I don't actually think this is used? - * @param {string} fileName + * Downloads a file from the server. I don't actually think this is used? + * @param {string} fileName * @returns Download URL */ async download(fileName) { - let response = await apiReq.get(backupURLs.downloadBackup(fileName)); - return response.data; + const url = backupURLs.downloadBackup(fileName); + apiReq.download(url); }, }; diff --git a/frontend/src/api/category.js b/frontend/src/api/category.js index 0f8ecd3fd..f60739c8d 100644 --- a/frontend/src/api/category.js +++ b/frontend/src/api/category.js @@ -44,6 +44,11 @@ export const tagAPI = { let response = await apiReq.get(tagURLs.getAll); return response.data; }, + async create(name) { + let response = await apiReq.post(tagURLs.getAll, { name: name }); + store.dispatch("requestTags"); + return response.data; + }, async getRecipesInTag(tag) { let response = await apiReq.get(tagURLs.getTag(tag)); return response.data; diff --git a/frontend/src/api/recipe.js b/frontend/src/api/recipe.js index 50e45e593..42d5c47eb 100644 --- a/frontend/src/api/recipe.js +++ b/frontend/src/api/recipe.js @@ -61,6 +61,11 @@ export const recipeAPI = { return response; }, + async updateImagebyURL(slug, url) { + const response = apiReq.post(recipeURLs.updateImage(slug), { url: url }); + return response; + }, + async update(data) { let response = await apiReq.put(recipeURLs.update(data.slug), data); store.dispatch("requestRecentRecipes"); diff --git a/frontend/src/components/Admin/Backup/ImportDialog.vue b/frontend/src/components/Admin/Backup/ImportDialog.vue index 0d54aeaa5..b379dd982 100644 --- a/frontend/src/components/Admin/Backup/ImportDialog.vue +++ b/frontend/src/components/Admin/Backup/ImportDialog.vue @@ -37,14 +37,7 @@ - - {{ $t("general.download") }} - + {{ $t("general.delete") }} @@ -66,9 +59,10 @@ diff --git a/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue b/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue index 8714c6fea..4c2f8597d 100644 --- a/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue +++ b/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue @@ -45,7 +45,7 @@ \ No newline at end of file + diff --git a/frontend/src/components/Admin/General/CreatePageDialog.vue b/frontend/src/components/Admin/General/CreatePageDialog.vue index efedf8cf0..6094f1fe7 100644 --- a/frontend/src/components/Admin/General/CreatePageDialog.vue +++ b/frontend/src/components/Admin/General/CreatePageDialog.vue @@ -19,10 +19,11 @@ v-model="page.name" label="Page Name" > - @@ -43,10 +44,10 @@ + + \ No newline at end of file diff --git a/frontend/src/components/FormHelpers/CategorySelector.vue b/frontend/src/components/FormHelpers/CategorySelector.vue deleted file mode 100644 index 3457206b5..000000000 --- a/frontend/src/components/FormHelpers/CategorySelector.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/FormHelpers/CategoryTagSelector.vue b/frontend/src/components/FormHelpers/CategoryTagSelector.vue new file mode 100644 index 000000000..4abdffe1f --- /dev/null +++ b/frontend/src/components/FormHelpers/CategoryTagSelector.vue @@ -0,0 +1,129 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/FormHelpers/TagSelector.vue b/frontend/src/components/FormHelpers/TagSelector.vue deleted file mode 100644 index 348ed90c0..000000000 --- a/frontend/src/components/FormHelpers/TagSelector.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/Recipe/RecipeEditor/ImageUploadBtn.vue b/frontend/src/components/Recipe/RecipeEditor/ImageUploadBtn.vue new file mode 100644 index 000000000..d3154c84a --- /dev/null +++ b/frontend/src/components/Recipe/RecipeEditor/ImageUploadBtn.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/frontend/src/components/Recipe/RecipeEditor/NutritionEditor.vue b/frontend/src/components/Recipe/RecipeEditor/NutritionEditor.vue new file mode 100644 index 000000000..b74b54b72 --- /dev/null +++ b/frontend/src/components/Recipe/RecipeEditor/NutritionEditor.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/components/Recipe/RecipeEditor/index.vue b/frontend/src/components/Recipe/RecipeEditor/index.vue index 6917ad2c1..f4a8a3c1a 100644 --- a/frontend/src/components/Recipe/RecipeEditor/index.vue +++ b/frontend/src/components/Recipe/RecipeEditor/index.vue @@ -2,16 +2,12 @@ - - - - - + @@ -92,7 +88,7 @@ auto-grow solo dense - rows="2" + rows="1" >

{{ $t("recipe.categories") }}

- - - + :show-add="true" + :show-label="false" + />

{{ $t("recipe.tags") }}

- - - + :show-add="true" + :tag-selector="true" + :show-label="false" + />

{{ $t("recipe.notes") }}

mdi-plus
+ @@ -261,15 +219,20 @@ + + \ No newline at end of file diff --git a/frontend/src/components/UI/UploadBtn.vue b/frontend/src/components/UI/UploadBtn.vue index e185db715..b69b8a130 100644 --- a/frontend/src/components/UI/UploadBtn.vue +++ b/frontend/src/components/UI/UploadBtn.vue @@ -1,7 +1,12 @@