Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a41ad8c6ed | ||
|
|
9c38c89c44 | ||
|
|
998440d064 | ||
|
|
b01d12c377 | ||
|
|
1dee574a08 | ||
|
|
257c4461a3 | ||
|
|
01f4257190 | ||
|
|
d7b7dd6c83 | ||
|
|
23c2eab682 | ||
|
|
def346d16d | ||
|
|
cc324b29ae | ||
|
|
9d58f9b266 | ||
|
|
30b2776f3c | ||
|
|
60d23d0686 | ||
|
|
edf649dea6 | ||
|
|
29b4a3cd22 | ||
|
|
f3a5148628 | ||
|
|
33abd777e0 | ||
|
|
739055caf6 | ||
|
|
8c29bd3439 | ||
|
|
2c4d0b692b | ||
|
|
946b79b77a | ||
|
|
cd154d09b2 | ||
|
|
236c930b54 | ||
|
|
980c847e36 | ||
|
|
91700771e6 | ||
|
|
abb6ad5fd0 | ||
|
|
ac7af02f77 | ||
|
|
525b398687 | ||
|
|
fafc836ccc | ||
|
|
c617b829e5 | ||
|
|
5b1e827d45 | ||
|
|
e33b62be2a | ||
|
|
60c33b499c | ||
|
|
c205dff523 | ||
|
|
ce69899c4b | ||
|
|
a4183e3453 | ||
|
|
ab39408a24 | ||
|
|
8c6c98483c | ||
|
|
ae095ab572 | ||
|
|
65356bc21a | ||
|
|
3aed5de3fc | ||
|
|
a4e9e54dae | ||
|
|
8f698e437e | ||
|
|
ab0d36825a | ||
|
|
4e2f6c57f1 | ||
|
|
de4cb8ba83 | ||
|
|
375f43c596 | ||
|
|
3034945e7e | ||
|
|
8e5effa532 | ||
|
|
3b81d3b18a | ||
|
|
d0f8b5773d | ||
|
|
14910162dc | ||
|
|
035f780d27 | ||
|
|
f10161ee92 | ||
|
|
b1a100a8c5 | ||
|
|
7db39d32d1 | ||
|
|
10921f9a64 | ||
|
|
ba1c44172e | ||
|
|
fd2dc15a15 | ||
|
|
47124488bb | ||
|
|
6e680c972a | ||
|
|
1fd2eb37ae | ||
|
|
923a59791a | ||
|
|
1fcc2c755a | ||
|
|
d5f7a883df | ||
|
|
17f9eef551 | ||
|
|
ca1ab33291 | ||
|
|
6e6ae80c46 | ||
|
|
aa6e109162 | ||
|
|
a6e4b778c1 | ||
|
|
31c7cb7906 | ||
|
|
d954b5cf48 | ||
|
|
e5c2f5570f | ||
|
|
e344f3f1e6 | ||
|
|
6a7f0edbc6 | ||
|
|
d2fd4e0843 | ||
|
|
d639d168fa |
@@ -38,3 +38,6 @@ RUN apt-get update \
|
||||
libwebp-dev \
|
||||
libsasl2-dev libldap2-dev libssl-dev \
|
||||
gnupg gnupg2 gnupg1
|
||||
|
||||
# create directory used for Docker Secrets
|
||||
RUN mkdir -p /run/secrets
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
},
|
||||
"extensions": [
|
||||
"charliermarsh.ruff",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"matangover.mypy",
|
||||
"ms-python.black-formatter",
|
||||
|
||||
9
.github/workflows/release.yml
vendored
@@ -61,10 +61,15 @@ jobs:
|
||||
- name: Checkout 🛎
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract Version From Tag Name
|
||||
run: echo "VERSION_NUM=$(echo ${{ github.event.release.tag_name }} | sed 's/^v//')" >> $GITHUB_ENV
|
||||
|
||||
- name: Modify version strings
|
||||
run: |
|
||||
sed -i 's/:v[0-9]*.[0-9]*.[0-9]*/:${{ github.event.release.tag_name }}/' docs/docs/documentation/getting-started/installation/sqlite.md
|
||||
sed -i 's/:v[0-9]*.[0-9]*.[0-9]*/:${{ github.event.release.tag_name }}/' docs/docs/documentation/getting-started/installation/postgres.md
|
||||
sed -i 's/:v[0-9]*.[0-9]*.[0-9]*/:v${{ env.VERSION_NUM }}/' docs/docs/documentation/getting-started/installation/sqlite.md
|
||||
sed -i 's/:v[0-9]*.[0-9]*.[0-9]*/:v${{ env.VERSION_NUM }}/' docs/docs/documentation/getting-started/installation/postgres.md
|
||||
sed -i 's/^version = "[^"]*"/version = "${{ env.VERSION_NUM }}"/' pyproject.toml
|
||||
sed -i 's/^\s*"version": "[^"]*"/"version": "${{ env.VERSION_NUM }}"/' frontend/package.json
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
|
||||
32
.github/workflows/scheduled-checks.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Scheduled Checks
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every monday at 7 AM
|
||||
- cron: 0 7 * * 1
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout 🛎
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Update pre-commit Hooks
|
||||
uses: vrslev/pre-commit-autoupdate@v1.0.0
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
# This doesn't currently work for us because it creates the PR but the workflows don't run.
|
||||
# TODO: Provide a personal access token as a parameter here, that solves that problem.
|
||||
# https://github.com/peter-evans/create-pull-request
|
||||
with:
|
||||
commit-message: "Update pre-commit hooks"
|
||||
branch: "fix/update-pre-commit-hooks"
|
||||
delete-branch: true
|
||||
base: mealie-next
|
||||
title: "fix(auto): Update pre-commit hooks"
|
||||
body: "Auto-generated by `.github/workflows/scheduled-checks.yml`"
|
||||
@@ -12,6 +12,6 @@ repos:
|
||||
exclude: ^tests/data/
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.5.0
|
||||
rev: v0.5.5
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
|
||||
@@ -148,7 +148,7 @@ tasks:
|
||||
- poetry run python mealie/app.py
|
||||
|
||||
py:migrate:
|
||||
desc: generates a new database migration file e.g. task py:migrate "add new column"
|
||||
desc: generates a new database migration file e.g. task py:migrate -- "add new column"
|
||||
cmds:
|
||||
- poetry run alembic revision --autogenerate -m "{{ .CLI_ARGS }}"
|
||||
- task: py:format
|
||||
|
||||
@@ -13,7 +13,7 @@ from text_unidecode import unidecode
|
||||
|
||||
import mealie.db.migration_types
|
||||
from alembic import op
|
||||
from mealie.db.models._model_utils import GUID
|
||||
from mealie.db.models._model_utils.guid import GUID
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "5ab195a474eb"
|
||||
|
||||
@@ -6,7 +6,7 @@ Create Date: 2024-03-18 02:28:15.896959
|
||||
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from textwrap import dedent
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
@@ -34,7 +34,7 @@ def new_user_rating(user_id: Any, recipe_id: Any, rating: float | None = None, i
|
||||
else:
|
||||
id = "%.32x" % uuid4().int
|
||||
|
||||
now = datetime.now().isoformat()
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
return {
|
||||
"id": id,
|
||||
"user_id": user_id,
|
||||
|
||||
@@ -92,6 +92,9 @@ RUN apt-get update \
|
||||
libldap-2.5 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# create directory used for Docker Secrets
|
||||
RUN mkdir -p /run/secrets
|
||||
|
||||
# copying poetry and venv into image
|
||||
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
|
||||
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
|
||||
|
||||
@@ -9,7 +9,7 @@ How exactly you need to modify it is of course highly contextual to the change y
|
||||
|
||||
## Using Alembic to generate upgrade script
|
||||
|
||||
In your dev container you can run something like (change the message) `task py:migrate "Add creation tag to group preferences"` to have Alembic generate an upgrade script for you.
|
||||
In your dev container you can run something like (change the message) `task py:migrate -- "Add creation tag to group preferences"` to have Alembic generate an upgrade script for you.
|
||||
|
||||
The script Alembic generates, will be limited! (Perhaps there's a way to resolve that? Haven't looked into it yet)
|
||||
For example, Alembic generated a script _similar_ to this (it has been modified already to have accurate foreign key names, for instance):
|
||||
|
||||
@@ -48,7 +48,7 @@ services:
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
Don't forget to change the <code>mydomain.duckns</code> into your personal domain and the <code>duckdnstoken</code> into your token and remove the brackets.
|
||||
Don't forget to change the <code>mydomain.duckdns</code> into your personal domain and the <code>duckdnstoken</code> into your token and remove the brackets.
|
||||
|
||||
## Step 3: Change the config files
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
## How do I enable "smart" ingredient handling?
|
||||
|
||||
You might have noticed that scaling up a recipe or making a shopping list doesn't by default handle the ingredients in a way you might expect. Depending on your settings, scaling up might yield things like `2 1 cup broth` instead of `2 cup broth`. And making shopping lists from reciepes that have shared ingredients can yield multiple lines of the same ingredient. **But**, mealie has a mechanism to intelligently handle ingredients and make your day better. How?
|
||||
You might have noticed that scaling up a recipe or making a shopping list doesn't by default handle the ingredients in a way you might expect. Depending on your settings, scaling up might yield things like `2 1 cup broth` instead of `2 cup broth`. And, making shopping lists from recipes that have shared ingredients can yield multiple lines of the same ingredient. **But**, Mealie has a mechanism to intelligently handle ingredients and make your day better. How?
|
||||
### Set up your Foods and Units
|
||||
Do the following just **once**. Doing this applies to your whole group, so be careful.
|
||||
|
||||
1. Click on your name in the upper left corner to get to your settings
|
||||
2. In the bottom right, select `Manage Data`
|
||||
3. In the Management page, make sure that a little orange button says `Foods`
|
||||
4. If your Foods database is empty, click `Seed` and choose your language. You should end up with a list of foods. (Wait bit for seeding to happen, and try not to seed more than once or you will have duplicates)
|
||||
4. If your Foods database is empty, click `Seed` and choose your language. You should end up with a list of foods. (Wait a bit for seeding to happen, and try not to seed more than once or you will have duplicates)
|
||||
5. Click the little orange `Foods` button and now choose `Units`.
|
||||
6. Click `Seed` and choose your language. You should end up with a list of units (e.g. `tablespoon`)
|
||||
|
||||
@@ -33,9 +33,9 @@ Do the following for each recipe you want to intelligently handle ingredients.
|
||||
|
||||
Scaling up this recipe or adding it to a Shopping List will now smartly take care of ingredient amounts and duplicate combinations.
|
||||
|
||||
## Is it Safe to Upgrade Mealie?
|
||||
## Is it safe to upgrade Mealie?
|
||||
|
||||
Yes. If you are using the v1 branches (including beta), you can upgrade to the latest version of Mealie without performing a site Export/Restore. This process was required in previous versions of Mealie, however we've automated the database migration process to make it easier to upgrade. Not that if you were using the v0.5.x version, you CANNOT upgrade to the latest version automatically. You must follow the migration instructions in the documentation.
|
||||
Yes. If you are using the v1 branches (including beta), you can upgrade to the latest version of Mealie without performing a site Export/Restore. This process was required in previous versions of Mealie, however we've automated the database migration process to make it easier to upgrade. Note that if you were using the v0.5.x version, you CANNOT upgrade to the latest version automatically. You must follow the migration instructions in the documentation.
|
||||
|
||||
- [Migration From v0.5.x](./migrating-to-mealie-v1.md)
|
||||
|
||||
@@ -45,7 +45,7 @@ You can change the theme by settings the environment variables.
|
||||
|
||||
- [Backend Config - Themeing](./installation/backend-config.md#themeing)
|
||||
|
||||
## How can I change the Login Session Timeout?
|
||||
## How can I change the login session timeout?
|
||||
|
||||
Login session can be configured by setting the `TOKEN_TIME` variable on the backend container.
|
||||
|
||||
@@ -53,7 +53,7 @@ Login session can be configured by setting the `TOKEN_TIME` variable on the back
|
||||
|
||||
## Can I serve Mealie on a subpath?
|
||||
|
||||
No. Due to limitations from the Javascript Framework, mealie doesn't support serving Mealie on a subpath.
|
||||
No. Due to limitations from the JavaScript Framework, Mealie doesn't support serving Mealie on a subpath.
|
||||
|
||||
## Can I install Mealie without docker?
|
||||
|
||||
@@ -130,8 +130,8 @@ stateDiagram-v2
|
||||
|
||||
For more information, check out the [Permissions and Public Access guide](./usage/permissions-and-public-access.md).
|
||||
|
||||
## Can I use fail2ban with mealie?
|
||||
Yes, mealie is configured to properly forward external IP addresses into the `mealie.log` logfile. Note that due to restrictions in docker, IP address forwarding only works on Linux.
|
||||
## Can I use fail2ban with Mealie?
|
||||
Yes, Mealie is configured to properly forward external IP addresses into the `mealie.log` logfile. Note that due to restrictions in docker, IP address forwarding only works on Linux.
|
||||
|
||||
Your fail2ban usage should look like the following:
|
||||
```
|
||||
@@ -139,11 +139,11 @@ Use datepattern : %d-%b-%y %H:%M:%S : Day-MON-Year2 24hour:Minute:Second
|
||||
Use failregex line : ^ERROR:\s+Incorrect username or password from <HOST>
|
||||
```
|
||||
|
||||
## Why An API?
|
||||
An API allows integration into applications like [Home Assistant](https://www.home-assistant.io/) that can act as notification engines to provide custom notifications based on Meal Plan data to remind you to defrost the chicken, marinade the steak, or start the CrockPot. Additionally, you can access nearly any backend service via the API giving you total control to extend the application. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation.
|
||||
## Why an API?
|
||||
An API allows integration into applications like [Home Assistant](https://www.home-assistant.io/) that can act as notification engines to provide custom notifications based on Meal Plan data to remind you to defrost the chicken, marinate the steak, or start the CrockPot. Additionally, you can access nearly any backend service via the API giving you total control to extend the application. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation.
|
||||
|
||||
## Why a Database?
|
||||
Some users of static-site generator applications like ChowDown have expressed concerns about their data being stuck in a database. Considering this is a new project, it is a valid concern to be worried about your data. Mealie specifically addresses this concern by provided automatic daily backups that export your data in json, plain-text markdown files, and/or custom Jinja2 templates. **This puts you in control of how your data is represented** when exported from Mealie, which means you can easily migrate to any other service provided Mealie doesn't work for you.
|
||||
## Why a database?
|
||||
Some users of static-site generator applications like ChowDown have expressed concerns about their data being stuck in a database. Considering this is a new project, it is a valid concern to be worried about your data. Mealie specifically addresses this concern by providing automatic daily backups that export your data in json, plain-text markdown files, and/or custom Jinja2 templates. **This puts you in control of how your data is represented** when exported from Mealie, which means you can easily migrate to any other service provided Mealie doesn't work for you.
|
||||
|
||||
As to why we need a database?
|
||||
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
|
||||
### General
|
||||
|
||||
| Variables | Default | Description |
|
||||
| ----------------------------- | :-------------------: | ----------------------------------------------------------------------------------- |
|
||||
| PUID | 911 | UserID permissions between host OS and container |
|
||||
| PGID | 911 | GroupID permissions between host OS and container |
|
||||
| DEFAULT_GROUP | Home | The default group for users |
|
||||
| BASE_URL | http://localhost:8080 | Used for Notifications |
|
||||
| TOKEN_TIME | 48 | The time in hours that a login/auth token is valid |
|
||||
| API_PORT | 9000 | The port exposed by backend API. **Do not change this if you're running in Docker** |
|
||||
| API_DOCS | True | Turns on/off access to the API documentation locally. |
|
||||
| TZ | UTC | Must be set to get correct date/time on the server |
|
||||
| ALLOW_SIGNUP<super>\*</super> | false | Allow user sign-up without token |
|
||||
| LOG_CONFIG_OVERRIDE | | Override the config for logging with a custom path |
|
||||
| LOG_LEVEL | info | Logging level (e.g. critical, error, warning, info, debug, trace) |
|
||||
| DAILY_SCHEDULE_TIME | 23:45 | The time of day to run the daily tasks. |
|
||||
| Variables | Default | Description |
|
||||
| ----------------------------- | :-------------------: | --------------------------------------------------------------------------------------------------------- |
|
||||
| PUID | 911 | UserID permissions between host OS and container |
|
||||
| PGID | 911 | GroupID permissions between host OS and container |
|
||||
| DEFAULT_GROUP | Home | The default group for users |
|
||||
| BASE_URL | http://localhost:8080 | Used for Notifications |
|
||||
| TOKEN_TIME | 48 | The time in hours that a login/auth token is valid |
|
||||
| API_PORT | 9000 | The port exposed by backend API. **Do not change this if you're running in Docker** |
|
||||
| API_DOCS | True | Turns on/off access to the API documentation locally |
|
||||
| TZ | UTC | Must be set to get correct date/time on the server |
|
||||
| ALLOW_SIGNUP<super>\*</super> | false | Allow user sign-up without token |
|
||||
| LOG_CONFIG_OVERRIDE | | Override the config for logging with a custom path |
|
||||
| LOG_LEVEL | info | Logging level (e.g. critical, error, warning, info, debug, trace) |
|
||||
| DAILY_SCHEDULE_TIME | 23:45 | The time of day to run daily server tasks, in HH:MM format. Use the server's local time, *not* UTC |
|
||||
|
||||
<super>\*</super> Starting in v1.4.0 this was changed to default to `false` as apart of a security review of the application.
|
||||
<super>\*</super> Starting in v1.4.0 this was changed to default to `false` as part of a security review of the application.
|
||||
|
||||
### Security
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ The following steps were tested on a Ubuntu 20.04 server, but should work for mo
|
||||
4. Create a docker-compose.yaml file in the mealie directory: `touch docker-compose.yaml`
|
||||
5. Use the text editor of your choice to edit the file and copy the contents of the docker-compose template for the deployment type you want to use: `nano docker-compose.yaml` or `vi docker-compose.yaml`
|
||||
|
||||
## Step 2: Customizing The `docker-compose.yaml` files.
|
||||
## Step 3: Customizing The `docker-compose.yaml` files.
|
||||
|
||||
After you've decided setup the files it's important to set a few ENV variables to ensure that you can use all the features of Mealie. I recommend that you verify and check that:
|
||||
|
||||
@@ -67,7 +67,7 @@ After you've decided setup the files it's important to set a few ENV variables t
|
||||
- [x] You've set the [`BASE_URL`](./backend-config.md#general) variable.
|
||||
- [x] You've set the `DEFAULT_EMAIL` and `DEFAULT_GROUP` variable.
|
||||
|
||||
## Step 3: Startup
|
||||
## Step 4: Startup
|
||||
|
||||
After you've configured your database and updated the `docker-compose.yaml` files, you can start Mealie by running the following command in the directory where you've added your `docker-compose.yaml`.
|
||||
|
||||
@@ -87,11 +87,11 @@ You should see the containers start up without error. You should now be able to
|
||||
|
||||
**Password:** MyPassword
|
||||
|
||||
## Step 4: Validate Installation
|
||||
## Step 5: Validate Installation
|
||||
|
||||
After the startup is complete, you should see a login screen. Use the default credentials above to log in and navigate to `/admin/site-settings`. Here, you'll find a summary of your configuration details and their respective status. Before proceeding, you should validate that the configuration is correct. For any warnings or errors the page will display an error and notify you of what you need to verify.
|
||||
|
||||
## Step 5: Backup
|
||||
## Step 6: Backup
|
||||
|
||||
While v1.0.0 is a great step to data-stability and security, it's not a backup. Mealie provides a full site data backup mechanism through the UI.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v1.9.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v1.10.2 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
- mealie-data:/app/data/
|
||||
environment:
|
||||
# Set Backend ENV Variables Here
|
||||
ALLOW_SIGNUP: true
|
||||
ALLOW_SIGNUP: false
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: America/Anchorage
|
||||
|
||||
@@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th
|
||||
```yaml
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v1.9.0 # (3)
|
||||
image: ghcr.io/mealie-recipes/mealie:v1.10.2 # (3)
|
||||
container_name: mealie
|
||||
restart: always
|
||||
ports:
|
||||
@@ -24,7 +24,7 @@ services:
|
||||
- mealie-data:/app/data/
|
||||
environment:
|
||||
# Set Backend ENV Variables Here
|
||||
ALLOW_SIGNUP: true
|
||||
ALLOW_SIGNUP: false
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: America/Anchorage
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
icon: $globals.icons.testTube,
|
||||
text: $tc('general.test'),
|
||||
event: 'test',
|
||||
// TODO: There is no functionality hooked up to this. Enable it when there is
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
icon: $globals.icons.save,
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<v-list-item-subtitle>
|
||||
<SafeMarkdown :source="description" />
|
||||
</v-list-item-subtitle>
|
||||
<div class="d-flex flex-wrap justify-start">
|
||||
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" url-prefix="tags" />
|
||||
</div>
|
||||
<div class="d-flex flex-wrap justify-end align-center">
|
||||
<slot name="actions">
|
||||
<RecipeFavoriteBadge v-if="isOwnGroup && showRecipeContent" :recipe-id="recipeId" show-always />
|
||||
@@ -83,6 +86,7 @@ import RecipeFavoriteBadge from "./RecipeFavoriteBadge.vue";
|
||||
import RecipeContextMenu from "./RecipeContextMenu.vue";
|
||||
import RecipeCardImage from "./RecipeCardImage.vue";
|
||||
import RecipeRating from "./RecipeRating.vue";
|
||||
import RecipeChips from "./RecipeChips.vue";
|
||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
||||
|
||||
export default defineComponent({
|
||||
@@ -91,6 +95,7 @@ export default defineComponent({
|
||||
RecipeContextMenu,
|
||||
RecipeRating,
|
||||
RecipeCardImage,
|
||||
RecipeChips,
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
@@ -114,6 +119,10 @@ export default defineComponent({
|
||||
required: false,
|
||||
default: "abc123",
|
||||
},
|
||||
tags: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
recipeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
||||
@@ -237,30 +237,40 @@ export default defineComponent({
|
||||
}
|
||||
});
|
||||
|
||||
let currentTitle = "";
|
||||
const onHandIngs: ShoppingListIngredient[] = [];
|
||||
const shoppingListIngredientSections = shoppingListIngredients.reduce((sections, ing) => {
|
||||
// if title append new section to the end of the array
|
||||
if (ing.ingredient.title) {
|
||||
currentTitle = ing.ingredient.title;
|
||||
}
|
||||
|
||||
// If this is the first item in the section, create a new section
|
||||
if (sections.length === 0 || currentTitle !== sections[sections.length - 1].sectionName) {
|
||||
if (sections.length) {
|
||||
// Add the on-hand ingredients to the previous section
|
||||
sections[sections.length - 1].ingredients.push(...onHandIngs);
|
||||
onHandIngs.length = 0;
|
||||
}
|
||||
sections.push({
|
||||
sectionName: ing.ingredient.title,
|
||||
ingredients: [ing],
|
||||
sectionName: currentTitle,
|
||||
ingredients: [],
|
||||
});
|
||||
}
|
||||
|
||||
// Store the on-hand ingredients for later
|
||||
if (ing.ingredient.food?.onHand) {
|
||||
onHandIngs.push(ing);
|
||||
return sections;
|
||||
}
|
||||
|
||||
// append new section if first
|
||||
if (sections.length === 0) {
|
||||
sections.push({
|
||||
sectionName: "",
|
||||
ingredients: [ing],
|
||||
});
|
||||
return sections;
|
||||
}
|
||||
|
||||
// otherwise add ingredient to last section in the array
|
||||
// Add the ingredient to previous section
|
||||
sections[sections.length - 1].ingredients.push(ing);
|
||||
return sections;
|
||||
}, [] as ShoppingListIngredientSection[]);
|
||||
|
||||
// Add remaining on-hand ingredients to the previous section
|
||||
shoppingListIngredientSections[shoppingListIngredientSections.length - 1].ingredients.push(...onHandIngs);
|
||||
|
||||
recipeSectionMap.set(recipe.slug, {
|
||||
recipeId: recipe.id,
|
||||
recipeName: recipe.name,
|
||||
|
||||
@@ -126,8 +126,8 @@
|
||||
<RecipeCardSection
|
||||
v-if="state.ready"
|
||||
class="mt-n5"
|
||||
:icon="$globals.icons.search"
|
||||
:title="$tc('search.results')"
|
||||
:icon="$globals.icons.silverwareForkKnife"
|
||||
:title="$tc('general.recipes')"
|
||||
:recipes="recipes"
|
||||
:query="passedQueryWithSeed"
|
||||
@replaceRecipes="replaceRecipes"
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<v-icon left>
|
||||
{{ $globals.icons.calendar }}
|
||||
</v-icon>
|
||||
{{ $t('recipe.last-made-date', { date: value ? new Date(value+"Z").toLocaleDateString($i18n.locale) : $t("general.never") } ) }}
|
||||
{{ $t('recipe.last-made-date', { date: value ? new Date(value).toLocaleDateString($i18n.locale) : $t("general.never") } ) }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,11 +199,7 @@ export default defineComponent({
|
||||
await userApi.recipes.updateLastMade(props.recipe.slug, newTimelineEvent.value.timestamp);
|
||||
|
||||
// update recipe in parent so the user can see it
|
||||
// we remove the trailing "Z" since this is how the API returns it
|
||||
context.emit(
|
||||
"input", newTimelineEvent.value.timestamp
|
||||
.substring(0, newTimelineEvent.value.timestamp.length - 1)
|
||||
);
|
||||
context.emit("input", newTimelineEvent.value.timestamp);
|
||||
}
|
||||
|
||||
// update the image, if provided
|
||||
|
||||
@@ -114,9 +114,9 @@ export default defineComponent({
|
||||
options: {
|
||||
ignoreLocation: true,
|
||||
shouldSort: true,
|
||||
threshold: 0.6,
|
||||
threshold: 0.2,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
distance: 20,
|
||||
findAllMatches: true,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<template v-if="!useMobileFormat" #opposite>
|
||||
<v-chip v-if="event.timestamp" label large>
|
||||
<v-icon class="mr-1"> {{ $globals.icons.calendar }} </v-icon>
|
||||
{{ new Date(event.timestamp+"Z").toLocaleDateString($i18n.locale) }}
|
||||
{{ new Date(event.timestamp).toLocaleDateString($i18n.locale) }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<v-card
|
||||
@@ -25,7 +25,7 @@
|
||||
<v-col v-if="useMobileFormat" align-self="center" class="pr-0">
|
||||
<v-chip label>
|
||||
<v-icon> {{ $globals.icons.calendar }} </v-icon>
|
||||
{{ new Date(event.timestamp+"Z").toLocaleDateString($i18n.locale) }}
|
||||
{{ new Date(event.timestamp || "").toLocaleDateString($i18n.locale) }}
|
||||
</v-chip>
|
||||
</v-col>
|
||||
<v-col v-else cols="9" style="margin: auto; text-align: center;">
|
||||
|
||||
@@ -69,13 +69,13 @@
|
||||
</v-row>
|
||||
<v-row v-if="!listItem.checked && recipeList && recipeList.length && displayRecipeRefs" no-gutters class="mb-2">
|
||||
<v-col cols="auto" style="width: 100%;">
|
||||
<RecipeList :recipes="recipeList" :list-item="listItem" :disabled="isOffline" small tile />
|
||||
<RecipeList :recipes="recipeList" :list-item="listItem" :disabled="$nuxt.isOffline" small tile />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-if="listItem.checked" no-gutters class="mb-2">
|
||||
<v-col cols="auto">
|
||||
<div class="text-caption font-weight-light font-italic">
|
||||
{{ $t("shopping-list.completed-on", {date: new Date(listItem.updateAt+"Z").toLocaleDateString($i18n.locale)}) }}
|
||||
{{ $t("shopping-list.completed-on", {date: new Date(listItem.updateAt || "").toLocaleDateString($i18n.locale)}) }}
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@@ -136,10 +136,6 @@ export default defineComponent({
|
||||
type: Map<string, RecipeSummary>,
|
||||
default: undefined,
|
||||
},
|
||||
isOffline: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { i18n } = useContext();
|
||||
|
||||
@@ -157,9 +157,9 @@
|
||||
|
||||
const topLinks = computed<SidebarLinks>(() => [
|
||||
{
|
||||
icon: $globals.icons.search,
|
||||
icon: $globals.icons.silverwareForkKnife,
|
||||
to: `/g/${groupSlug.value}`,
|
||||
title: i18n.tc("sidebar.search"),
|
||||
title: i18n.tc("general.recipes"),
|
||||
restricted: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -64,7 +64,6 @@ export const useGroupWebhooks = function () {
|
||||
newDt.setMinutes(Number(minutes));
|
||||
|
||||
updateData.scheduledTime = `${pad(newDt.getUTCHours(), 2)}:${pad(newDt.getUTCMinutes(), 2)}`;
|
||||
console.log(updateData.scheduledTime);
|
||||
|
||||
const payload = {
|
||||
...updateData,
|
||||
@@ -85,7 +84,14 @@ export const useGroupWebhooks = function () {
|
||||
if (data) {
|
||||
this.refreshAll();
|
||||
}
|
||||
loading.value = false;
|
||||
},
|
||||
|
||||
async testOne(id: string | number) {
|
||||
loading.value = true;
|
||||
await api.groupWebhooks.testOne(id);
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const webhooks = actions.getAll();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { computed, ref } from "@nuxtjs/composition-api";
|
||||
import { computed, reactive, watch } from "@nuxtjs/composition-api";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { ShoppingListItemOut, ShoppingListOut } from "~/lib/api/types/group";
|
||||
@@ -24,14 +24,23 @@ interface Storage {
|
||||
export function useShoppingListItemActions(shoppingListId: string) {
|
||||
const api = useUserApi();
|
||||
const storage = useLocalStorage(localStorageKey, {} as Storage, { deep: true });
|
||||
const queue = getQueue();
|
||||
const queue = reactive(getQueue());
|
||||
const queueEmpty = computed(() => !queue.create.length && !queue.update.length && !queue.delete.length);
|
||||
if (queueEmpty.value) {
|
||||
queue.lastUpdate = Date.now();
|
||||
storage.value[shoppingListId].lastUpdate = queue.lastUpdate;
|
||||
}
|
||||
|
||||
const isOffline = ref(false);
|
||||
storage.value[shoppingListId] = { ...queue }
|
||||
watch(
|
||||
() => queue,
|
||||
(value) => {
|
||||
storage.value[shoppingListId] = { ...value }
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
|
||||
function isValidQueueObject(obj: any): obj is ShoppingListQueue {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
@@ -51,17 +60,18 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
}
|
||||
|
||||
function createEmptyQueue(): ShoppingListQueue {
|
||||
return { create: [], update: [], delete: [], lastUpdate: Date.now() };
|
||||
const newQueue = { create: [], update: [], delete: [], lastUpdate: Date.now() };
|
||||
return newQueue;
|
||||
}
|
||||
|
||||
function getQueue(): ShoppingListQueue {
|
||||
try {
|
||||
const queue = storage.value[shoppingListId];
|
||||
if (!isValidQueueObject(queue)) {
|
||||
const fetchedQueue = storage.value[shoppingListId];
|
||||
if (!isValidQueueObject(fetchedQueue)) {
|
||||
console.log("Invalid queue object in local storage; resetting queue.");
|
||||
return createEmptyQueue();
|
||||
} else {
|
||||
return queue;
|
||||
return fetchedQueue;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error validating queue object in local storage; resetting queue.", error);
|
||||
@@ -81,14 +91,12 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
|
||||
async function getList() {
|
||||
const response = await api.shopping.lists.getOne(shoppingListId);
|
||||
handleResponse(response);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
function createItem(item: ShoppingListItemOut) {
|
||||
removeFromQueue(queue.create, item);
|
||||
queue.create.push(item);
|
||||
storage.value[shoppingListId] = { ...queue };
|
||||
}
|
||||
|
||||
function updateItem(item: ShoppingListItemOut) {
|
||||
@@ -96,13 +104,11 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
if (removedFromCreate) {
|
||||
// this item hasn't been created yet, so we don't need to update it
|
||||
queue.create.push(item);
|
||||
storage.value[shoppingListId] = { ...queue };
|
||||
return;
|
||||
}
|
||||
|
||||
removeFromQueue(queue.update, item);
|
||||
queue.update.push(item);
|
||||
storage.value[shoppingListId] = { ...queue };
|
||||
}
|
||||
|
||||
function deleteItem(item: ShoppingListItemOut) {
|
||||
@@ -115,7 +121,6 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
removeFromQueue(queue.update, item);
|
||||
removeFromQueue(queue.delete, item);
|
||||
queue.delete.push(item);
|
||||
storage.value[shoppingListId] = { ...queue };
|
||||
}
|
||||
|
||||
function getQueueItems(itemQueueType: ItemQueueType) {
|
||||
@@ -135,16 +140,6 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
if (queueEmpty.value) {
|
||||
queue.lastUpdate = Date.now();
|
||||
}
|
||||
|
||||
// Set the storage value explicitly so changes are saved in the browser.
|
||||
storage.value[shoppingListId] = { ...queue };
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the response from the backend and sets the isOffline flag if necessary.
|
||||
*/
|
||||
function handleResponse(response: RequestResponse<any>) {
|
||||
isOffline.value = response?.response?.status === undefined;
|
||||
}
|
||||
|
||||
function checkUpdateState(list: ShoppingListOut) {
|
||||
@@ -178,9 +173,8 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
try {
|
||||
const itemsToProcess = [...queueItems];
|
||||
await action(itemsToProcess)
|
||||
.then((response) => {
|
||||
handleResponse(response);
|
||||
if (!isOffline.value) {
|
||||
.then(() => {
|
||||
if (window.$nuxt.isOnline) {
|
||||
clearQueueItems(itemQueueType, itemsToProcess.map(item => item.id));
|
||||
}
|
||||
});
|
||||
@@ -196,7 +190,6 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
async function process() {
|
||||
if(queueEmpty.value) {
|
||||
queue.lastUpdate = Date.now();
|
||||
storage.value[shoppingListId].lastUpdate = queue.lastUpdate;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,14 +208,12 @@ export function useShoppingListItemActions(shoppingListId: string) {
|
||||
|
||||
// If we're online, or the queue is empty, the queue is fully processed, so we're up to date
|
||||
// Otherwise, if all three queue processes failed, we've already reset the queue, so we need to reset the date
|
||||
if (!isOffline.value || queueEmpty.value || failures === 3) {
|
||||
if (window.$nuxt.isOnline || queueEmpty.value || failures === 3) {
|
||||
queue.lastUpdate = Date.now();
|
||||
storage.value[shoppingListId].lastUpdate = queue.lastUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isOffline,
|
||||
getList,
|
||||
createItem,
|
||||
updateItem,
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissies",
|
||||
"administrator": "Administrateur",
|
||||
"user-can-invite-other-to-group": "Gebruiker kan ander na groep nooi",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Gebruiker kan groep bestuur",
|
||||
"user-can-organize-group-data": "Gebruiker kan groepdata organiseer",
|
||||
"enable-advanced-features": "Aktiveer gevorderde funksies",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Права",
|
||||
"administrator": "Администратор",
|
||||
"user-can-invite-other-to-group": "Потребителя може да добавя други в групата",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Потребителя може да управлява групата",
|
||||
"user-can-organize-group-data": "Потребителя може да организира данните на групата",
|
||||
"enable-advanced-features": "Включване на разширени функции",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permisos",
|
||||
"administrator": "Administrador",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -145,11 +145,11 @@
|
||||
"save": "Uložit",
|
||||
"settings": "Nastavení",
|
||||
"share": "Sdílet",
|
||||
"show-all": "Show All",
|
||||
"show-all": "Zobrazit vše",
|
||||
"shuffle": "Náhodně",
|
||||
"sort": "Seřadit",
|
||||
"sort-ascending": "Sort Ascending",
|
||||
"sort-descending": "Sort Descending",
|
||||
"sort-ascending": "Řadit vzestupně",
|
||||
"sort-descending": "Řadit sestupně",
|
||||
"sort-alphabetically": "Abecedně",
|
||||
"status": "Stav",
|
||||
"subject": "Předmět",
|
||||
@@ -161,7 +161,7 @@
|
||||
"test": "Test",
|
||||
"themes": "Motivy",
|
||||
"thursday": "Čtvrtek",
|
||||
"title": "Title",
|
||||
"title": "Název",
|
||||
"token": "Token",
|
||||
"tuesday": "Úterý",
|
||||
"type": "Typ",
|
||||
@@ -208,7 +208,7 @@
|
||||
"upload-file": "Nahrát soubor",
|
||||
"created-on-date": "Vytvořeno dne: {0}",
|
||||
"unsaved-changes": "You have unsaved changes. Do you want to save before leaving? Okay to save, Cancel to discard changes.",
|
||||
"clipboard-copy-failure": "Failed to copy to the clipboard.",
|
||||
"clipboard-copy-failure": "Zkopírování do schránky se nezdařilo.",
|
||||
"confirm-delete-generic-items": "Are you sure you want to delete the following items?",
|
||||
"organizers": "Organizers",
|
||||
"caution": "Caution"
|
||||
@@ -247,7 +247,7 @@
|
||||
"group-preferences": "Nastavení skupiny",
|
||||
"private-group": "Soukromá skupina",
|
||||
"private-group-description": "Setting your group to private will default all public view options to default. This overrides an individual recipes public view settings.",
|
||||
"enable-public-access": "Enable Public Access",
|
||||
"enable-public-access": "Povolit veřejný přístup",
|
||||
"enable-public-access-description": "Make group recipes public by default, and allow visitors to view recipes without logging-in",
|
||||
"allow-users-outside-of-your-group-to-see-your-recipes": "Povolit uživatelům mimo vaši skupinu vidět vaše recepty",
|
||||
"allow-users-outside-of-your-group-to-see-your-recipes-description": "When enabled you can use a public share link to share specific recipes without authorizing the user. When disabled, you can only share recipes with users who are in your group or with a pre-generated private link",
|
||||
@@ -794,10 +794,10 @@
|
||||
"food": "Jídlo",
|
||||
"note": "Poznámka",
|
||||
"label": "Popisek",
|
||||
"save-label": "Save Label",
|
||||
"save-label": "Uložit štítek",
|
||||
"linked-item-warning": "Tato položka je propojena s jedním nebo více recepty. Úprava jednotky nebo jídla bude mít neočekávané důsledky při přidání nebo odebrání receptu z tohoto seznamu.",
|
||||
"toggle-food": "Přepnout typ položky",
|
||||
"manage-labels": "Manage Labels",
|
||||
"manage-labels": "Spravovat štítky",
|
||||
"are-you-sure-you-want-to-delete-this-item": "Are you sure you want to delete this item?",
|
||||
"copy-as-text": "Copy as Text",
|
||||
"copy-as-markdown": "Copy as Markdown",
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
@@ -1018,9 +1018,9 @@
|
||||
"labels": {
|
||||
"seed-dialog-text": "Naplnit databázi s běžnými popisky používanými ve vašem jazyce.",
|
||||
"edit-label": "Upravit štítek",
|
||||
"new-label": "New Label",
|
||||
"new-label": "Nový štítek",
|
||||
"labels": "Štítky",
|
||||
"assign-label": "Assign Label"
|
||||
"assign-label": "Přiřadit štítek"
|
||||
},
|
||||
"recipes": {
|
||||
"purge-exports": "Purge Exports",
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
"clipboard-copy-failure": "Kopiering til udklipsholderen mislykkedes.",
|
||||
"confirm-delete-generic-items": "Er du sikker på at du ønsker at slette de valgte emner?",
|
||||
"organizers": "Organisatorer",
|
||||
"caution": "Caution"
|
||||
"caution": "Bemærk"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "Er du sikker på, du vil slette <b>{groupName}<b/>?",
|
||||
@@ -292,8 +292,8 @@
|
||||
"mealplan-updated": "Madplanen blev ændret",
|
||||
"no-meal-plan-defined-yet": "Ingen madplan er defineret",
|
||||
"no-meal-planned-for-today": "Ingen ret er planlagt til i dag",
|
||||
"numberOfDays-hint": "Number of days on page load",
|
||||
"numberOfDays-label": "Default Days",
|
||||
"numberOfDays-hint": "Antal dage ved sideindlæsning",
|
||||
"numberOfDays-label": "Standarddage",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Kun opskrifter med disse kategorier vil blive brugt i madplaner",
|
||||
"planner": "Planlæg madplan",
|
||||
"quick-week": "Hurtig uge",
|
||||
@@ -383,7 +383,7 @@
|
||||
},
|
||||
"recipekeeper": {
|
||||
"title": "Recipe Keeper",
|
||||
"description-long": "Mealie can import recipes from Recipe Keeper. Export your recipes in zip format, then upload the .zip file below."
|
||||
"description-long": "Mealie kan importere opskrifter fra Recipe Keeper. Eksportér dine opskrifter i zip-format, og upload derefter .zip-filen nedenfor."
|
||||
}
|
||||
},
|
||||
"new-recipe": {
|
||||
@@ -449,8 +449,8 @@
|
||||
"ingredients": "Ingredienser",
|
||||
"insert-ingredient": "Indsæt Ingrediens",
|
||||
"insert-section": "Indsæt sektion",
|
||||
"insert-above": "Insert Above",
|
||||
"insert-below": "Insert Below",
|
||||
"insert-above": "Indsæt ovenover",
|
||||
"insert-below": "Indsæt nedenunder",
|
||||
"instructions": "Instruktioner",
|
||||
"key-name-required": "Nøglenavn påkrævet",
|
||||
"landscape-view-coming-soon": "Liggende visning (Kommer snart)",
|
||||
@@ -586,8 +586,8 @@
|
||||
"report-deletion-failed": "Sletning af rapport mislykkedes",
|
||||
"recipe-debugger": "Fejlsøgning af opskrifter",
|
||||
"recipe-debugger-description": "Indsæt URL'en på hjemmesiden, der indeholder den opskrift, du vil fejlsøge. URL-adressen vil blive læst og resultaterne vil blive vist. Hvis ingen data bliver vist, er indhentning af opskrifter fra hjemmesiden endnu ikke understøttet af Mealie.",
|
||||
"use-openai": "Use OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Use OpenAI to parse the results instead of relying on the scraper library. When creating a recipe via URL, this is done automatically if the scraper library fails, but you may test it manually here.",
|
||||
"use-openai": "Brug OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Brug OpenAI til at fortolke resultaterne i stedet for at stole på scraper biblioteket. Når du opretter en opskrift via URL, gøres dette automatisk, hvis skraberbiblioteket fejler, men du kan teste det manuelt her.",
|
||||
"debug": "Fejlsøgning",
|
||||
"tree-view": "Træ visning",
|
||||
"recipe-yield": "Udbytte af opskrift",
|
||||
@@ -640,7 +640,7 @@
|
||||
"backup-created-at-response-export_path": "Backup oprettet ved {path}",
|
||||
"backup-deleted": "Backup slettet",
|
||||
"restore-success": "Gendannelse lykkedes",
|
||||
"restore-fail": "Restore failed. Check your server logs for more details",
|
||||
"restore-fail": "Gendannelse mislykkedes. Tjek dine serverlogs for flere detaljer",
|
||||
"backup-tag": "Backupnavn",
|
||||
"create-heading": "Opret en backup",
|
||||
"delete-backup": "Slet backup",
|
||||
@@ -810,11 +810,11 @@
|
||||
"items-checked-count": "Ingen elementer markeret|Et element markeret|{count} elementer er markeret",
|
||||
"no-label": "Ingen etiket",
|
||||
"completed-on": "Afsluttet den {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "Du er offline",
|
||||
"you-are-offline-description": "Ikke alle funktioner er tilgængelige mens offline. Du kan stadig tilføje, modificere, og fjerne elementer, men du vil ikke kunne synkronisere dine ændringer til serveren, før du er online igen.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Er du sikker på, at du vil markere alle elementer?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Er du sikker på, at du vil fjerne markeringen af alle elementer?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Er du sikker på, at du vil sletter de valgte elementer?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Alle opskr.",
|
||||
@@ -955,7 +955,7 @@
|
||||
"user-details": "Brugerdetaljer",
|
||||
"user-name": "Brugernavn",
|
||||
"authentication-method": "Godkendelsesmetode",
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"authentication-method-hint": "Dette angiver, hvordan en bruger vil logge ind på Mealie. Hvis du ikke er sikker, vælg 'Mealie'",
|
||||
"permissions": "Rettigheder",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "Bruger kan invitere andre til gruppen",
|
||||
@@ -990,8 +990,8 @@
|
||||
"food-data": "Oplysninger om fødevare",
|
||||
"example-food-singular": "fx.: grøntsag",
|
||||
"example-food-plural": "fx.: grøntsager",
|
||||
"label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"label-overwrite-warning": "Dette vil tildele den valgte etiket til alle udvalgte fødevarer og potentielt overskrive dine eksisterende etiketter.",
|
||||
"on-hand-checkbox-label": "Ændring af dette flag ændrer markeringen, så denne fødevare ikke er markeret som standard, når du tilføjer en opskrift til en indkøbsliste."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Opret standard enheder i dit sprog.",
|
||||
@@ -1020,7 +1020,7 @@
|
||||
"edit-label": "Redigér etiket",
|
||||
"new-label": "Ny etiket",
|
||||
"labels": "Etiketter",
|
||||
"assign-label": "Assign Label"
|
||||
"assign-label": "Tildel etiket"
|
||||
},
|
||||
"recipes": {
|
||||
"purge-exports": "Tøm Eksport",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Αυτό καθορίζει τον τρόπο με τον οποίο ένας χρήστης θα ταυτοποιηθεί με το Mealie. Αν δεν είστε σίγουροι, επιλέξτε 'Mealie'",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "Ο χρήστης μπορεί να προσκαλέσει άλλους στην ομάδα",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Ενεργοποίηση χαρακτηριστικών για προχωρημένους",
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
"group-management": "Group Management",
|
||||
"admin-group-management": "Admin Group Management",
|
||||
"admin-group-management-text": "Changes to this group will be reflected immediately.",
|
||||
"group-id-value": "Group Id: {0}"
|
||||
"group-id-value": "Group ID: {0}"
|
||||
},
|
||||
"meal-plan": {
|
||||
"create-a-new-meal-plan": "Create a New Meal Plan",
|
||||
@@ -283,18 +283,18 @@
|
||||
"meal-planner": "Meal Planner",
|
||||
"meal-plans": "Meal Plans",
|
||||
"mealplan-categories": "MEALPLAN CATEGORIES",
|
||||
"mealplan-created": "Mealplan created",
|
||||
"mealplan-creation-failed": "Mealplan creation failed",
|
||||
"mealplan-created": "Meal plan created",
|
||||
"mealplan-creation-failed": "Meal plan creation failed",
|
||||
"mealplan-deleted": "Mealplan deleted",
|
||||
"mealplan-deletion-failed": "Mealplan deletion failed",
|
||||
"mealplan-settings": "Mealplan Settings",
|
||||
"mealplan-update-failed": "Mealplan update failed",
|
||||
"mealplan-updated": "Mealplan Updated",
|
||||
"mealplan-deletion-failed": "Meal plan deletion failed",
|
||||
"mealplan-settings": "Meal plan settings",
|
||||
"mealplan-update-failed": "Meal plan update failed",
|
||||
"mealplan-updated": "Meal plan updated",
|
||||
"no-meal-plan-defined-yet": "No meal plan defined yet",
|
||||
"no-meal-planned-for-today": "No meal planned for today",
|
||||
"numberOfDays-hint": "Number of days on page load",
|
||||
"numberOfDays-label": "Default Days",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only recipes with these categories will be used in Meal Plans",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "Only the recipes with these categories will be used in Meal Plans",
|
||||
"planner": "Planner",
|
||||
"quick-week": "Quick Week",
|
||||
"side": "Side",
|
||||
@@ -935,13 +935,13 @@
|
||||
"you-are-not-allowed-to-delete-this-user": "You are not allowed to delete this user",
|
||||
"enable-advanced-content": "Enable Advanced Content",
|
||||
"enable-advanced-content-description": "Enables advanced features like Recipe Scaling, API keys, Webhooks, and Data Management. Don't worry, you can always change this later",
|
||||
"favorite-recipes": "Favorite Recipes",
|
||||
"favorite-recipes": "Favourite Recipes",
|
||||
"email-or-username": "Email or Username",
|
||||
"remember-me": "Remember Me",
|
||||
"please-enter-your-email-and-password": "Please enter your email and password",
|
||||
"invalid-credentials": "Invalid Credentials",
|
||||
"account-locked-please-try-again-later": "Account Locked. Please try again later",
|
||||
"user-favorites": "User Favorites",
|
||||
"user-favorites": "User Favourites",
|
||||
"password-strength-values": {
|
||||
"weak": "Weak",
|
||||
"good": "Good",
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie'",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie'",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permisos",
|
||||
"administrator": "Administrador",
|
||||
"user-can-invite-other-to-group": "El usuario puede invitar a otros al grupo",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "El usuario puede administrar el grupo",
|
||||
"user-can-organize-group-data": "El usuario puede organizar los datos del grupo",
|
||||
"enable-advanced-features": "Habilitar Características Avanzadas",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Tämä määrittelee, miten käyttäjä todentaa Mealien. Jos et ole varma, valitse 'Mealie'",
|
||||
"permissions": "Käyttöoikeudet",
|
||||
"administrator": "Ylläpitäjä",
|
||||
"user-can-invite-other-to-group": "Käyttäjä voi kutsua muita ryhmään",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Käyttäjä voi hallita ryhmää",
|
||||
"user-can-organize-group-data": "Käyttäjä voi järjestellä ryhmän tietoja",
|
||||
"enable-advanced-features": "Salli edistyneemmät ominaisuudet",
|
||||
|
||||
@@ -810,8 +810,8 @@
|
||||
"items-checked-count": "Aucun élément coché|Un élément coché|{count} éléments cochés",
|
||||
"no-label": "Aucune étiquette",
|
||||
"completed-on": "Terminé le {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"you-are-offline": "Vous êtes hors-ligne",
|
||||
"you-are-offline-description": "Certaines fonctionnalités ne sont pas disponibles lorsque vous êtes hors-ligne. Vous pouvez toujours ajouter, modifier et supprimer des éléments, mais il ne sera pas possible de synchroniser les changements avec le serveur tant que vous ne serez pas en ligne.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Voulez-vous vraiment sélectionner tous les éléments ?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Voulez-vous vraiment désélectionner tous les éléments ?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Voulez-vous vraiment supprimer tous les éléments sélectionnés ?"
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Ceci infique comment un utilisateur va s'authentifier sur Mealie. Si vous n'êtes pas sûr, choisissez 'Mealie'",
|
||||
"permissions": "Autorisations",
|
||||
"administrator": "Administrateur",
|
||||
"user-can-invite-other-to-group": "L'utilisateur peut inviter quelqu'un au groupe",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "L'utilisateur peut gérer le groupe",
|
||||
"user-can-organize-group-data": "L'utilisateur peut organiser des données de groupe",
|
||||
"enable-advanced-features": "Activer les fonctions avancées",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Ceci infique comment un utilisateur va s'authentifier sur Mealie. Si vous n'êtes pas sûr, choisissez 'Mealie'",
|
||||
"permissions": "Autorisations",
|
||||
"administrator": "Administrateur",
|
||||
"user-can-invite-other-to-group": "L'utilisateur peut inviter quelqu'un au groupe",
|
||||
"user-can-invite-other-to-group": "L’utilisateur peut inviter d’autres personnes dans le groupe",
|
||||
"user-can-manage-group": "L'utilisateur peut gérer le groupe",
|
||||
"user-can-organize-group-data": "L'utilisateur peut organiser des données de groupe",
|
||||
"enable-advanced-features": "Activer les fonctions avancées",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "זה מציין איך משתמש יתחבר ל״מילי״. אם אתה לא בטוח, בחר מילי",
|
||||
"permissions": "הרשאות",
|
||||
"administrator": "מנהל ראשי",
|
||||
"user-can-invite-other-to-group": "משתמש יכול להזמין אחרים לקבוצה",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "משתמש יכול לנהל קבוצה",
|
||||
"user-can-organize-group-data": "משתמש יכול לשנות מידע של קבוצה",
|
||||
"enable-advanced-features": "אפשר אפשרויות מתקדמות",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Ovo određuje način autentifikacije korisnika u Mealie sustavu. Ako niste sigurni, odaberite 'Mealie",
|
||||
"permissions": "Dozvole",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "Korisnik može pozvati druge u grupu",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Korisnik može upravljati grupom",
|
||||
"user-can-organize-group-data": "Korisnik može organizirati podatke grupe",
|
||||
"enable-advanced-features": "Omogućite napredne značajke",
|
||||
|
||||
@@ -596,7 +596,7 @@
|
||||
"screen-awake": "Képernyő ébren tartása",
|
||||
"remove-image": "Kép etávolítása",
|
||||
"nextStep": "Következő lépés",
|
||||
"recipe-actions": "Recipe Actions",
|
||||
"recipe-actions": "Receptekkel kapcsolatos tevékenységek",
|
||||
"parser": {
|
||||
"experimental-alert-text": "A Mealie természetes nyelvi feldolgozást használ a recept összetevőinek elemzésére, az egységek és az élelmiszerelemek létrehozására. Ez a funkció kísérleti jellegű, és előfordulhat, hogy nem mindig működik az elvárt módon. Ha nem szeretné használni az elemzett eredményeket, válassza a 'Mégse' lehetőséget, és a módosítások nem kerülnek mentésre.",
|
||||
"ingredient-parser": "Hozzávaló elemző",
|
||||
@@ -810,11 +810,11 @@
|
||||
"items-checked-count": "Nincs ellenőrzött tétel|Egy ellenőrzött tétel|{count} ellenőrzött tétel",
|
||||
"no-label": "Nincs címke",
|
||||
"completed-on": "Teljesítve {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "Offline vagy",
|
||||
"you-are-offline-description": "Offline állapotban nem minden funkció érhető el. Továbbra is hozzáadhat, módosíthat és eltávolíthat elemeket, de a módosításokat nem tudja szinkronizálni a szerverrel, amíg vissza nem tér az online állapotba.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Biztos, hogy minden elemet be akar jelölni?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Biztos, hogy minden elem kijelölését visszavonja?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Biztosan törölni akarja az összes bejelölt elemet?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Minden recept",
|
||||
@@ -991,7 +991,7 @@
|
||||
"example-food-singular": "pl. Hagyma",
|
||||
"example-food-plural": "pl. Hagymák",
|
||||
"label-overwrite-warning": "Ez a kiválasztott címkét az összes kiválasztott élelmiszerhez hozzárendeli, és esetleg felülírja a meglévő címkéket.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"on-hand-checkbox-label": "Ha ezt a jelzőt beállítja, akkor ez az élelmiszer alapértelmezés szerint nem lesz bejelölve, amikor egy receptet hozzáad egy bevásárlólistához."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Töltse be az Ön nyelve szerinti közös mennyiségi egységet tartalmazó adatbázist.",
|
||||
@@ -1044,9 +1044,9 @@
|
||||
"source-unit-will-be-deleted": "A forrás mennyiségi egység törlésre kerül"
|
||||
},
|
||||
"recipe-actions": {
|
||||
"recipe-actions-data": "Recipe Actions Data",
|
||||
"new-recipe-action": "New Recipe Action",
|
||||
"edit-recipe-action": "Edit Recipe Action",
|
||||
"recipe-actions-data": "Receptekkel kapcsolatos tevékenységek adatai",
|
||||
"new-recipe-action": "Új recept tevékenység",
|
||||
"edit-recipe-action": "Recept tevékenység szerkesztése",
|
||||
"action-type": "Művelet típusa"
|
||||
},
|
||||
"create-alias": "Alias készítése",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie'",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -587,7 +587,7 @@
|
||||
"recipe-debugger": "Debugger Ricetta",
|
||||
"recipe-debugger-description": "Prendi l'URL della ricetta che vuoi fare il debug e incollalo qui. L'URL verrà recuperato dallo scraper di ricette e i risultati verranno visualizzati. Se non si vede alcun dato restituito, il sito che si sta cercando di analizzare non è supportato da Mealie o la sua libreria di scraping.",
|
||||
"use-openai": "Usa OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Use OpenAI to parse the results instead of relying on the scraper library. When creating a recipe via URL, this is done automatically if the scraper library fails, but you may test it manually here.",
|
||||
"recipe-debugger-use-openai-description": "Usa OpenAI per analizzare i risultati invece di affidarsi alla libreria scraper. Quando si crea una ricetta tramite URL, questo viene fatto automaticamente se la libreria scraper fallisce, ma è possibile testarlo manualmente qui.",
|
||||
"debug": "Debug",
|
||||
"tree-view": "Visualizzazione ad Albero",
|
||||
"recipe-yield": "Resa Ricetta",
|
||||
@@ -596,7 +596,7 @@
|
||||
"screen-awake": "Mantieni lo schermo acceso",
|
||||
"remove-image": "Rimuovi immagine",
|
||||
"nextStep": "Passo successivo",
|
||||
"recipe-actions": "Recipe Actions",
|
||||
"recipe-actions": "Azioni Ricetta",
|
||||
"parser": {
|
||||
"experimental-alert-text": "Mealie utilizza l'elaborazione del linguaggio naturale per analizzare e creare unità e prodotti alimentari per i vostri ingredienti di ricetta. Questa funzione è sperimentale e potrebbe non funzionare sempre come previsto. Se preferisci non usare i risultati analizzati, puoi selezionare 'Annulla' e le tue modifiche non saranno salvate.",
|
||||
"ingredient-parser": "Analizzatore ingredienti",
|
||||
@@ -605,7 +605,7 @@
|
||||
"select-parser": "Seleziona Analizzatore",
|
||||
"natural-language-processor": "Analizzatore di Linguaggio Naturale",
|
||||
"brute-parser": "Analizzatore brutale",
|
||||
"openai-parser": "OpenAI Parser",
|
||||
"openai-parser": "Parser OpenAI",
|
||||
"parse-all": "Analizza tutto",
|
||||
"no-unit": "Nessuna unità",
|
||||
"missing-unit": "Crea unità mancante: {unit}",
|
||||
@@ -640,7 +640,7 @@
|
||||
"backup-created-at-response-export_path": "Backup Creato in {path}",
|
||||
"backup-deleted": "Backup eliminato",
|
||||
"restore-success": "Ripristino riuscito",
|
||||
"restore-fail": "Restore failed. Check your server logs for more details",
|
||||
"restore-fail": "Ripristino non riuscito. Controlla i log del tuo server per maggiori dettagli",
|
||||
"backup-tag": "Tag Backup",
|
||||
"create-heading": "Crea un Backup",
|
||||
"delete-backup": "Elimina Backup",
|
||||
@@ -778,9 +778,9 @@
|
||||
"oidc-ready": "Pronto per OIDC",
|
||||
"oidc-ready-error-text": "I valori OIDC non sono configurati. Questo può essere ignorato se non si utilizza Autenticazione OIDC.",
|
||||
"oidc-ready-success-text": "Le variabili OIDC richieste sono tutte impostate.",
|
||||
"openai-ready": "OpenAI Ready",
|
||||
"openai-ready-error-text": "Not all OpenAI Values are configured. This can be ignored if you are not using OpenAI features.",
|
||||
"openai-ready-success-text": "Required OpenAI variables are all set."
|
||||
"openai-ready": "OpenAI Pronto",
|
||||
"openai-ready-error-text": "Non tutti i valori OpenAI sono configurati. Puoi ignorarlo se non utilizzi le funzioni di OpenAI.",
|
||||
"openai-ready-success-text": "Le variabili OpenAI richieste sono tutte impostate."
|
||||
},
|
||||
"shopping-list": {
|
||||
"all-lists": "Tutte le Liste",
|
||||
@@ -794,7 +794,7 @@
|
||||
"food": "Alimenti",
|
||||
"note": "Nota",
|
||||
"label": "Etichetta",
|
||||
"save-label": "Save Label",
|
||||
"save-label": "Salva Etichetta",
|
||||
"linked-item-warning": "Questo elemento è collegato a una o più ricette. La modifica delle unità o degli alimenti potrebbe dare risultati inattesi quando si aggiunge o si rimuove la ricetta da questo elenco.",
|
||||
"toggle-food": "Attiva/Disattiva Alimento",
|
||||
"manage-labels": "Gestisci Etichette",
|
||||
@@ -810,11 +810,11 @@
|
||||
"items-checked-count": "Nessun elemento selezionato|Un elemento selezionato|{count} elementi selezionati",
|
||||
"no-label": "Nessuna etichetta",
|
||||
"completed-on": "Completato il {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "Non sei in linea",
|
||||
"you-are-offline-description": "Non tutte le funzioni sono disponibili quando non sei in linea. Puoi ancora aggiungere, modificare e rimuovere elementi, ma non sarai in grado di sincronizzare le modifiche con il server fino a quando non sarai di nuovo in linea.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Sei sicuro di voler tutti gli elementi?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Sei sicuro di voler deselezionare tutti gli elementi?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Sei sicuro di voler rimuovere tutti gli articoli selezionati?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Ricette",
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Indica come un utente si autenticherà con Mealie. Se non sei sicuro, scegli 'Mealie",
|
||||
"permissions": "Permessi",
|
||||
"administrator": "Amministratore",
|
||||
"user-can-invite-other-to-group": "L'utente può invitare altri al gruppo",
|
||||
"user-can-invite-other-to-group": "L'utente può invitare altre persone nel gruppo",
|
||||
"user-can-manage-group": "L'utente può gestire il gruppo",
|
||||
"user-can-organize-group-data": "L'utente può organizzare i dati del gruppo",
|
||||
"enable-advanced-features": "Abilita funzionalità avanzate",
|
||||
@@ -990,8 +990,8 @@
|
||||
"food-data": "Dati Alimento",
|
||||
"example-food-singular": "esempio: Cipolla",
|
||||
"example-food-plural": "esempio: Cipolle",
|
||||
"label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"label-overwrite-warning": "Questo assegnerà l'etichetta scelta a tutti gli alimenti selezionati e potenzialmente sovrascriverà le etichette esistenti.",
|
||||
"on-hand-checkbox-label": "Abilitando questa impostazione, l'alimento verrà deselezionato di default quando si aggiungerà una ricetta a una lista della spesa."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Riempie il database con unità comuni basate sulla lingua.",
|
||||
@@ -1020,7 +1020,7 @@
|
||||
"edit-label": "Modifica Etichetta",
|
||||
"new-label": "Nuova Etichetta",
|
||||
"labels": "Etichette",
|
||||
"assign-label": "Assign Label"
|
||||
"assign-label": "Assegna Etichetta"
|
||||
},
|
||||
"recipes": {
|
||||
"purge-exports": "Elimina Esportazioni",
|
||||
@@ -1044,10 +1044,10 @@
|
||||
"source-unit-will-be-deleted": "L'unità di origine verrà eliminata"
|
||||
},
|
||||
"recipe-actions": {
|
||||
"recipe-actions-data": "Recipe Actions Data",
|
||||
"new-recipe-action": "New Recipe Action",
|
||||
"edit-recipe-action": "Edit Recipe Action",
|
||||
"action-type": "Action Type"
|
||||
"recipe-actions-data": "Dati Azioni Ricetta",
|
||||
"new-recipe-action": "Nuova Azione Ricetta",
|
||||
"edit-recipe-action": "Modifica Azione Ricetta",
|
||||
"action-type": "Tipo Di Azione"
|
||||
},
|
||||
"create-alias": "Crea Alias",
|
||||
"manage-aliases": "Gestisci Alias",
|
||||
|
||||
@@ -210,8 +210,8 @@
|
||||
"unsaved-changes": "保存されていない変更があります。移動する前に保存しますか?保存するには はい を、変更を破棄するにはキャンセルしてください。",
|
||||
"clipboard-copy-failure": "クリップボードにコピーできませんでした",
|
||||
"confirm-delete-generic-items": "次のアイテムを本当に削除しますか?",
|
||||
"organizers": "Organizers",
|
||||
"caution": "Caution"
|
||||
"organizers": "収納",
|
||||
"caution": "注意"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "<b>{groupName}<b/> を削除しますか?",
|
||||
@@ -292,8 +292,8 @@
|
||||
"mealplan-updated": "献立を更新しました",
|
||||
"no-meal-plan-defined-yet": "食事プランはまだ定義されていません",
|
||||
"no-meal-planned-for-today": "今日の食事プランはありません",
|
||||
"numberOfDays-hint": "Number of days on page load",
|
||||
"numberOfDays-label": "Default Days",
|
||||
"numberOfDays-hint": "ページ読み込みの日数",
|
||||
"numberOfDays-label": "デフォルトの日数",
|
||||
"only-recipes-with-these-categories-will-be-used-in-meal-plans": "食事プランでは、これらのカテゴリを持つレシピのみが使用されます",
|
||||
"planner": "プランナー",
|
||||
"quick-week": "クイックウィーク",
|
||||
@@ -383,7 +383,7 @@
|
||||
},
|
||||
"recipekeeper": {
|
||||
"title": "Recipe Keeper",
|
||||
"description-long": "Mealie can import recipes from Recipe Keeper. Export your recipes in zip format, then upload the .zip file below."
|
||||
"description-long": "MealieはRecipe Keeperからレシピをインポートできます。レシピをzip形式でエクスポートし、以下に.zipファイルをアップロードしてください。"
|
||||
}
|
||||
},
|
||||
"new-recipe": {
|
||||
@@ -449,8 +449,8 @@
|
||||
"ingredients": "材料",
|
||||
"insert-ingredient": "材料を投入",
|
||||
"insert-section": "手順を挿入",
|
||||
"insert-above": "Insert Above",
|
||||
"insert-below": "Insert Below",
|
||||
"insert-above": "上に挿入",
|
||||
"insert-below": "下に挿入",
|
||||
"instructions": "説明",
|
||||
"key-name-required": "キー名が必要です",
|
||||
"landscape-view-coming-soon": "Landscape View (Coming Soon)",
|
||||
@@ -586,8 +586,8 @@
|
||||
"report-deletion-failed": "レポートの削除に失敗しました",
|
||||
"recipe-debugger": "レシピのデバッガー",
|
||||
"recipe-debugger-description": "デバッグしたいレシピのURLを取得し、ここに貼り付けます。 URLはレシピスクレーパーによって削除され、結果が表示されます。 データが返されていない場合、スクレイプしようとしているサイトはMealieまたはそのスクレイパーライブラリではサポートされていません。",
|
||||
"use-openai": "Use OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Use OpenAI to parse the results instead of relying on the scraper library. When creating a recipe via URL, this is done automatically if the scraper library fails, but you may test it manually here.",
|
||||
"use-openai": "OpenAIを使用する",
|
||||
"recipe-debugger-use-openai-description": "スクレーパーライブラリに依存するのではなく、結果を解析するためにOpenAIを使用してください。 URL経由でレシピを作成する場合は、スクレーパーライブラリが失敗した場合に自動的に行われますが、ここで手動でテストすることができます。",
|
||||
"debug": "デバッグ",
|
||||
"tree-view": "ツリービュー",
|
||||
"recipe-yield": "レシピ収率",
|
||||
@@ -598,19 +598,19 @@
|
||||
"nextStep": "次のステップ",
|
||||
"recipe-actions": "レシピ操作",
|
||||
"parser": {
|
||||
"experimental-alert-text": "Mealie uses natural language processing to parse and create units and food items for your recipe ingredients. This feature is experimental and may not always work as expected. If you prefer not to use the parsed results, you can select 'Cancel' and your changes will not be saved.",
|
||||
"experimental-alert-text": "Mealieは、自然言語処理を使用して、レシピ成分のための単位や食品を解析し、作成します。 この機能は実験的であり、常に期待どおりに動作するとは限りません。 解析結果を使用したくない場合は、「キャンセル」を選択することができ、変更内容は保存されません。",
|
||||
"ingredient-parser": "Ingredient Parser",
|
||||
"explanation": "To use the ingredient parser, click the 'Parse All' button to start the process. Once the processed ingredients are available, you can review the items and verify that they were parsed correctly. The model's confidence score is displayed on the right of the item title. This score is an average of all the individual scores and may not always be completely accurate.",
|
||||
"alerts-explainer": "Alerts will be displayed if a matching foods or unit is found but does not exists in the database.",
|
||||
"select-parser": "Select Parser",
|
||||
"natural-language-processor": "Natural Language Processor",
|
||||
"brute-parser": "Brute Parser",
|
||||
"openai-parser": "OpenAI Parser",
|
||||
"parse-all": "Parse All",
|
||||
"no-unit": "No unit",
|
||||
"missing-unit": "Create missing unit: {unit}",
|
||||
"missing-food": "Create missing food: {food}",
|
||||
"no-food": "No Food"
|
||||
"explanation": "Ingredient Parserを使用するには、「すべて解析」ボタンをクリックしてプロセスを開始します。 処理された原材料が利用可能になったら、項目を確認し、それらが正しく解析されたことを確認できます。 アイテムタイトルの右側にモデルの信頼度が表示されます。 このスコアは、すべての個々のスコアの平均であり、常に完全に正確であるとは限りません。",
|
||||
"alerts-explainer": "一致する食品または単位が見つかってもデータベースに存在しない場合は、アラートが表示されます。",
|
||||
"select-parser": "パーサを選択",
|
||||
"natural-language-processor": "自然言語処理",
|
||||
"brute-parser": "Bruteパーサ",
|
||||
"openai-parser": "OpenAIパーサ",
|
||||
"parse-all": "すべて解析",
|
||||
"no-unit": "単位がありません",
|
||||
"missing-unit": "欠けている単位を作成: {unit}",
|
||||
"missing-food": "欠けている食材を作成: {food}",
|
||||
"no-food": "食材はありません"
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
@@ -640,7 +640,7 @@
|
||||
"backup-created-at-response-export_path": "{path} にバックアップを作成しました",
|
||||
"backup-deleted": "バックアップを削除しました",
|
||||
"restore-success": "復元に成功しました",
|
||||
"restore-fail": "Restore failed. Check your server logs for more details",
|
||||
"restore-fail": "復元に失敗しました。詳細はサーバーのログを確認してください",
|
||||
"backup-tag": "バックアップ タグ",
|
||||
"create-heading": "Create a Backup",
|
||||
"delete-backup": "バックアップを削除",
|
||||
@@ -771,7 +771,7 @@
|
||||
"server-side-base-url-error-text": "`BASE_URL` はAPIサーバーのデフォルト値です。サーバー上でメールなどの通知リンクが生成されると問題が発生します。",
|
||||
"server-side-base-url-success-text": "サーバー側のURLがデフォルトと一致しません",
|
||||
"ldap-ready": "LDAP対応",
|
||||
"ldap-ready-error-text": "すべてのLDAP値が設定されているわけではありません。LDAP認証を使用していない場合はこれは無視できます。",
|
||||
"ldap-ready-error-text": "すべてのLDAP値が設定されていません。LDAP認証を使用していない場合は無視できます。",
|
||||
"ldap-ready-success-text": "必要なLDAP変数はすべて設定されています。",
|
||||
"build": "Build",
|
||||
"recipe-scraper-version": "Recipe Scraper バージョン",
|
||||
@@ -779,8 +779,8 @@
|
||||
"oidc-ready-error-text": "すべてのOIDC値が設定されていません。OIDC認証を使用していない場合は無視できます。",
|
||||
"oidc-ready-success-text": "必要なOIDC変数はすべて設定されています。",
|
||||
"openai-ready": "OpenAI Ready",
|
||||
"openai-ready-error-text": "Not all OpenAI Values are configured. This can be ignored if you are not using OpenAI features.",
|
||||
"openai-ready-success-text": "Required OpenAI variables are all set."
|
||||
"openai-ready-error-text": "すべてのOpenAIの値が設定されていません。OpenAIを使用していない場合は無視できます。",
|
||||
"openai-ready-success-text": "必須のOpenAI変数はすべて設定されています。"
|
||||
},
|
||||
"shopping-list": {
|
||||
"all-lists": "すべてのリスト",
|
||||
@@ -794,7 +794,7 @@
|
||||
"food": "食料",
|
||||
"note": "メモ",
|
||||
"label": "ラベル",
|
||||
"save-label": "Save Label",
|
||||
"save-label": "ラベルを保存",
|
||||
"linked-item-warning": "このアイテムは 1 つ以上のレシピにリンクされています。このリストにレシピを追加または削除するときに、単位や食品を調整すると予期しない結果が生じることがあります。",
|
||||
"toggle-food": "食料の切り替え",
|
||||
"manage-labels": "ラベルの管理",
|
||||
@@ -810,11 +810,11 @@
|
||||
"items-checked-count": "チェックされたアイテムはありません|チェックされたアイテムは1つです| チェックされたアイテムは {count} です",
|
||||
"no-label": "ラベルなし",
|
||||
"completed-on": "完了日: {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "オフライン",
|
||||
"you-are-offline-description": "オフライン中は機能が一部制限されます。 アイテムの追加、変更、削除は可能ですがオンラインに戻るまでサーバーに変更を同期することはできません",
|
||||
"are-you-sure-you-want-to-check-all-items": "すべての項目をチェックしてもよろしいですか?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "すべてのアイテムのチェックを外してもよろしいですか?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "チェックされた項目をすべて削除してもよろしいですか?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "すべてのレシピ",
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "権限",
|
||||
"administrator": "管理者",
|
||||
"user-can-invite-other-to-group": "ユーザーは他のグループに招待できます",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "ユーザーはグループを管理できます",
|
||||
"user-can-organize-group-data": "ユーザーはグループデータを整理できます",
|
||||
"enable-advanced-features": "高度な機能を有効にする",
|
||||
@@ -990,8 +990,8 @@
|
||||
"food-data": "食品データ",
|
||||
"example-food-singular": "例: 玉ねぎ",
|
||||
"example-food-plural": "例: 玉ねぎ",
|
||||
"label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"label-overwrite-warning": "選択したすべての食品に選択したラベルが割り当てられ、既存のラベルが上書きされます。",
|
||||
"on-hand-checkbox-label": "このフラグを設定すると、ショッピング リストにレシピを追加するときに、デフォルトでこの食品のチェックが外されます。"
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "ローカル言語に基づいた共通の単位をデータベースにシードします。",
|
||||
@@ -1020,7 +1020,7 @@
|
||||
"edit-label": "ラベルの編集",
|
||||
"new-label": "新規ラベル",
|
||||
"labels": "ラベル",
|
||||
"assign-label": "Assign Label"
|
||||
"assign-label": "ラベルの割り当て"
|
||||
},
|
||||
"recipes": {
|
||||
"purge-exports": "エクスポートの削除",
|
||||
@@ -1044,10 +1044,10 @@
|
||||
"source-unit-will-be-deleted": "元の単位が削除されます"
|
||||
},
|
||||
"recipe-actions": {
|
||||
"recipe-actions-data": "Recipe Actions Data",
|
||||
"new-recipe-action": "New Recipe Action",
|
||||
"edit-recipe-action": "Edit Recipe Action",
|
||||
"action-type": "Action Type"
|
||||
"recipe-actions-data": "レシピ操作データ",
|
||||
"new-recipe-action": "新しいレシピ操作",
|
||||
"edit-recipe-action": "レシピ操作の編集",
|
||||
"action-type": "操作タイプ"
|
||||
},
|
||||
"create-alias": "エイリアスを作成",
|
||||
"manage-aliases": "エイリアスの管理",
|
||||
@@ -1222,16 +1222,16 @@
|
||||
"get-invite-link": "招待リンクを取得",
|
||||
"get-public-link": "公開リンクを取得",
|
||||
"account-summary": "アカウントの概要",
|
||||
"account-summary-description": "Here's a summary of your group's information.",
|
||||
"account-summary-description": "グループ情報の概要は次のとおりです.",
|
||||
"group-statistics": "グループ統計",
|
||||
"group-statistics-description": "グループ統計によりMealieの使用状況がわかります。",
|
||||
"storage-capacity": "ストレージ容量",
|
||||
"storage-capacity-description": "ストレージ容量は、アップロードした画像とアセットの合計です。",
|
||||
"personal": "個人",
|
||||
"personal-description": "These are settings that are personal to you. Changes here won't affect other users.",
|
||||
"personal-description": "これらは個人的な設定です。ここでの変更は他のユーザーには影響しません.",
|
||||
"user-settings": "ユーザー設定",
|
||||
"user-settings-description": "Manage your preferences, change your password, and update your email.",
|
||||
"api-tokens-description": "Manage your API Tokens for access from external applications.",
|
||||
"user-settings-description": "設定を管理し、パスワードを変更し、電子メールを更新します。",
|
||||
"api-tokens-description": "外部アプリケーションからアクセスするためのAPIトークンを管理します.",
|
||||
"group-description": "これらのアイテムはグループ内で共有されます。そのうちの 1 つを編集すると、グループ全体の内容が変更されます。",
|
||||
"group-settings": "グループ設定",
|
||||
"group-settings-description": "食事プランやプライバシー設定などの共通のグループ設定を管理します。",
|
||||
@@ -1242,9 +1242,9 @@
|
||||
"notifiers": "通知",
|
||||
"notifiers-description": "Setup email and push notifications that trigger on specific events.",
|
||||
"manage-data": "データ管理",
|
||||
"manage-data-description": "Manage your Mealie data; Foods, Units, Categories, Tags and more.",
|
||||
"manage-data-description": "Mealieデータの管理:食材、単位、カテゴリ、タグなど。",
|
||||
"data-migrations": "データ移行",
|
||||
"data-migrations-description": "Migrate your existing data from other applications like Nextcloud Recipes and Chowdown.",
|
||||
"data-migrations-description": "NextcloudレシピやChowdownなどの他のアプリケーションから既存のデータを移行します。",
|
||||
"email-sent": "メールが送信されました",
|
||||
"error-sending-email": "メール送信エラー",
|
||||
"personal-information": "個人情報",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Leidimai",
|
||||
"administrator": "Administratorius",
|
||||
"user-can-invite-other-to-group": "Naudotojas gali kviesti kitus į grupę",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Naudotojas gali valdyti grupę",
|
||||
"user-can-organize-group-data": "Naudotojas gali tvarkyti grupės duomenis",
|
||||
"enable-advanced-features": "Įjungti pažangias funkcijas",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Dit bepaalt hoe een gebruiker zich aanmeldt bij Mealie. Als je het niet zeker weet, kies dan voor 'Mealie'",
|
||||
"permissions": "Gebruikersrechten",
|
||||
"administrator": "Beheerder",
|
||||
"user-can-invite-other-to-group": "Gebruiker kan iemand uitnodigen voor de groep",
|
||||
"user-can-invite-other-to-group": "Gebruiker kan anderen uitnodigen voor zijn groep",
|
||||
"user-can-manage-group": "Gebruiker kan de groep beheren",
|
||||
"user-can-organize-group-data": "Gebruiker kan groepsgegevens indelen",
|
||||
"enable-advanced-features": "Geavanceerde functies inschakelen",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Rettigheter",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "Brukeren kan invitere andre til gruppe",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Brukeren kan administrere gruppe",
|
||||
"user-can-organize-group-data": "Brukeren kan organisere gruppedata",
|
||||
"enable-advanced-features": "Aktiver avanserte funksjoner",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Określa jak użytkownik będzie uwierzytelniać się z Mealie. Jeśli nie jesteś pewien, wybierz 'Mealie",
|
||||
"permissions": "Uprawnienia",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "Użytkownik może zaprosić innych do grupy",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Użytkownik może zarządzać grupą",
|
||||
"user-can-organize-group-data": "Użytkownik może organizować dane grupy",
|
||||
"enable-advanced-features": "Włącz zaawansowane funkcje",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Isto especifica como um usuário se autentica com o Mealie. Se não tem certeza, escolha \"Mealie\"",
|
||||
"permissions": "Permissões",
|
||||
"administrator": "Administrador",
|
||||
"user-can-invite-other-to-group": "O usuário pode convidar outro para o grupo",
|
||||
"user-can-invite-other-to-group": "O usuário pode convidar outros para o grupo",
|
||||
"user-can-manage-group": "Usuário pode gerenciar o grupo",
|
||||
"user-can-organize-group-data": "Usuário pode organizar dados do grupo",
|
||||
"enable-advanced-features": "Ativar recursos avançados",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissões",
|
||||
"administrator": "Administrador",
|
||||
"user-can-invite-other-to-group": "O utilizador pode convidar outro para o grupo",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "O utilizador pode gerir o grupo",
|
||||
"user-can-organize-group-data": "O utilizador pode organizar dados do grupo",
|
||||
"enable-advanced-features": "Habilitar recursos avançados",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Права доступа",
|
||||
"administrator": "Администратор",
|
||||
"user-can-invite-other-to-group": "Пользователь может пригласить других в группу",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Пользователь может управлять группой",
|
||||
"user-can-organize-group-data": "Пользователь может менять групповые данные",
|
||||
"enable-advanced-features": "Включить доп. функции",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Toto určuje ako bude overený užívateľ. Ak si nie ste istý, zvoľte 'Mealie'",
|
||||
"permissions": "Povolenia",
|
||||
"administrator": "Administrátor",
|
||||
"user-can-invite-other-to-group": "Užívateľ môže do skupiny pozvať ďalších",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Užívateľ môže spravovať skupinu",
|
||||
"user-can-organize-group-data": "Užívateľ môže spravovať údaje skupiny",
|
||||
"enable-advanced-features": "Povoliť pokročilé funkcie",
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
"clipboard-copy-failure": "Kopiranje na odložišče ni bilo uspešno.",
|
||||
"confirm-delete-generic-items": "Ali ste prepričani, da želite izbrisati izbrane elemente?",
|
||||
"organizers": "Organizatorji",
|
||||
"caution": "Caution"
|
||||
"caution": "Pozor"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "Ste prepričani, da želite izbrisati <b>{groupName}<b/>?",
|
||||
@@ -449,8 +449,8 @@
|
||||
"ingredients": "Sestavine",
|
||||
"insert-ingredient": "Dodaj sestavino",
|
||||
"insert-section": "Vstavi odsek",
|
||||
"insert-above": "Insert Above",
|
||||
"insert-below": "Insert Below",
|
||||
"insert-above": "Vstavi zgoraj",
|
||||
"insert-below": "Vstavi spodaj",
|
||||
"instructions": "Navodila",
|
||||
"key-name-required": "Obvezen vnos imena ključa",
|
||||
"landscape-view-coming-soon": "Ležeči pogled",
|
||||
@@ -586,7 +586,7 @@
|
||||
"report-deletion-failed": "Brisanje poročila ni bilo uspešno",
|
||||
"recipe-debugger": "Odpravljanje težav v strganju recepta",
|
||||
"recipe-debugger-description": "Prilepi povezavo do recepta, ki ga želiš postrgati. Strgalnik receptov bo postrgal spletno stran in prikazal rezultate. Če ne vidiš nobenih podatkov, potem spletna stran, ki jo želiš strgati ni podprta v Mealie oz. v strgalniku, ki ga uporablja.",
|
||||
"use-openai": "Use OpenAI",
|
||||
"use-openai": "Uporabi OpenAI",
|
||||
"recipe-debugger-use-openai-description": "Use OpenAI to parse the results instead of relying on the scraper library. When creating a recipe via URL, this is done automatically if the scraper library fails, but you may test it manually here.",
|
||||
"debug": "Debug",
|
||||
"tree-view": "Drevesni prikaz",
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Dovoljenja",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "Uporabnik lahko druge povabi v skupino",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "Uporabnik lahko upravlja s skupino",
|
||||
"user-can-organize-group-data": "Uporabnik lahko organizira podatke skupine",
|
||||
"enable-advanced-features": "Vključi napredne funkcije",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "Ово одређује како ће се корисник аутентификовати са Mили. Ако нисте сигурни, изаберите 'Mealie'",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
"clipboard-copy-failure": "Det gick inte att kopiera till urklipp.",
|
||||
"confirm-delete-generic-items": "Är du säker på att du vill radera följande objekt?",
|
||||
"organizers": "Organisatörer",
|
||||
"caution": "Caution"
|
||||
"caution": "Varning"
|
||||
},
|
||||
"group": {
|
||||
"are-you-sure-you-want-to-delete-the-group": "Är du säker på att du vill radera <b>{groupName}<b/>?",
|
||||
@@ -449,8 +449,8 @@
|
||||
"ingredients": "Ingredienser",
|
||||
"insert-ingredient": "Infoga ingrediens",
|
||||
"insert-section": "Infoga avdelning",
|
||||
"insert-above": "Insert Above",
|
||||
"insert-below": "Insert Below",
|
||||
"insert-above": "Infoga Ovan",
|
||||
"insert-below": "Infoga Nedan",
|
||||
"instructions": "Instruktioner",
|
||||
"key-name-required": "Nyckelnamn krävs",
|
||||
"landscape-view-coming-soon": "Landskapsvy (kommer snart)",
|
||||
@@ -810,11 +810,11 @@
|
||||
"items-checked-count": "Inga artiklar markerade|En artikel markerad|{count} artiklar markerade",
|
||||
"no-label": "Ingen etikett",
|
||||
"completed-on": "Slutförd på {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "Du är offline",
|
||||
"you-are-offline-description": "Alla funktioner är inte tillgängliga när du är offline. Du kan fortfarande lägga till, ändra och ta bort objekt, men du kommer ej kunna synka dina ändringar till servern förrän du är online igen.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Är du säker på att du vill markera alla objekt?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Är du säker på att du vill avmarkera alla objekt?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Är du säker på att du vill ta bort alla markerade objekt?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Recept",
|
||||
@@ -990,8 +990,8 @@
|
||||
"food-data": "Mat data",
|
||||
"example-food-singular": "ex: Lök",
|
||||
"example-food-plural": "ex: Lökar",
|
||||
"label-overwrite-warning": "This will assign the chosen label to all selected foods and potentially overwrite your existing labels.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"label-overwrite-warning": "Detta kommer att tilldela den valda etiketten till alla utvalda måltider och potentiellt skriva över dina befintliga etiketter.",
|
||||
"on-hand-checkbox-label": "Om du ställer in den här flaggan kommer de här livsmedlen att avmarkeras som standard när du lägger till ett recept i en inköpslista."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Fyll databasen med vanliga enheter baserade på ditt språk.",
|
||||
@@ -1020,7 +1020,7 @@
|
||||
"edit-label": "Redigera etikett",
|
||||
"new-label": "Ny etikett",
|
||||
"labels": "Etiketter",
|
||||
"assign-label": "Assign Label"
|
||||
"assign-label": "Tilldela etikett"
|
||||
},
|
||||
"recipes": {
|
||||
"purge-exports": "Rensa exporter",
|
||||
|
||||
@@ -804,17 +804,17 @@
|
||||
"delete-checked": "Видалити відмічене",
|
||||
"toggle-label-sort": "Сортування міток",
|
||||
"reorder-labels": "Перевпорядкувати мітки",
|
||||
"uncheck-all-items": "Зняти вибір з усіх елементів",
|
||||
"check-all-items": "Вибрати всі елементи",
|
||||
"uncheck-all-items": "Зняти відмітку з усіх елементів",
|
||||
"check-all-items": "Відмітити всі елементи",
|
||||
"linked-recipes-count": "Нема пов'язаних рецептів|Один пов'язаний рецепт|{count} пов'язаних рецептів",
|
||||
"items-checked-count": "Нема відмічених елементів|Один відмічений елемент|{count} елементів відмічено",
|
||||
"no-label": "Без Мітки",
|
||||
"completed-on": "Завершено {date}",
|
||||
"you-are-offline": "You are offline",
|
||||
"you-are-offline-description": "Not all features are available while offline. You can still add, modify, and remove items, but you will not be able to sync your changes to the server until you are back online.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Are you sure you want to check all items?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Are you sure you want to uncheck all items?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Are you sure you want to delete all checked items?"
|
||||
"you-are-offline": "Ви не в мережі",
|
||||
"you-are-offline-description": "Не всі функції доступні без мережі. Ви все ще можете додавати, змінювати та видаляти елементи, але не зможете синхронізувати зміни на сервер, поки під'єднаєтесь до мережі.",
|
||||
"are-you-sure-you-want-to-check-all-items": "Ви впевнені, що хочете відмітити всі елементи?",
|
||||
"are-you-sure-you-want-to-uncheck-all-items": "Ви впевнені, що хочете зняти відмітку з усіх елементів?",
|
||||
"are-you-sure-you-want-to-delete-checked-items": "Ви впевнені, що хочете видалити всі відмічені елементи?"
|
||||
},
|
||||
"sidebar": {
|
||||
"all-recipes": "Всі рецепти",
|
||||
@@ -867,7 +867,7 @@
|
||||
"create-a-tool": "Створити новий інструмент",
|
||||
"tool-name": "Назва інструмента",
|
||||
"create-new-tool": "Створити новий інструмент",
|
||||
"on-hand-checkbox-label": "Показувати як в наявності (позначено)",
|
||||
"on-hand-checkbox-label": "Показувати як в наявності (відмічене)",
|
||||
"required-tools": "Необхідні інструменти",
|
||||
"tool": "Інструмент"
|
||||
},
|
||||
@@ -991,7 +991,7 @@
|
||||
"example-food-singular": "приклад: Цибулина",
|
||||
"example-food-plural": "приклад: Цибуля",
|
||||
"label-overwrite-warning": "Це призначить обрану мітку для всіх вибраних продуктів і потенційно перезапише існуючі мітки.",
|
||||
"on-hand-checkbox-label": "Setting this flag will make this food unchecked by default when adding a recipe to a shopping list."
|
||||
"on-hand-checkbox-label": "Встановлення цього параметра дозволить зробити цю їжу невідміченою за замовчуванням при додаванні рецепта до списку покупок."
|
||||
},
|
||||
"units": {
|
||||
"seed-dialog-text": "Заповнити базу даних розповсюдженими одиницями виміру що відповідають мові.",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "权限",
|
||||
"administrator": "管理员",
|
||||
"user-can-invite-other-to-group": "用户可以邀请其他人加入群组",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "用户可以管理群组",
|
||||
"user-can-organize-group-data": "用户可以整理群组数据",
|
||||
"enable-advanced-features": "启用高级功能",
|
||||
|
||||
@@ -958,7 +958,7 @@
|
||||
"authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie",
|
||||
"permissions": "Permissions",
|
||||
"administrator": "Administrator",
|
||||
"user-can-invite-other-to-group": "User can invite other to group",
|
||||
"user-can-invite-other-to-group": "User can invite others to group",
|
||||
"user-can-manage-group": "User can manage group",
|
||||
"user-can-organize-group-data": "User can organize group data",
|
||||
"enable-advanced-features": "Enable advanced features",
|
||||
|
||||
@@ -6,9 +6,15 @@ const prefix = "/api";
|
||||
const routes = {
|
||||
webhooks: `${prefix}/groups/webhooks`,
|
||||
webhooksId: (id: string | number) => `${prefix}/groups/webhooks/${id}`,
|
||||
webhooksIdTest: (id: string | number) => `${prefix}/groups/webhooks/${id}/test`,
|
||||
};
|
||||
|
||||
export class WebhooksAPI extends BaseCRUDAPI<CreateWebhook, ReadWebhook> {
|
||||
baseRoute = routes.webhooks;
|
||||
itemRoute = routes.webhooksId;
|
||||
itemTestRoute = routes.webhooksIdTest;
|
||||
|
||||
async testOne(itemId: string | number) {
|
||||
return await this.requests.post<null>(`${this.itemTestRoute(itemId)}`, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ import {
|
||||
mdiRotateRight,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiFileCabinet,
|
||||
mdiSilverwareForkKnife
|
||||
} from "@mdi/js";
|
||||
|
||||
export const icons = {
|
||||
@@ -249,6 +250,7 @@ export const icons = {
|
||||
search: mdiMagnify,
|
||||
shareVariant: mdiShareVariant,
|
||||
shuffleVariant: mdiShuffleVariant,
|
||||
silverwareForkKnife: mdiSilverwareForkKnife,
|
||||
sort: mdiSort,
|
||||
sortAscending: mdiSortAscending,
|
||||
sortDescending: mdiSortDescending,
|
||||
|
||||
@@ -351,13 +351,22 @@ export default {
|
||||
},
|
||||
manifest: {
|
||||
start_url: "/",
|
||||
scope: "/",
|
||||
lang: "en",
|
||||
dir: "auto",
|
||||
name: "Mealie",
|
||||
short_name: "Mealie",
|
||||
id: "mealie",
|
||||
description: "Mealie is a recipe management and meal planning app",
|
||||
theme_color: process.env.THEME_LIGHT_PRIMARY || "#E58325",
|
||||
background_color: "#FFFFFF",
|
||||
display: "standalone",
|
||||
display_override: [
|
||||
"standalone",
|
||||
"minimal-ui",
|
||||
"browser",
|
||||
"window-controls-overlay"
|
||||
],
|
||||
share_target: {
|
||||
action: "/r/create/url",
|
||||
method: "GET",
|
||||
@@ -395,6 +404,56 @@ export default {
|
||||
purpose: "maskable",
|
||||
},
|
||||
],
|
||||
screenshots: [
|
||||
{
|
||||
"src": "/screenshots/home-narrow.png",
|
||||
"sizes": "1600x2420",
|
||||
"form_factor": "narrow",
|
||||
"label": "Home Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/recipe-narrow.png",
|
||||
"sizes": "1600x2420",
|
||||
"form_factor": "narrow",
|
||||
"label": "Recipe Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/editor-narrow.png",
|
||||
"sizes": "1600x2420",
|
||||
"form_factor": "narrow",
|
||||
"label": "Editor Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/parser-narrow.png",
|
||||
"sizes": "1600x2420",
|
||||
"form_factor": "narrow",
|
||||
"label": "Parser Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/home-wide.png",
|
||||
"sizes": "2560x1460",
|
||||
"form_factor": "wide",
|
||||
"label": "Home Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/recipe-wide.png",
|
||||
"sizes": "2560x1460",
|
||||
"form_factor": "wide",
|
||||
"label": "Recipe Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/editor-wide.png",
|
||||
"sizes": "2560x1460",
|
||||
"form_factor": "wide",
|
||||
"label": "Editor Page"
|
||||
},
|
||||
{
|
||||
"src": "/screenshots/parser-wide.png",
|
||||
"sizes": "2560x1460",
|
||||
"form_factor": "wide",
|
||||
"label": "Parser Page"
|
||||
}
|
||||
],
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Shopping Lists",
|
||||
@@ -403,8 +462,12 @@ export default {
|
||||
"url": "/shopping-lists",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/svgs/mdiFormatListChecks.svg",
|
||||
"sizes": "256x256",
|
||||
"src": "/icons/mdiFormatListChecks-192x192.png",
|
||||
"sizes": "192x192",
|
||||
},
|
||||
{
|
||||
"src": "/icons/mdiFormatListChecks-96x96.png",
|
||||
"sizes": "96x96",
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -415,12 +478,28 @@ export default {
|
||||
"url": "/group/mealplan/planner/view",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/svgs/mdiCalendarMultiselect.svg",
|
||||
"sizes": "256x256",
|
||||
"src": "/icons/mdiCalendarMultiselect-192x192.png",
|
||||
"sizes": "192x192",
|
||||
},
|
||||
{
|
||||
"src": "/icons/mdiCalendarMultiselect-96x96.png",
|
||||
"sizes": "96x96",
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
prefer_related_applications: false,
|
||||
handle_links: "preferred",
|
||||
orientation: "any",
|
||||
categories: [
|
||||
"food"
|
||||
],
|
||||
launch_handler: {
|
||||
"client_mode": ["focus-existing", "auto"]
|
||||
},
|
||||
edge_side_panel: {
|
||||
"preferred_width": 400
|
||||
}
|
||||
},
|
||||
icon: false, // disables the icon module
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mealie",
|
||||
"version": "1.0.0",
|
||||
"version": "1.10.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt",
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
:slug="mealplan.recipe ? mealplan.recipe.slug : mealplan.title"
|
||||
:description="mealplan.recipe ? mealplan.recipe.description : mealplan.text"
|
||||
:name="mealplan.recipe ? mealplan.recipe.name : mealplan.title"
|
||||
:tags="mealplan.recipe ? mealplan.recipe.tags : []"
|
||||
/>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
</v-card-text>
|
||||
</BasePageTitle>
|
||||
|
||||
<BannerExperimental />
|
||||
|
||||
<BaseButton create @click="actions.createOne()" />
|
||||
<v-expansion-panels class="mt-2">
|
||||
<v-expansion-panel v-for="(webhook, index) in webhooks" :key="index" class="my-2 left-border rounded">
|
||||
@@ -36,6 +34,7 @@
|
||||
:webhook="webhook"
|
||||
@save="actions.updateOne($event)"
|
||||
@delete="actions.deleteOne($event)"
|
||||
@test="actions.testOne($event).then(() => alert.success($tc('events.test-message-sent')))"
|
||||
/>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
@@ -47,6 +46,7 @@
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useGroupWebhooks, timeUTC } from "~/composables/use-group-webhooks";
|
||||
import GroupWebhookEditor from "~/components/Domain/Group/GroupWebhookEditor.vue";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
|
||||
export default defineComponent({
|
||||
components: { GroupWebhookEditor },
|
||||
@@ -55,6 +55,7 @@ export default defineComponent({
|
||||
const { actions, webhooks } = useGroupWebhooks();
|
||||
|
||||
return {
|
||||
alert,
|
||||
webhooks,
|
||||
actions,
|
||||
timeUTC
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<template #title> {{ shoppingList.name }} </template>
|
||||
</BasePageTitle>
|
||||
<BannerWarning
|
||||
v-if="isOffline"
|
||||
v-if="$nuxt.isOffline"
|
||||
:title="$tc('shopping-list.you-are-offline')"
|
||||
:description="$tc('shopping-list.you-are-offline-description')"
|
||||
/>
|
||||
@@ -46,7 +46,6 @@
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
:recipes="recipeMap"
|
||||
:is-offline="isOffline"
|
||||
@checked="saveListItem"
|
||||
@save="saveListItem"
|
||||
@delete="deleteListItem(item)"
|
||||
@@ -75,7 +74,6 @@
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
:recipes="recipeMap"
|
||||
:is-offline="isOffline"
|
||||
@checked="saveListItem"
|
||||
@save="saveListItem"
|
||||
@delete="deleteListItem(item)"
|
||||
@@ -132,7 +130,6 @@
|
||||
:labels="allLabels || []"
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
:is-offline="isOffline"
|
||||
@delete="createEditorOpen = false"
|
||||
@cancel="createEditorOpen = false"
|
||||
@save="createListItem"
|
||||
@@ -141,7 +138,7 @@
|
||||
<div v-else class="mt-4 d-flex justify-end">
|
||||
<BaseButton
|
||||
v-if="preferences.viewByLabel" edit class="mr-2"
|
||||
:disabled="isOffline"
|
||||
:disabled="$nuxt.isOffline"
|
||||
@click="toggleReorderLabelsDialog">
|
||||
<template #icon> {{ $globals.icons.tags }} </template>
|
||||
{{ $t('shopping-list.reorder-labels') }}
|
||||
@@ -221,7 +218,6 @@
|
||||
:labels="allLabels || []"
|
||||
:units="allUnits || []"
|
||||
:foods="allFoods || []"
|
||||
:is-offline="isOffline"
|
||||
@checked="saveListItem"
|
||||
@save="saveListItem"
|
||||
@delete="deleteListItem(item)"
|
||||
@@ -244,10 +240,10 @@
|
||||
{{ $tc('shopping-list.linked-recipes-count', shoppingList.recipeReferences ? shoppingList.recipeReferences.length : 0) }}
|
||||
</div>
|
||||
<v-divider class="my-4"></v-divider>
|
||||
<RecipeList :recipes="Array.from(recipeMap.values())" show-description :disabled="isOffline">
|
||||
<RecipeList :recipes="Array.from(recipeMap.values())" show-description :disabled="$nuxt.isOffline">
|
||||
<template v-for="(recipe, index) in recipeMap.values()" #[`actions-${recipe.id}`]>
|
||||
<v-list-item-action :key="'item-actions-decrease' + recipe.id">
|
||||
<v-btn icon :disabled="isOffline" @click.prevent="removeRecipeReferenceToList(recipe.id)">
|
||||
<v-btn icon :disabled="$nuxt.isOffline" @click.prevent="removeRecipeReferenceToList(recipe.id)">
|
||||
<v-icon color="grey lighten-1">{{ $globals.icons.minus }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
@@ -255,7 +251,7 @@
|
||||
{{ shoppingList.recipeReferences[index].recipeQuantity }}
|
||||
</div>
|
||||
<v-list-item-action :key="'item-actions-increase' + recipe.id">
|
||||
<v-btn icon :disabled="isOffline" @click.prevent="addRecipeReferenceToList(recipe.id)">
|
||||
<v-btn icon :disabled="$nuxt.isOffline" @click.prevent="addRecipeReferenceToList(recipe.id)">
|
||||
<v-icon color="grey lighten-1">{{ $globals.icons.createAlt }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
@@ -268,7 +264,7 @@
|
||||
<div class="d-flex justify-end">
|
||||
<BaseButton
|
||||
edit
|
||||
:disabled="isOffline"
|
||||
:disabled="$nuxt.isOffline"
|
||||
@click="toggleSettingsDialog"
|
||||
>
|
||||
<template #icon> {{ $globals.icons.cog }} </template>
|
||||
@@ -278,7 +274,7 @@
|
||||
</v-lazy>
|
||||
|
||||
<v-lazy>
|
||||
<div v-if="!isOffline" class="d-flex justify-end mt-10">
|
||||
<div v-if="$nuxt.isOnline" class="d-flex justify-end mt-10">
|
||||
<ButtonLink
|
||||
:to="`/group/data/labels`"
|
||||
:text="$tc('shopping-list.manage-labels')"
|
||||
@@ -868,7 +864,6 @@ export default defineComponent({
|
||||
|
||||
// set a temporary updatedAt timestamp prior to refresh so it appears at the top of the checked items
|
||||
item.updateAt = new Date().toISOString();
|
||||
item.updateAt = item.updateAt.substring(0, item.updateAt.length-1);
|
||||
}
|
||||
|
||||
// make updates reflect immediately
|
||||
@@ -1073,7 +1068,6 @@ export default defineComponent({
|
||||
getLabelColor,
|
||||
groupSlug,
|
||||
itemsByLabel,
|
||||
isOffline: shoppingListItemActions.isOffline,
|
||||
listItems,
|
||||
loadingCounter,
|
||||
preferences,
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<v-list-item-title>
|
||||
{{ token.name }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle> {{ $t('general.created-on-date', [$d(new Date(token.createdAt+"Z"))]) }} </v-list-item-subtitle>
|
||||
<v-list-item-subtitle> {{ $t('general.created-on-date', [$d(new Date(token.createdAt))]) }} </v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<BaseButton delete small @click="deleteToken(token.id)"></BaseButton>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 9.4 KiB |
BIN
frontend/static/icons/mdiCalendarMultiselect-192x192.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
frontend/static/icons/mdiCalendarMultiselect-96x96.png
Normal file
|
After Width: | Height: | Size: 771 B |
BIN
frontend/static/icons/mdiFormatListChecks-192x192.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
frontend/static/icons/mdiFormatListChecks-96x96.png
Normal file
|
After Width: | Height: | Size: 760 B |
BIN
frontend/static/screenshots/editor-narrow.png
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
frontend/static/screenshots/editor-wide.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
frontend/static/screenshots/home-narrow.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
frontend/static/screenshots/home-wide.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
frontend/static/screenshots/parser-narrow.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
frontend/static/screenshots/parser-wide.png
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
frontend/static/screenshots/recipe-narrow.png
Normal file
|
After Width: | Height: | Size: 770 KiB |
BIN
frontend/static/screenshots/recipe-wide.png
Normal file
|
After Width: | Height: | Size: 943 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="mdi-calendar-multiselect" viewBox="0 0 24 24"><path d="M19,19V8H5V19H19M16,1H18V3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3H6V1H8V3H16V1M7,10H9V12H7V10M15,10H17V12H15V10M11,14H13V16H11V14M15,14H17V16H15V14Z" /></svg>
|
||||
|
Before Width: | Height: | Size: 298 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="mdi-format-list-checks" viewBox="0 0 24 24"><path d="M3,5H9V11H3V5M5,7V9H7V7H5M11,7H21V9H11V7M11,15H21V17H11V15M5,20L1.5,16.5L2.91,15.09L5,17.17L9.59,12.59L11,14L5,20Z" /></svg>
|
||||
|
Before Width: | Height: | Size: 222 B |
@@ -17,18 +17,14 @@ from mealie.services.scheduler import SchedulerRegistry, SchedulerService, tasks
|
||||
|
||||
settings = get_app_settings()
|
||||
|
||||
description = f"""
|
||||
description = """
|
||||
Mealie is a web application for managing your recipes, meal plans, and shopping lists. This is the Restful
|
||||
API interactive documentation that can be used to explore the API. If you're justing getting started with
|
||||
the API and want to get started quickly, you can use the
|
||||
[API Usage | Mealie Docs](https://nightly.mealie.io/documentation/getting-started/api-usage/)
|
||||
[API Usage | Mealie Docs](https://docs.mealie.io/documentation/getting-started/api-usage/)
|
||||
as a reference for how to get started.
|
||||
|
||||
|
||||
As of this release <b>{APP_VERSION}</b>, Mealie is still in rapid development and therefore some of these APIs may
|
||||
change from version to version.
|
||||
|
||||
|
||||
If you have any questions or comments about mealie, please use the discord server to talk to the developers or other
|
||||
community members. If you'd like to file an issue, please use the
|
||||
[GitHub Issue Tracker | Mealie](https://github.com/mealie-recipes/mealie/issues/new/choose)
|
||||
@@ -36,10 +32,9 @@ community members. If you'd like to file an issue, please use the
|
||||
|
||||
## Helpful Links
|
||||
- [Home Page](https://mealie.io)
|
||||
- [Documentation](https://nightly.mealie.io)
|
||||
- [Documentation](https://docs.mealie.io)
|
||||
- [Discord](https://discord.gg/QuStdQGSGK)
|
||||
- [Demo](https://demo.mealie.io)
|
||||
- [Beta](https://demo.mealie.io)
|
||||
"""
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
@@ -32,7 +32,7 @@ def get_latest_version() -> str:
|
||||
|
||||
global _LAST_RESET
|
||||
|
||||
now = datetime.datetime.now()
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
if not _LAST_RESET or now - _LAST_RESET > datetime.timedelta(days=MAX_DAYS_OLD):
|
||||
_LAST_RESET = now
|
||||
|
||||
@@ -38,7 +38,7 @@ class OpenIDProvider(AuthProvider[OIDCRequest]):
|
||||
user = self.try_get_user(claims.get(settings.OIDC_USER_CLAIM))
|
||||
is_admin = False
|
||||
if settings.OIDC_USER_GROUP or settings.OIDC_ADMIN_GROUP:
|
||||
group_claim = claims.get(settings.OIDC_GROUPS_CLAIM, [])
|
||||
group_claim = claims.get(settings.OIDC_GROUPS_CLAIM, []) or []
|
||||
is_admin = settings.OIDC_ADMIN_GROUP in group_claim if settings.OIDC_ADMIN_GROUP else False
|
||||
is_valid_user = settings.OIDC_USER_GROUP in group_claim if settings.OIDC_USER_GROUP else True
|
||||
|
||||
@@ -82,7 +82,12 @@ class OpenIDProvider(AuthProvider[OIDCRequest]):
|
||||
|
||||
def get_claims(self, settings: AppSettings) -> JWTClaims | None:
|
||||
"""Get the claims from the ID token and check if the required claims are present"""
|
||||
required_claims = {"preferred_username", "name", "email", settings.OIDC_USER_CLAIM}
|
||||
required_claims = {
|
||||
"preferred_username",
|
||||
"name",
|
||||
"email",
|
||||
settings.OIDC_USER_CLAIM,
|
||||
}
|
||||
jwks = OpenIDProvider.get_jwks(self.get_ttl_hash()) # cache the key set for 30 minutes
|
||||
if not jwks:
|
||||
return None
|
||||
|
||||
@@ -72,9 +72,18 @@ class PostgresProvider(AbstractDBProvider, BaseSettings):
|
||||
|
||||
@property
|
||||
def db_url_public(self) -> str:
|
||||
user = self.POSTGRES_USER
|
||||
password = self.POSTGRES_PASSWORD
|
||||
return self.db_url.replace(user, "*****", 1).replace(password, "*****", 1)
|
||||
if self.POSTGRES_URL_OVERRIDE:
|
||||
return "Postgres Url Overridden"
|
||||
|
||||
return str(
|
||||
PostgresDsn.build(
|
||||
scheme="postgresql",
|
||||
username="******",
|
||||
password="******",
|
||||
host=f"{self.POSTGRES_SERVER}:{self.POSTGRES_PORT}",
|
||||
path=f"{self.POSTGRES_DB or ''}",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def db_provider_factory(provider_name: str, data_dir: Path, env_file: Path, env_encoding="utf-8") -> AbstractDBProvider:
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import logging
|
||||
import secrets
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
|
||||
from dateutil.tz import tzlocal
|
||||
from pydantic import field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
@@ -9,6 +13,11 @@ from mealie.core.settings.themes import Theme
|
||||
from .db_providers import AbstractDBProvider, db_provider_factory
|
||||
|
||||
|
||||
class ScheduleTime(NamedTuple):
|
||||
hour: int
|
||||
minute: int
|
||||
|
||||
|
||||
def determine_secrets(data_dir: Path, production: bool) -> str:
|
||||
if not production:
|
||||
return "shh-secret-test-key"
|
||||
@@ -58,6 +67,44 @@ class AppSettings(BaseSettings):
|
||||
ALLOW_SIGNUP: bool = False
|
||||
|
||||
DAILY_SCHEDULE_TIME: str = "23:45"
|
||||
"""Local server time, in HH:MM format. See `DAILY_SCHEDULE_TIME_UTC` for the parsed UTC equivalent"""
|
||||
|
||||
_logger: logging.Logger | None = None
|
||||
|
||||
@property
|
||||
def logger(self) -> logging.Logger:
|
||||
if self._logger is None:
|
||||
# lazy load the logger, since get_logger depends on the settings being loaded
|
||||
from mealie.core.root_logger import get_logger
|
||||
|
||||
self._logger = get_logger()
|
||||
|
||||
return self._logger
|
||||
|
||||
@property
|
||||
def DAILY_SCHEDULE_TIME_UTC(self) -> ScheduleTime:
|
||||
"""The DAILY_SCHEDULE_TIME in UTC, parsed into hours and minutes"""
|
||||
|
||||
# parse DAILY_SCHEDULE_TIME into hours and minutes
|
||||
try:
|
||||
hour_str, minute_str = self.DAILY_SCHEDULE_TIME.split(":")
|
||||
local_hour = int(hour_str)
|
||||
local_minute = int(minute_str)
|
||||
except ValueError:
|
||||
local_hour = 23
|
||||
local_minute = 45
|
||||
self.logger.exception(
|
||||
f"Unable to parse {self.DAILY_SCHEDULE_TIME=} as HH:MM; defaulting to {local_hour}:{local_minute}"
|
||||
)
|
||||
|
||||
# DAILY_SCHEDULE_TIME is in local time, so we convert it to UTC
|
||||
local_tz = tzlocal()
|
||||
now = datetime.now(local_tz)
|
||||
local_time = now.replace(hour=local_hour, minute=local_minute)
|
||||
utc_time = local_time.astimezone(timezone.utc)
|
||||
|
||||
self.logger.debug(f"Local time: {local_hour}:{local_minute} | UTC time: {utc_time.hour}:{utc_time.minute}")
|
||||
return ScheduleTime(utc_time.hour, utc_time.minute)
|
||||
|
||||
# ===============================================
|
||||
# Security Configuration
|
||||
|
||||
@@ -4,11 +4,13 @@ from sqlalchemy import DateTime, Integer
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
from text_unidecode import unidecode
|
||||
|
||||
from ._model_utils.datetime import get_utc_now
|
||||
|
||||
|
||||
class SqlAlchemyBase(DeclarativeBase):
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
created_at: Mapped[datetime | None] = mapped_column(DateTime, default=datetime.now, index=True)
|
||||
update_at: Mapped[datetime | None] = mapped_column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||
created_at: Mapped[datetime | None] = mapped_column(DateTime, default=get_utc_now, index=True)
|
||||
update_at: Mapped[datetime | None] = mapped_column(DateTime, default=get_utc_now, onupdate=get_utc_now)
|
||||
|
||||
@classmethod
|
||||
def normalize(cls, val: str) -> str:
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from .auto_init import auto_init
|
||||
from .guid import GUID
|
||||
|
||||
__all__ = [
|
||||
"auto_init",
|
||||
"GUID",
|
||||
]
|
||||
|
||||